12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565 |
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
- # Copyright (c) 2014-2016, Matthew Brennan Jones <matthew.brennan.jones@gmail.com>
- # Py-cpuinfo is a Python module to show the cpuinfo of a processor
- # It uses a MIT style license
- # It is hosted at: https://github.com/workhorsy/py-cpuinfo
- #
- # Permission is hereby granted, free of charge, to any person obtaining
- # a copy of this software and associated documentation files (the
- # "Software"), to deal in the Software without restriction, including
- # without limitation the rights to use, copy, modify, merge, publish,
- # distribute, sublicense, and/or sell copies of the Software, and to
- # permit persons to whom the Software is furnished to do so, subject to
- # the following conditions:
- #
- # The above copyright notice and this permission notice shall be included
- # in all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- import os, sys
- import re
- import time
- import platform
- import multiprocessing
- import ctypes
- import pickle
- import base64
- import subprocess
- try:
- import _winreg as winreg
- except ImportError as err:
- try:
- import winreg
- except ImportError as err:
- pass
- PY2 = sys.version_info[0] == 2
- class DataSource(object):
- bits = platform.architecture()[0]
- cpu_count = multiprocessing.cpu_count()
- is_windows = platform.system().lower() == 'windows'
- raw_arch_string = platform.machine()
- @staticmethod
- def has_proc_cpuinfo():
- return os.path.exists('/proc/cpuinfo')
- @staticmethod
- def has_dmesg():
- return len(program_paths('dmesg')) > 0
- @staticmethod
- def has_cpufreq_info():
- return len(program_paths('cpufreq-info')) > 0
- @staticmethod
- def has_sestatus():
- return len(program_paths('sestatus')) > 0
- @staticmethod
- def has_sysctl():
- return len(program_paths('sysctl')) > 0
- @staticmethod
- def has_isainfo():
- return len(program_paths('isainfo')) > 0
- @staticmethod
- def has_kstat():
- return len(program_paths('kstat')) > 0
- @staticmethod
- def has_sysinfo():
- return len(program_paths('sysinfo')) > 0
- @staticmethod
- def has_lscpu():
- return len(program_paths('lscpu')) > 0
- @staticmethod
- def cat_proc_cpuinfo():
- return run_and_get_stdout(['cat', '/proc/cpuinfo'])
- @staticmethod
- def cpufreq_info():
- return run_and_get_stdout(['cpufreq-info'])
- @staticmethod
- def sestatus_allow_execheap():
- return run_and_get_stdout(['sestatus', '-b'], ['grep', '-i', '"allow_execheap"'])[1].strip().lower().endswith('on')
- @staticmethod
- def sestatus_allow_execmem():
- return run_and_get_stdout(['sestatus', '-b'], ['grep', '-i', '"allow_execmem"'])[1].strip().lower().endswith('on')
- @staticmethod
- def dmesg_a():
- return run_and_get_stdout(['dmesg', '-a'])
- @staticmethod
- def sysctl_machdep_cpu_hw_cpufrequency():
- return run_and_get_stdout(['sysctl', 'machdep.cpu', 'hw.cpufrequency'])
- @staticmethod
- def isainfo_vb():
- return run_and_get_stdout(['isainfo', '-vb'])
- @staticmethod
- def kstat_m_cpu_info():
- return run_and_get_stdout(['kstat', '-m', 'cpu_info'])
- @staticmethod
- def sysinfo_cpu():
- return run_and_get_stdout(['sysinfo', '-cpu'])
- @staticmethod
- def lscpu():
- return run_and_get_stdout(['lscpu'])
- @staticmethod
- def winreg_processor_brand():
- key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
- processor_brand = winreg.QueryValueEx(key, "ProcessorNameString")[0]
- winreg.CloseKey(key)
- return processor_brand
- @staticmethod
- def winreg_vendor_id():
- key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
- vendor_id = winreg.QueryValueEx(key, "VendorIdentifier")[0]
- winreg.CloseKey(key)
- return vendor_id
- @staticmethod
- def winreg_raw_arch_string():
- key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")
- raw_arch_string = winreg.QueryValueEx(key, "PROCESSOR_ARCHITECTURE")[0]
- winreg.CloseKey(key)
- return raw_arch_string
- @staticmethod
- def winreg_hz_actual():
- key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
- hz_actual = winreg.QueryValueEx(key, "~Mhz")[0]
- winreg.CloseKey(key)
- hz_actual = to_hz_string(hz_actual)
- return hz_actual
- @staticmethod
- def winreg_feature_bits():
- key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
- feature_bits = winreg.QueryValueEx(key, "FeatureSet")[0]
- winreg.CloseKey(key)
- return feature_bits
- def obj_to_b64(thing):
- a = thing
- b = pickle.dumps(a)
- c = base64.b64encode(b)
- d = c.decode('utf8')
- return d
- def b64_to_obj(thing):
- a = base64.b64decode(thing)
- b = pickle.loads(a)
- return b
- def run_and_get_stdout(command, pipe_command=None):
- if not pipe_command:
- p1 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output = p1.communicate()[0]
- if not PY2:
- output = output.decode(encoding='UTF-8')
- return p1.returncode, output
- else:
- p1 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- p2 = subprocess.Popen(pipe_command, stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- p1.stdout.close()
- output = p2.communicate()[0]
- if not PY2:
- output = output.decode(encoding='UTF-8')
- return p2.returncode, output
- def program_paths(program_name):
- paths = []
- exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
- path = os.environ['PATH']
- for p in os.environ['PATH'].split(os.pathsep):
- p = os.path.join(p, program_name)
- if os.access(p, os.X_OK):
- paths.append(p)
- for e in exts:
- pext = p + e
- if os.access(pext, os.X_OK):
- paths.append(pext)
- return paths
- def _get_field_actual(cant_be_number, raw_string, field_names):
- for line in raw_string.splitlines():
- for field_name in field_names:
- field_name = field_name.lower()
- if ':' in line:
- left, right = line.split(':', 1)
- left = left.strip().lower()
- right = right.strip()
- if left == field_name and len(right) > 0:
- if cant_be_number:
- if not right.isdigit():
- return right
- else:
- return right
- return None
- def _get_field(cant_be_number, raw_string, convert_to, default_value, *field_names):
- retval = _get_field_actual(cant_be_number, raw_string, field_names)
- # Convert the return value
- if retval and convert_to:
- try:
- retval = convert_to(retval)
- except:
- retval = default_value
- # Return the default if there is no return value
- if retval is None:
- retval = default_value
- return retval
- def _get_hz_string_from_brand(processor_brand):
- # Just return 0 if the processor brand does not have the Hz
- if not 'hz' in processor_brand.lower():
- return (1, '0.0')
- hz_brand = processor_brand.lower()
- scale = 1
- if hz_brand.endswith('mhz'):
- scale = 6
- elif hz_brand.endswith('ghz'):
- scale = 9
- if '@' in hz_brand:
- hz_brand = hz_brand.split('@')[1]
- else:
- hz_brand = hz_brand.rsplit(None, 1)[1]
- hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip()
- hz_brand = to_hz_string(hz_brand)
- return (scale, hz_brand)
- def _get_hz_string_from_beagle_bone():
- scale, hz_brand = 1, '0.0'
- if not DataSource.has_cpufreq_info():
- return scale, hz_brand
- returncode, output = DataSource.cpufreq_info()
- if returncode != 0:
- return (scale, hz_brand)
- hz_brand = output.split('current CPU frequency is')[1].split('.')[0].lower()
- if hz_brand.endswith('mhz'):
- scale = 6
- elif hz_brand.endswith('ghz'):
- scale = 9
- hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip()
- hz_brand = to_hz_string(hz_brand)
- return (scale, hz_brand)
- def _get_hz_string_from_lscpu():
- scale, hz_brand = 1, '0.0'
- if not DataSource.has_lscpu():
- return scale, hz_brand
- returncode, output = DataSource.lscpu()
- if returncode != 0:
- return (scale, hz_brand)
- new_hz = _get_field(False, output, None, None, 'CPU max MHz', 'CPU MHz')
- if new_hz == None:
- return (scale, hz_brand)
- new_hz = to_hz_string(new_hz)
- scale = 6
- return (scale, new_hz)
- def to_friendly_hz(ticks, scale):
- # Get the raw Hz as a string
- left, right = to_raw_hz(ticks, scale)
- ticks = '{0}.{1}'.format(left, right)
- # Get the location of the dot, and remove said dot
- dot_index = ticks.index('.')
- ticks = ticks.replace('.', '')
- # Get the Hz symbol and scale
- symbol = "Hz"
- scale = 0
- if dot_index > 9:
- symbol = "GHz"
- scale = 9
- elif dot_index > 6:
- symbol = "MHz"
- scale = 6
- elif dot_index > 3:
- symbol = "KHz"
- scale = 3
- # Get the Hz with the dot at the new scaled point
- ticks = '{0}.{1}'.format(ticks[:-scale-1], ticks[-scale-1:])
- # Format the ticks to have 4 numbers after the decimal
- # and remove any superfluous zeroes.
- ticks = '{0:.4f} {1}'.format(float(ticks), symbol)
- ticks = ticks.rstrip('0')
- return ticks
- def to_raw_hz(ticks, scale):
- # Scale the numbers
- ticks = ticks.lstrip('0')
- old_index = ticks.index('.')
- ticks = ticks.replace('.', '')
- ticks = ticks.ljust(scale + old_index+1, '0')
- new_index = old_index + scale
- ticks = '{0}.{1}'.format(ticks[:new_index], ticks[new_index:])
- left, right = ticks.split('.')
- left, right = int(left), int(right)
- return (left, right)
- def to_hz_string(ticks):
- # Convert to string
- ticks = '{0}'.format(ticks)
- # Add decimal if missing
- if '.' not in ticks:
- ticks = '{0}.0'.format(ticks)
- # Remove trailing zeros
- ticks = ticks.rstrip('0')
- # Add one trailing zero for empty right side
- if ticks.endswith('.'):
- ticks = '{0}0'.format(ticks)
- return ticks
- def parse_arch(raw_arch_string):
- arch, bits = None, None
- raw_arch_string = raw_arch_string.lower()
- # X86
- if re.match('^i\d86$|^x86$|^x86_32$|^i86pc$|^ia32$|^ia-32$|^bepc$', raw_arch_string):
- arch = 'X86_32'
- bits = 32
- elif re.match('^x64$|^x86_64$|^x86_64t$|^i686-64$|^amd64$|^ia64$|^ia-64$', raw_arch_string):
- arch = 'X86_64'
- bits = 64
- # ARM
- elif re.match('^armv8-a$', raw_arch_string):
- arch = 'ARM_8'
- bits = 64
- elif re.match('^armv7$|^armv7[a-z]$|^armv7-[a-z]$|^armv6[a-z]$', raw_arch_string):
- arch = 'ARM_7'
- bits = 32
- elif re.match('^armv8$|^armv8[a-z]$|^armv8-[a-z]$', raw_arch_string):
- arch = 'ARM_8'
- bits = 32
- # PPC
- elif re.match('^ppc32$|^prep$|^pmac$|^powermac$', raw_arch_string):
- arch = 'PPC_32'
- bits = 32
- elif re.match('^powerpc$|^ppc64$', raw_arch_string):
- arch = 'PPC_64'
- bits = 64
- # SPARC
- elif re.match('^sparc32$|^sparc$', raw_arch_string):
- arch = 'SPARC_32'
- bits = 32
- elif re.match('^sparc64$|^sun4u$|^sun4v$', raw_arch_string):
- arch = 'SPARC_64'
- bits = 64
- return (arch, bits)
- def is_bit_set(reg, bit):
- mask = 1 << bit
- is_set = reg & mask > 0
- return is_set
- class CPUID(object):
- def __init__(self):
- # Figure out if SE Linux is on and in enforcing mode
- self.is_selinux_enforcing = False
- # Just return if the SE Linux Status Tool is not installed
- if not DataSource.has_sestatus():
- return
- # Figure out if we can execute heap and execute memory
- can_selinux_exec_heap = DataSource.sestatus_allow_execheap()
- can_selinux_exec_memory = DataSource.sestatus_allow_execmem()
- self.is_selinux_enforcing = (not can_selinux_exec_heap or not can_selinux_exec_memory)
- def _asm_func(self, restype=None, argtypes=(), byte_code=[]):
- byte_code = bytes.join(b'', byte_code)
- address = None
- if DataSource.is_windows:
- # Allocate a memory segment the size of the byte code, and make it executable
- size = len(byte_code)
- MEM_COMMIT = ctypes.c_ulong(0x1000)
- PAGE_EXECUTE_READWRITE = ctypes.c_ulong(0x40)
- address = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_size_t(size), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
- if not address:
- raise Exception("Failed to VirtualAlloc")
- # Copy the byte code into the memory segment
- memmove = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)(ctypes._memmove_addr)
- if memmove(address, byte_code, size) < 0:
- raise Exception("Failed to memmove")
- else:
- # Allocate a memory segment the size of the byte code
- size = len(byte_code)
- address = ctypes.pythonapi.valloc(size)
- if not address:
- raise Exception("Failed to valloc")
- # Mark the memory segment as writeable only
- if not self.is_selinux_enforcing:
- WRITE = 0x2
- if ctypes.pythonapi.mprotect(address, size, WRITE) < 0:
- raise Exception("Failed to mprotect")
- # Copy the byte code into the memory segment
- if ctypes.pythonapi.memmove(address, byte_code, size) < 0:
- raise Exception("Failed to memmove")
- # Mark the memory segment as writeable and executable only
- if not self.is_selinux_enforcing:
- WRITE_EXECUTE = 0x2 | 0x4
- if ctypes.pythonapi.mprotect(address, size, WRITE_EXECUTE) < 0:
- raise Exception("Failed to mprotect")
- # Cast the memory segment into a function
- functype = ctypes.CFUNCTYPE(restype, *argtypes)
- fun = functype(address)
- return fun, address
- def _run_asm(self, *byte_code):
- # Convert the byte code into a function that returns an int
- restype = None
- if DataSource.bits == '64bit':
- restype = ctypes.c_uint64
- else:
- restype = ctypes.c_uint32
- argtypes = ()
- func, address = self._asm_func(restype, argtypes, byte_code)
- # Call the byte code like a function
- retval = func()
- size = ctypes.c_size_t(len(byte_code))
- # Free the function memory segment
- if DataSource.is_windows:
- MEM_RELEASE = ctypes.c_ulong(0x8000)
- ctypes.windll.kernel32.VirtualFree(address, size, MEM_RELEASE)
- else:
- # Remove the executable tag on the memory
- READ_WRITE = 0x1 | 0x2
- if ctypes.pythonapi.mprotect(address, size, READ_WRITE) < 0:
- raise Exception("Failed to mprotect")
- ctypes.pythonapi.free(address)
- return retval
- # FIXME: We should not have to use different instructions to
- # set eax to 0 or 1, on 32bit and 64bit machines.
- def _zero_eax(self):
- if DataSource.bits == '64bit':
- return (
- b"\x66\xB8\x00\x00" # mov eax,0x0"
- )
- else:
- return (
- b"\x31\xC0" # xor ax,ax
- )
- def _one_eax(self):
- if DataSource.bits == '64bit':
- return (
- b"\x66\xB8\x01\x00" # mov eax,0x1"
- )
- else:
- return (
- b"\x31\xC0" # xor ax,ax
- b"\x40" # inc ax
- )
- # http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
- def get_vendor_id(self):
- # EBX
- ebx = self._run_asm(
- self._zero_eax(),
- b"\x0F\xA2" # cpuid
- b"\x89\xD8" # mov ax,bx
- b"\xC3" # ret
- )
- # ECX
- ecx = self._run_asm(
- self._zero_eax(),
- b"\x0f\xa2" # cpuid
- b"\x89\xC8" # mov ax,cx
- b"\xC3" # ret
- )
- # EDX
- edx = self._run_asm(
- self._zero_eax(),
- b"\x0f\xa2" # cpuid
- b"\x89\xD0" # mov ax,dx
- b"\xC3" # ret
- )
- # Each 4bits is a ascii letter in the name
- vendor_id = []
- for reg in [ebx, edx, ecx]:
- for n in [0, 8, 16, 24]:
- vendor_id.append(chr((reg >> n) & 0xFF))
- vendor_id = ''.join(vendor_id)
- return vendor_id
- # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
- def get_info(self):
- # EAX
- eax = self._run_asm(
- self._one_eax(),
- b"\x0f\xa2" # cpuid
- b"\xC3" # ret
- )
- # Get the CPU info
- stepping = (eax >> 0) & 0xF # 4 bits
- model = (eax >> 4) & 0xF # 4 bits
- family = (eax >> 8) & 0xF # 4 bits
- processor_type = (eax >> 12) & 0x3 # 2 bits
- extended_model = (eax >> 16) & 0xF # 4 bits
- extended_family = (eax >> 20) & 0xFF # 8 bits
- return {
- 'stepping' : stepping,
- 'model' : model,
- 'family' : family,
- 'processor_type' : processor_type,
- 'extended_model' : extended_model,
- 'extended_family' : extended_family
- }
- # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000000h:_Get_Highest_Extended_Function_Supported
- def get_max_extension_support(self):
- # Check for extension support
- max_extension_support = self._run_asm(
- b"\xB8\x00\x00\x00\x80" # mov ax,0x80000000
- b"\x0f\xa2" # cpuid
- b"\xC3" # ret
- )
- return max_extension_support
- # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
- def get_flags(self, max_extension_support):
- # EDX
- edx = self._run_asm(
- self._one_eax(),
- b"\x0f\xa2" # cpuid
- b"\x89\xD0" # mov ax,dx
- b"\xC3" # ret
- )
- # ECX
- ecx = self._run_asm(
- self._one_eax(),
- b"\x0f\xa2" # cpuid
- b"\x89\xC8" # mov ax,cx
- b"\xC3" # ret
- )
- # Get the CPU flags
- flags = {
- 'fpu' : is_bit_set(edx, 0),
- 'vme' : is_bit_set(edx, 1),
- 'de' : is_bit_set(edx, 2),
- 'pse' : is_bit_set(edx, 3),
- 'tsc' : is_bit_set(edx, 4),
- 'msr' : is_bit_set(edx, 5),
- 'pae' : is_bit_set(edx, 6),
- 'mce' : is_bit_set(edx, 7),
- 'cx8' : is_bit_set(edx, 8),
- 'apic' : is_bit_set(edx, 9),
- #'reserved1' : is_bit_set(edx, 10),
- 'sep' : is_bit_set(edx, 11),
- 'mtrr' : is_bit_set(edx, 12),
- 'pge' : is_bit_set(edx, 13),
- 'mca' : is_bit_set(edx, 14),
- 'cmov' : is_bit_set(edx, 15),
- 'pat' : is_bit_set(edx, 16),
- 'pse36' : is_bit_set(edx, 17),
- 'pn' : is_bit_set(edx, 18),
- 'clflush' : is_bit_set(edx, 19),
- #'reserved2' : is_bit_set(edx, 20),
- 'dts' : is_bit_set(edx, 21),
- 'acpi' : is_bit_set(edx, 22),
- 'mmx' : is_bit_set(edx, 23),
- 'fxsr' : is_bit_set(edx, 24),
- 'sse' : is_bit_set(edx, 25),
- 'sse2' : is_bit_set(edx, 26),
- 'ss' : is_bit_set(edx, 27),
- 'ht' : is_bit_set(edx, 28),
- 'tm' : is_bit_set(edx, 29),
- 'ia64' : is_bit_set(edx, 30),
- 'pbe' : is_bit_set(edx, 31),
- 'pni' : is_bit_set(ecx, 0),
- 'pclmulqdq' : is_bit_set(ecx, 1),
- 'dtes64' : is_bit_set(ecx, 2),
- 'monitor' : is_bit_set(ecx, 3),
- 'ds_cpl' : is_bit_set(ecx, 4),
- 'vmx' : is_bit_set(ecx, 5),
- 'smx' : is_bit_set(ecx, 6),
- 'est' : is_bit_set(ecx, 7),
- 'tm2' : is_bit_set(ecx, 8),
- 'ssse3' : is_bit_set(ecx, 9),
- 'cid' : is_bit_set(ecx, 10),
- #'reserved3' : is_bit_set(ecx, 11),
- 'fma' : is_bit_set(ecx, 12),
- 'cx16' : is_bit_set(ecx, 13),
- 'xtpr' : is_bit_set(ecx, 14),
- 'pdcm' : is_bit_set(ecx, 15),
- #'reserved4' : is_bit_set(ecx, 16),
- 'pcid' : is_bit_set(ecx, 17),
- 'dca' : is_bit_set(ecx, 18),
- 'sse4_1' : is_bit_set(ecx, 19),
- 'sse4_2' : is_bit_set(ecx, 20),
- 'x2apic' : is_bit_set(ecx, 21),
- 'movbe' : is_bit_set(ecx, 22),
- 'popcnt' : is_bit_set(ecx, 23),
- 'tscdeadline' : is_bit_set(ecx, 24),
- 'aes' : is_bit_set(ecx, 25),
- 'xsave' : is_bit_set(ecx, 26),
- 'osxsave' : is_bit_set(ecx, 27),
- 'avx' : is_bit_set(ecx, 28),
- 'f16c' : is_bit_set(ecx, 29),
- 'rdrnd' : is_bit_set(ecx, 30),
- 'hypervisor' : is_bit_set(ecx, 31)
- }
- # Get a list of only the flags that are true
- flags = [k for k, v in flags.items() if v]
- # Get the Extended CPU flags
- extended_flags = {}
- # https://en.wikipedia.org/wiki/CPUID#EAX.3D7.2C_ECX.3D0:_Extended_Features
- if max_extension_support == 7:
- pass
- # FIXME: Are we missing all these flags too?
- # avx2 et cetera ...
- # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000001h:_Extended_Processor_Info_and_Feature_Bits
- if max_extension_support >= 0x80000001:
- # EBX # FIXME: This may need to be EDX instead
- ebx = self._run_asm(
- b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
- b"\x0f\xa2" # cpuid
- b"\x89\xD8" # mov ax,bx
- b"\xC3" # ret
- )
- # ECX
- ecx = self._run_asm(
- b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
- b"\x0f\xa2" # cpuid
- b"\x89\xC8" # mov ax,cx
- b"\xC3" # ret
- )
- # Get the extended CPU flags
- extended_flags = {
- 'fpu' : is_bit_set(ebx, 0),
- 'vme' : is_bit_set(ebx, 1),
- 'de' : is_bit_set(ebx, 2),
- 'pse' : is_bit_set(ebx, 3),
- 'tsc' : is_bit_set(ebx, 4),
- 'msr' : is_bit_set(ebx, 5),
- 'pae' : is_bit_set(ebx, 6),
- 'mce' : is_bit_set(ebx, 7),
- 'cx8' : is_bit_set(ebx, 8),
- 'apic' : is_bit_set(ebx, 9),
- #'reserved' : is_bit_set(ebx, 10),
- 'syscall' : is_bit_set(ebx, 11),
- 'mtrr' : is_bit_set(ebx, 12),
- 'pge' : is_bit_set(ebx, 13),
- 'mca' : is_bit_set(ebx, 14),
- 'cmov' : is_bit_set(ebx, 15),
- 'pat' : is_bit_set(ebx, 16),
- 'pse36' : is_bit_set(ebx, 17),
- #'reserved' : is_bit_set(ebx, 18),
- 'mp' : is_bit_set(ebx, 19),
- 'nx' : is_bit_set(ebx, 20),
- #'reserved' : is_bit_set(ebx, 21),
- 'mmxext' : is_bit_set(ebx, 22),
- 'mmx' : is_bit_set(ebx, 23),
- 'fxsr' : is_bit_set(ebx, 24),
- 'fxsr_opt' : is_bit_set(ebx, 25),
- 'pdpe1gp' : is_bit_set(ebx, 26),
- 'rdtscp' : is_bit_set(ebx, 27),
- #'reserved' : is_bit_set(ebx, 28),
- 'lm' : is_bit_set(ebx, 29),
- '3dnowext' : is_bit_set(ebx, 30),
- '3dnow' : is_bit_set(ebx, 31),
- 'lahf_lm' : is_bit_set(ecx, 0),
- 'cmp_legacy' : is_bit_set(ecx, 1),
- 'svm' : is_bit_set(ecx, 2),
- 'extapic' : is_bit_set(ecx, 3),
- 'cr8_legacy' : is_bit_set(ecx, 4),
- 'abm' : is_bit_set(ecx, 5),
- 'sse4a' : is_bit_set(ecx, 6),
- 'misalignsse' : is_bit_set(ecx, 7),
- '3dnowprefetch' : is_bit_set(ecx, 8),
- 'osvw' : is_bit_set(ecx, 9),
- 'ibs' : is_bit_set(ecx, 10),
- 'xop' : is_bit_set(ecx, 11),
- 'skinit' : is_bit_set(ecx, 12),
- 'wdt' : is_bit_set(ecx, 13),
- #'reserved' : is_bit_set(ecx, 14),
- 'lwp' : is_bit_set(ecx, 15),
- 'fma4' : is_bit_set(ecx, 16),
- 'tce' : is_bit_set(ecx, 17),
- #'reserved' : is_bit_set(ecx, 18),
- 'nodeid_msr' : is_bit_set(ecx, 19),
- #'reserved' : is_bit_set(ecx, 20),
- 'tbm' : is_bit_set(ecx, 21),
- 'topoext' : is_bit_set(ecx, 22),
- 'perfctr_core' : is_bit_set(ecx, 23),
- 'perfctr_nb' : is_bit_set(ecx, 24),
- #'reserved' : is_bit_set(ecx, 25),
- 'dbx' : is_bit_set(ecx, 26),
- 'perftsc' : is_bit_set(ecx, 27),
- 'pci_l2i' : is_bit_set(ecx, 28),
- #'reserved' : is_bit_set(ecx, 29),
- #'reserved' : is_bit_set(ecx, 30),
- #'reserved' : is_bit_set(ecx, 31)
- }
- # Get a list of only the flags that are true
- extended_flags = [k for k, v in extended_flags.items() if v]
- flags += extended_flags
- flags.sort()
- return flags
- # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000002h.2C80000003h.2C80000004h:_Processor_Brand_String
- def get_processor_brand(self, max_extension_support):
- processor_brand = ""
- # Processor brand string
- if max_extension_support >= 0x80000004:
- instructions = [
- b"\xB8\x02\x00\x00\x80", # mov ax,0x80000002
- b"\xB8\x03\x00\x00\x80", # mov ax,0x80000003
- b"\xB8\x04\x00\x00\x80" # mov ax,0x80000004
- ]
- for instruction in instructions:
- # EAX
- eax = self._run_asm(
- instruction, # mov ax,0x8000000?
- b"\x0f\xa2" # cpuid
- b"\x89\xC0" # mov ax,ax
- b"\xC3" # ret
- )
- # EBX
- ebx = self._run_asm(
- instruction, # mov ax,0x8000000?
- b"\x0f\xa2" # cpuid
- b"\x89\xD8" # mov ax,bx
- b"\xC3" # ret
- )
- # ECX
- ecx = self._run_asm(
- instruction, # mov ax,0x8000000?
- b"\x0f\xa2" # cpuid
- b"\x89\xC8" # mov ax,cx
- b"\xC3" # ret
- )
- # EDX
- edx = self._run_asm(
- instruction, # mov ax,0x8000000?
- b"\x0f\xa2" # cpuid
- b"\x89\xD0" # mov ax,dx
- b"\xC3" # ret
- )
- # Combine each of the 4 bytes in each register into the string
- for reg in [eax, ebx, ecx, edx]:
- for n in [0, 8, 16, 24]:
- processor_brand += chr((reg >> n) & 0xFF)
- # Strip off any trailing NULL terminators and white space
- processor_brand = processor_brand.strip("\0").strip()
- return processor_brand
- # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000006h:_Extended_L2_Cache_Features
- def get_cache(self, max_extension_support):
- cache_info = {}
- # Just return if the cache feature is not supported
- if max_extension_support < 0x80000006:
- return cache_info
- # ECX
- ecx = self._run_asm(
- b"\xB8\x06\x00\x00\x80" # mov ax,0x80000006
- b"\x0f\xa2" # cpuid
- b"\x89\xC8" # mov ax,cx
- b"\xC3" # ret
- )
- cache_info = {
- 'size_kb' : ecx & 0xFF,
- 'line_size_b' : (ecx >> 12) & 0xF,
- 'associativity' : (ecx >> 16) & 0xFFFF
- }
- return cache_info
- def get_ticks(self):
- retval = None
- if DataSource.bits == '32bit':
- # Works on x86_32
- restype = None
- argtypes = (ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint))
- get_ticks_x86_32, address = self._asm_func(restype, argtypes,
- [
- b"\x55", # push bp
- b"\x89\xE5", # mov bp,sp
- b"\x31\xC0", # xor ax,ax
- b"\x0F\xA2", # cpuid
- b"\x0F\x31", # rdtsc
- b"\x8B\x5D\x08", # mov bx,[di+0x8]
- b"\x8B\x4D\x0C", # mov cx,[di+0xc]
- b"\x89\x13", # mov [bp+di],dx
- b"\x89\x01", # mov [bx+di],ax
- b"\x5D", # pop bp
- b"\xC3" # ret
- ]
- )
- high = ctypes.c_uint32(0)
- low = ctypes.c_uint32(0)
- get_ticks_x86_32(ctypes.byref(high), ctypes.byref(low))
- retval = ((high.value << 32) & 0xFFFFFFFF00000000) | low.value
- elif DataSource.bits == '64bit':
- # Works on x86_64
- restype = ctypes.c_uint64
- argtypes = ()
- get_ticks_x86_64, address = self._asm_func(restype, argtypes,
- [
- b"\x48", # dec ax
- b"\x31\xC0", # xor ax,ax
- b"\x0F\xA2", # cpuid
- b"\x0F\x31", # rdtsc
- b"\x48", # dec ax
- b"\xC1\xE2\x20", # shl dx,byte 0x20
- b"\x48", # dec ax
- b"\x09\xD0", # or ax,dx
- b"\xC3", # ret
- ]
- )
- retval = get_ticks_x86_64()
- return retval
- def get_raw_hz(self):
- start = self.get_ticks()
- time.sleep(1)
- end = self.get_ticks()
- ticks = (end - start)
- return ticks
- def get_cpu_info_from_cpuid():
- '''
- Returns the CPU info gathered by querying the X86 cpuid register in a new process.
- Returns None of non X86 cpus.
- Returns None if SELinux is in enforcing mode.
- '''
- returncode, output = run_and_get_stdout([sys.executable, "-c", "import cpuinfo; print(cpuinfo.actual_get_cpu_info_from_cpuid())"])
- if returncode != 0:
- return None
- info = b64_to_obj(output)
- return info
- def actual_get_cpu_info_from_cpuid():
- # Get the CPU arch and bits
- arch, bits = parse_arch(DataSource.raw_arch_string)
- # Return none if this is not an X86 CPU
- if not arch in ['X86_32', 'X86_64']:
- return None
- # Return none if SE Linux is in enforcing mode
- cpuid = CPUID()
- if cpuid.is_selinux_enforcing:
- return None
- # Get the cpu info from the CPUID register
- max_extension_support = cpuid.get_max_extension_support()
- cache_info = cpuid.get_cache(max_extension_support)
- info = cpuid.get_info()
- processor_brand = cpuid.get_processor_brand(max_extension_support)
- # Get the Hz and scale
- hz_actual = cpuid.get_raw_hz()
- hz_actual = to_hz_string(hz_actual)
- # Get the Hz and scale
- scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
- info = {
- 'vendor_id' : cpuid.get_vendor_id(),
- 'hardware' : '',
- 'brand' : processor_brand,
- 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
- 'hz_actual' : to_friendly_hz(hz_actual, 6),
- 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
- 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
- 'arch' : arch,
- 'bits' : bits,
- 'count' : DataSource.cpu_count,
- 'raw_arch_string' : DataSource.raw_arch_string,
- 'l2_cache_size' : cache_info['size_kb'],
- 'l2_cache_line_size' : cache_info['line_size_b'],
- 'l2_cache_associativity' : hex(cache_info['associativity']),
- 'stepping' : info['stepping'],
- 'model' : info['model'],
- 'family' : info['family'],
- 'processor_type' : info['processor_type'],
- 'extended_model' : info['extended_model'],
- 'extended_family' : info['extended_family'],
- 'flags' : cpuid.get_flags(max_extension_support)
- }
- return obj_to_b64(info)
- def get_cpu_info_from_proc_cpuinfo():
- '''
- Returns the CPU info gathered from /proc/cpuinfo. Will return None if
- /proc/cpuinfo is not found.
- '''
- try:
- # Just return None if there is no cpuinfo
- if not DataSource.has_proc_cpuinfo():
- return None
- returncode, output = DataSource.cat_proc_cpuinfo()
- if returncode != 0:
- return None
- # Various fields
- vendor_id = _get_field(False, output, None, '', 'vendor_id', 'vendor id', 'vendor')
- processor_brand = _get_field(True, output, None, None, 'model name','cpu', 'processor')
- cache_size = _get_field(False, output, None, '', 'cache size')
- stepping = _get_field(False, output, int, 0, 'stepping')
- model = _get_field(False, output, int, 0, 'model')
- family = _get_field(False, output, int, 0, 'cpu family')
- hardware = _get_field(False, output, None, '', 'Hardware')
- # Flags
- flags = _get_field(False, output, None, None, 'flags', 'Features').split()
- flags.sort()
- # Convert from MHz string to Hz
- hz_actual = _get_field(False, output, None, '', 'cpu MHz', 'cpu speed', 'clock')
- hz_actual = hz_actual.lower().rstrip('mhz').strip()
- hz_actual = to_hz_string(hz_actual)
- # Convert from GHz/MHz string to Hz
- scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
- # Try getting the Hz for a BeagleBone
- if hz_advertised == '0.0':
- scale, hz_advertised = _get_hz_string_from_beagle_bone()
- hz_actual = hz_advertised
- # Try getting the Hz for a lscpu
- if hz_advertised == '0.0':
- scale, hz_advertised = _get_hz_string_from_lscpu()
- hz_actual = hz_advertised
- # Get the CPU arch and bits
- arch, bits = parse_arch(DataSource.raw_arch_string)
- return {
- 'vendor_id' : vendor_id,
- 'hardware' : hardware,
- 'brand' : processor_brand,
- 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
- 'hz_actual' : to_friendly_hz(hz_actual, 6),
- 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
- 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
- 'arch' : arch,
- 'bits' : bits,
- 'count' : DataSource.cpu_count,
- 'raw_arch_string' : DataSource.raw_arch_string,
- 'l2_cache_size' : cache_size,
- 'l2_cache_line_size' : 0,
- 'l2_cache_associativity' : 0,
- 'stepping' : stepping,
- 'model' : model,
- 'family' : family,
- 'processor_type' : 0,
- 'extended_model' : 0,
- 'extended_family' : 0,
- 'flags' : flags
- }
- except:
- #raise # NOTE: To have this throw on error, uncomment this line
- return None
- def get_cpu_info_from_dmesg():
- '''
- Returns the CPU info gathered from dmesg. Will return None if
- dmesg is not found or does not have the desired info.
- '''
- try:
- # Just return None if there is no dmesg
- if not DataSource.has_dmesg():
- return None
- # If dmesg fails return None
- returncode, output = DataSource.dmesg_a()
- if output == None or returncode != 0:
- return None
- # Processor Brand
- long_brand = output.split('CPU: ')[1].split('\n')[0]
- processor_brand = long_brand.rsplit('(', 1)[0]
- processor_brand = processor_brand.strip()
- # Hz
- scale = 0
- hz_actual = long_brand.rsplit('(', 1)[1].split(' ')[0].lower()
- if hz_actual.endswith('mhz'):
- scale = 6
- elif hz_actual.endswith('ghz'):
- scale = 9
- hz_actual = hz_actual.split('-')[0]
- hz_actual = to_hz_string(hz_actual)
- # Various fields
- fields = output.split('CPU: ')[1].split('\n')[1].split('\n')[0].strip().split(' ')
- vendor_id = None
- stepping = None
- model = None
- family = None
- for field in fields:
- name, value = field.split('=')
- name = name.strip().lower()
- value = value.strip()
- if name == 'origin':
- vendor_id = value.strip('"')
- elif name == 'stepping':
- stepping = int(value)
- elif name == 'model':
- model = int(value, 16)
- elif name == 'family':
- family = int(value, 16)
- # Flags
- flag_lines = []
- for category in [' Features=', ' Features2=', ' AMD Features=', ' AMD Features2=']:
- if category in output:
- flag_lines.append(output.split(category)[1].split('\n')[0])
- flags = []
- for line in flag_lines:
- line = line.split('<')[1].split('>')[0].lower()
- for flag in line.split(','):
- flags.append(flag)
- flags.sort()
- # Convert from GHz/MHz string to Hz
- scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
- # Get the CPU arch and bits
- arch, bits = parse_arch(DataSource.raw_arch_string)
- return {
- 'vendor_id' : vendor_id,
- 'hardware' : '',
- 'brand' : processor_brand,
- 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
- 'hz_actual' : to_friendly_hz(hz_actual, 6),
- 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
- 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
- 'arch' : arch,
- 'bits' : bits,
- 'count' : DataSource.cpu_count,
- 'raw_arch_string' : DataSource.raw_arch_string,
- 'l2_cache_size' : 0,
- 'l2_cache_line_size' : 0,
- 'l2_cache_associativity' : 0,
- 'stepping' : stepping,
- 'model' : model,
- 'family' : family,
- 'processor_type' : 0,
- 'extended_model' : 0,
- 'extended_family' : 0,
- 'flags' : flags
- }
- except:
- return None
- def get_cpu_info_from_sysctl():
- '''
- Returns the CPU info gathered from sysctl. Will return None if
- sysctl is not found.
- '''
- try:
- # Just return None if there is no sysctl
- if not DataSource.has_sysctl():
- return None
- # If sysctl fails return None
- returncode, output = DataSource.sysctl_machdep_cpu_hw_cpufrequency()
- if output == None or returncode != 0:
- return None
- # Various fields
- vendor_id = _get_field(False, output, None, None, 'machdep.cpu.vendor')
- processor_brand = _get_field(True, output, None, None, 'machdep.cpu.brand_string')
- cache_size = _get_field(False, output, None, None, 'machdep.cpu.cache.size')
- stepping = _get_field(False, output, int, 0, 'machdep.cpu.stepping')
- model = _get_field(False, output, int, 0, 'machdep.cpu.model')
- family = _get_field(False, output, int, 0, 'machdep.cpu.family')
- # Flags
- flags = _get_field(False, output, None, None, 'machdep.cpu.features').lower().split()
- flags.sort()
- # Convert from GHz/MHz string to Hz
- scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
- hz_actual = _get_field(False, output, None, None, 'hw.cpufrequency')
- hz_actual = to_hz_string(hz_actual)
- # Get the CPU arch and bits
- arch, bits = parse_arch(DataSource.raw_arch_string)
- return {
- 'vendor_id' : vendor_id,
- 'hardware' : '',
- 'brand' : processor_brand,
- 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
- 'hz_actual' : to_friendly_hz(hz_actual, 0),
- 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
- 'hz_actual_raw' : to_raw_hz(hz_actual, 0),
- 'arch' : arch,
- 'bits' : bits,
- 'count' : DataSource.cpu_count,
- 'raw_arch_string' : DataSource.raw_arch_string,
- 'l2_cache_size' : cache_size,
- 'l2_cache_line_size' : 0,
- 'l2_cache_associativity' : 0,
- 'stepping' : stepping,
- 'model' : model,
- 'family' : family,
- 'processor_type' : 0,
- 'extended_model' : 0,
- 'extended_family' : 0,
- 'flags' : flags
- }
- except:
- return None
- def get_cpu_info_from_sysinfo():
- '''
- Returns the CPU info gathered from sysinfo. Will return None if
- sysinfo is not found.
- '''
- try:
- # Just return None if there is no sysinfo
- if not DataSource.has_sysinfo():
- return None
- # If sysinfo fails return None
- returncode, output = DataSource.sysinfo_cpu()
- if output == None or returncode != 0:
- return None
- # Various fields
- vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ')
- processor_brand = output.split('CPU #0: "')[1].split('"\n')[0]
- cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size')
- stepping = int(output.split(', stepping ')[1].split(',')[0].strip())
- model = int(output.split(', model ')[1].split(',')[0].strip())
- family = int(output.split(', family ')[1].split(',')[0].strip())
- # Flags
- flags = []
- for line in output.split('\n'):
- if line.startswith('\t\t'):
- for flag in line.strip().lower().split():
- flags.append(flag)
- flags.sort()
- # Convert from GHz/MHz string to Hz
- scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
- hz_actual = hz_advertised
- # Get the CPU arch and bits
- arch, bits = parse_arch(DataSource.raw_arch_string)
- return {
- 'vendor_id' : vendor_id,
- 'hardware' : '',
- 'brand' : processor_brand,
- 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
- 'hz_actual' : to_friendly_hz(hz_actual, scale),
- 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
- 'hz_actual_raw' : to_raw_hz(hz_actual, scale),
- 'arch' : arch,
- 'bits' : bits,
- 'count' : DataSource.cpu_count,
- 'raw_arch_string' : DataSource.raw_arch_string,
- 'l2_cache_size' : cache_size,
- 'l2_cache_line_size' : 0,
- 'l2_cache_associativity' : 0,
- 'stepping' : stepping,
- 'model' : model,
- 'family' : family,
- 'processor_type' : 0,
- 'extended_model' : 0,
- 'extended_family' : 0,
- 'flags' : flags
- }
- except:
- return None
- def get_cpu_info_from_registry():
- '''
- FIXME: Is missing many of the newer CPU flags like sse3
- Returns the CPU info gathered from the Windows Registry. Will return None if
- not on Windows.
- '''
- try:
- # Just return None if not on Windows
- if not DataSource.is_windows:
- return None
- # Get the CPU name
- processor_brand = DataSource.winreg_processor_brand()
- # Get the CPU vendor id
- vendor_id = DataSource.winreg_vendor_id()
- # Get the CPU arch and bits
- raw_arch_string = DataSource.winreg_raw_arch_string()
- arch, bits = parse_arch(raw_arch_string)
- # Get the actual CPU Hz
- hz_actual = DataSource.winreg_hz_actual()
- hz_actual = to_hz_string(hz_actual)
- # Get the advertised CPU Hz
- scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
- # Get the CPU features
- feature_bits = DataSource.winreg_feature_bits()
- def is_set(bit):
- mask = 0x80000000 >> bit
- retval = mask & feature_bits > 0
- return retval
- # http://en.wikipedia.org/wiki/CPUID
- # http://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean
- # http://www.lohninger.com/helpcsuite/public_constants_cpuid.htm
- flags = {
- 'fpu' : is_set(0), # Floating Point Unit
- 'vme' : is_set(1), # V86 Mode Extensions
- 'de' : is_set(2), # Debug Extensions - I/O breakpoints supported
- 'pse' : is_set(3), # Page Size Extensions (4 MB pages supported)
- 'tsc' : is_set(4), # Time Stamp Counter and RDTSC instruction are available
- 'msr' : is_set(5), # Model Specific Registers
- 'pae' : is_set(6), # Physical Address Extensions (36 bit address, 2MB pages)
- 'mce' : is_set(7), # Machine Check Exception supported
- 'cx8' : is_set(8), # Compare Exchange Eight Byte instruction available
- 'apic' : is_set(9), # Local APIC present (multiprocessor operation support)
- 'sepamd' : is_set(10), # Fast system calls (AMD only)
- 'sep' : is_set(11), # Fast system calls
- 'mtrr' : is_set(12), # Memory Type Range Registers
- 'pge' : is_set(13), # Page Global Enable
- 'mca' : is_set(14), # Machine Check Architecture
- 'cmov' : is_set(15), # Conditional MOVe instructions
- 'pat' : is_set(16), # Page Attribute Table
- 'pse36' : is_set(17), # 36 bit Page Size Extensions
- 'serial' : is_set(18), # Processor Serial Number
- 'clflush' : is_set(19), # Cache Flush
- #'reserved1' : is_set(20), # reserved
- 'dts' : is_set(21), # Debug Trace Store
- 'acpi' : is_set(22), # ACPI support
- 'mmx' : is_set(23), # MultiMedia Extensions
- 'fxsr' : is_set(24), # FXSAVE and FXRSTOR instructions
- 'sse' : is_set(25), # SSE instructions
- 'sse2' : is_set(26), # SSE2 (WNI) instructions
- 'ss' : is_set(27), # self snoop
- #'reserved2' : is_set(28), # reserved
- 'tm' : is_set(29), # Automatic clock control
- 'ia64' : is_set(30), # IA64 instructions
- '3dnow' : is_set(31) # 3DNow! instructions available
- }
- # Get a list of only the flags that are true
- flags = [k for k, v in flags.items() if v]
- flags.sort()
- return {
- 'vendor_id' : vendor_id,
- 'hardware' : '',
- 'brand' : processor_brand,
- 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
- 'hz_actual' : to_friendly_hz(hz_actual, 6),
- 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
- 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
- 'arch' : arch,
- 'bits' : bits,
- 'count' : DataSource.cpu_count,
- 'raw_arch_string' : raw_arch_string,
- 'l2_cache_size' : 0,
- 'l2_cache_line_size' : 0,
- 'l2_cache_associativity' : 0,
- 'stepping' : 0,
- 'model' : 0,
- 'family' : 0,
- 'processor_type' : 0,
- 'extended_model' : 0,
- 'extended_family' : 0,
- 'flags' : flags
- }
- except:
- return None
- def get_cpu_info_from_kstat():
- '''
- Returns the CPU info gathered from isainfo and kstat. Will
- return None if isainfo or kstat are not found.
- '''
- try:
- # Just return None if there is no isainfo or kstat
- if not DataSource.has_isainfo() or not DataSource.has_kstat():
- return None
- # If isainfo fails return None
- returncode, flag_output = DataSource.isainfo_vb()
- if flag_output == None or returncode != 0:
- return None
- # If kstat fails return None
- returncode, kstat = DataSource.kstat_m_cpu_info()
- if kstat == None or returncode != 0:
- return None
- # Various fields
- vendor_id = kstat.split('\tvendor_id ')[1].split('\n')[0].strip()
- processor_brand = kstat.split('\tbrand ')[1].split('\n')[0].strip()
- cache_size = 0
- stepping = int(kstat.split('\tstepping ')[1].split('\n')[0].strip())
- model = int(kstat.split('\tmodel ')[1].split('\n')[0].strip())
- family = int(kstat.split('\tfamily ')[1].split('\n')[0].strip())
- # Flags
- flags = flag_output.strip().split('\n')[-1].strip().lower().split()
- flags.sort()
- # Convert from GHz/MHz string to Hz
- scale = 6
- hz_advertised = kstat.split('\tclock_MHz ')[1].split('\n')[0].strip()
- hz_advertised = to_hz_string(hz_advertised)
- # Convert from GHz/MHz string to Hz
- hz_actual = kstat.split('\tcurrent_clock_Hz ')[1].split('\n')[0].strip()
- hz_actual = to_hz_string(hz_actual)
- # Get the CPU arch and bits
- arch, bits = parse_arch(DataSource.raw_arch_string)
- return {
- 'vendor_id' : vendor_id,
- 'hardware' : '',
- 'brand' : processor_brand,
- 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
- 'hz_actual' : to_friendly_hz(hz_actual, 0),
- 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
- 'hz_actual_raw' : to_raw_hz(hz_actual, 0),
- 'arch' : arch,
- 'bits' : bits,
- 'count' : DataSource.cpu_count,
- 'raw_arch_string' : DataSource.raw_arch_string,
- 'l2_cache_size' : cache_size,
- 'l2_cache_line_size' : 0,
- 'l2_cache_associativity' : 0,
- 'stepping' : stepping,
- 'model' : model,
- 'family' : family,
- 'processor_type' : 0,
- 'extended_model' : 0,
- 'extended_family' : 0,
- 'flags' : flags
- }
- except:
- return None
- def get_cpu_info():
- info = None
- # Try the Windows registry
- if not info:
- info = get_cpu_info_from_registry()
- # Try /proc/cpuinfo
- if not info:
- info = get_cpu_info_from_proc_cpuinfo()
- # Try sysctl
- if not info:
- info = get_cpu_info_from_sysctl()
- # Try kstat
- if not info:
- info = get_cpu_info_from_kstat()
- # Try dmesg
- if not info:
- info = get_cpu_info_from_dmesg()
- # Try sysinfo
- if not info:
- info = get_cpu_info_from_sysinfo()
- # Try querying the CPU cpuid register
- if not info:
- info = get_cpu_info_from_cpuid()
- return info
- # Make sure we are running on a supported system
- def _check_arch():
- arch, bits = parse_arch(DataSource.raw_arch_string)
- if not arch in ['X86_32', 'X86_64', 'ARM_7', 'ARM_8']:
- raise Exception("py-cpuinfo currently only works on X86 and some ARM CPUs.")
- def main():
- try:
- _check_arch()
- except Exception as err:
- sys.stderr.write(str(err) + "\n")
- sys.exit(1)
- info = get_cpu_info()
- if info:
- print('Vendor ID: {0}'.format(info.get('vendor_id', '')))
- print('Hardware Raw: {0}'.format(info.get('hardware', '')))
- print('Brand: {0}'.format(info.get('brand', '')))
- print('Hz Advertised: {0}'.format(info.get('hz_advertised', '')))
- print('Hz Actual: {0}'.format(info.get('hz_actual', '')))
- print('Hz Advertised Raw: {0}'.format(info.get('hz_advertised_raw', '')))
- print('Hz Actual Raw: {0}'.format(info.get('hz_actual_raw', '')))
- print('Arch: {0}'.format(info.get('arch', '')))
- print('Bits: {0}'.format(info.get('bits', '')))
- print('Count: {0}'.format(info.get('count', '')))
- print('Raw Arch String: {0}'.format(info.get('raw_arch_string', '')))
- print('L2 Cache Size: {0}'.format(info.get('l2_cache_size', '')))
- print('L2 Cache Line Size: {0}'.format(info.get('l2_cache_line_size', '')))
- print('L2 Cache Associativity: {0}'.format(info.get('l2_cache_associativity', '')))
- print('Stepping: {0}'.format(info.get('stepping', '')))
- print('Model: {0}'.format(info.get('model', '')))
- print('Family: {0}'.format(info.get('family', '')))
- print('Processor Type: {0}'.format(info.get('processor_type', '')))
- print('Extended Model: {0}'.format(info.get('extended_model', '')))
- print('Extended Family: {0}'.format(info.get('extended_family', '')))
- print('Flags: {0}'.format(', '.join(info.get('flags', ''))))
- else:
- sys.stderr.write("Failed to find cpu info\n")
- sys.exit(1)
- if __name__ == '__main__':
- main()
- else:
- _check_arch()
|