cpuinfo.py 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565
  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3. # Copyright (c) 2014-2016, Matthew Brennan Jones <matthew.brennan.jones@gmail.com>
  4. # Py-cpuinfo is a Python module to show the cpuinfo of a processor
  5. # It uses a MIT style license
  6. # It is hosted at: https://github.com/workhorsy/py-cpuinfo
  7. #
  8. # Permission is hereby granted, free of charge, to any person obtaining
  9. # a copy of this software and associated documentation files (the
  10. # "Software"), to deal in the Software without restriction, including
  11. # without limitation the rights to use, copy, modify, merge, publish,
  12. # distribute, sublicense, and/or sell copies of the Software, and to
  13. # permit persons to whom the Software is furnished to do so, subject to
  14. # the following conditions:
  15. #
  16. # The above copyright notice and this permission notice shall be included
  17. # in all copies or substantial portions of the Software.
  18. #
  19. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  22. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23. # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24. # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26. import os, sys
  27. import re
  28. import time
  29. import platform
  30. import multiprocessing
  31. import ctypes
  32. import pickle
  33. import base64
  34. import subprocess
  35. try:
  36. import _winreg as winreg
  37. except ImportError as err:
  38. try:
  39. import winreg
  40. except ImportError as err:
  41. pass
  42. PY2 = sys.version_info[0] == 2
  43. class DataSource(object):
  44. bits = platform.architecture()[0]
  45. cpu_count = multiprocessing.cpu_count()
  46. is_windows = platform.system().lower() == 'windows'
  47. raw_arch_string = platform.machine()
  48. @staticmethod
  49. def has_proc_cpuinfo():
  50. return os.path.exists('/proc/cpuinfo')
  51. @staticmethod
  52. def has_dmesg():
  53. return len(program_paths('dmesg')) > 0
  54. @staticmethod
  55. def has_cpufreq_info():
  56. return len(program_paths('cpufreq-info')) > 0
  57. @staticmethod
  58. def has_sestatus():
  59. return len(program_paths('sestatus')) > 0
  60. @staticmethod
  61. def has_sysctl():
  62. return len(program_paths('sysctl')) > 0
  63. @staticmethod
  64. def has_isainfo():
  65. return len(program_paths('isainfo')) > 0
  66. @staticmethod
  67. def has_kstat():
  68. return len(program_paths('kstat')) > 0
  69. @staticmethod
  70. def has_sysinfo():
  71. return len(program_paths('sysinfo')) > 0
  72. @staticmethod
  73. def has_lscpu():
  74. return len(program_paths('lscpu')) > 0
  75. @staticmethod
  76. def cat_proc_cpuinfo():
  77. return run_and_get_stdout(['cat', '/proc/cpuinfo'])
  78. @staticmethod
  79. def cpufreq_info():
  80. return run_and_get_stdout(['cpufreq-info'])
  81. @staticmethod
  82. def sestatus_allow_execheap():
  83. return run_and_get_stdout(['sestatus', '-b'], ['grep', '-i', '"allow_execheap"'])[1].strip().lower().endswith('on')
  84. @staticmethod
  85. def sestatus_allow_execmem():
  86. return run_and_get_stdout(['sestatus', '-b'], ['grep', '-i', '"allow_execmem"'])[1].strip().lower().endswith('on')
  87. @staticmethod
  88. def dmesg_a():
  89. return run_and_get_stdout(['dmesg', '-a'])
  90. @staticmethod
  91. def sysctl_machdep_cpu_hw_cpufrequency():
  92. return run_and_get_stdout(['sysctl', 'machdep.cpu', 'hw.cpufrequency'])
  93. @staticmethod
  94. def isainfo_vb():
  95. return run_and_get_stdout(['isainfo', '-vb'])
  96. @staticmethod
  97. def kstat_m_cpu_info():
  98. return run_and_get_stdout(['kstat', '-m', 'cpu_info'])
  99. @staticmethod
  100. def sysinfo_cpu():
  101. return run_and_get_stdout(['sysinfo', '-cpu'])
  102. @staticmethod
  103. def lscpu():
  104. return run_and_get_stdout(['lscpu'])
  105. @staticmethod
  106. def winreg_processor_brand():
  107. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  108. processor_brand = winreg.QueryValueEx(key, "ProcessorNameString")[0]
  109. winreg.CloseKey(key)
  110. return processor_brand
  111. @staticmethod
  112. def winreg_vendor_id():
  113. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  114. vendor_id = winreg.QueryValueEx(key, "VendorIdentifier")[0]
  115. winreg.CloseKey(key)
  116. return vendor_id
  117. @staticmethod
  118. def winreg_raw_arch_string():
  119. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")
  120. raw_arch_string = winreg.QueryValueEx(key, "PROCESSOR_ARCHITECTURE")[0]
  121. winreg.CloseKey(key)
  122. return raw_arch_string
  123. @staticmethod
  124. def winreg_hz_actual():
  125. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  126. hz_actual = winreg.QueryValueEx(key, "~Mhz")[0]
  127. winreg.CloseKey(key)
  128. hz_actual = to_hz_string(hz_actual)
  129. return hz_actual
  130. @staticmethod
  131. def winreg_feature_bits():
  132. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  133. feature_bits = winreg.QueryValueEx(key, "FeatureSet")[0]
  134. winreg.CloseKey(key)
  135. return feature_bits
  136. def obj_to_b64(thing):
  137. a = thing
  138. b = pickle.dumps(a)
  139. c = base64.b64encode(b)
  140. d = c.decode('utf8')
  141. return d
  142. def b64_to_obj(thing):
  143. a = base64.b64decode(thing)
  144. b = pickle.loads(a)
  145. return b
  146. def run_and_get_stdout(command, pipe_command=None):
  147. if not pipe_command:
  148. p1 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  149. output = p1.communicate()[0]
  150. if not PY2:
  151. output = output.decode(encoding='UTF-8')
  152. return p1.returncode, output
  153. else:
  154. p1 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  155. p2 = subprocess.Popen(pipe_command, stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  156. p1.stdout.close()
  157. output = p2.communicate()[0]
  158. if not PY2:
  159. output = output.decode(encoding='UTF-8')
  160. return p2.returncode, output
  161. def program_paths(program_name):
  162. paths = []
  163. exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
  164. path = os.environ['PATH']
  165. for p in os.environ['PATH'].split(os.pathsep):
  166. p = os.path.join(p, program_name)
  167. if os.access(p, os.X_OK):
  168. paths.append(p)
  169. for e in exts:
  170. pext = p + e
  171. if os.access(pext, os.X_OK):
  172. paths.append(pext)
  173. return paths
  174. def _get_field_actual(cant_be_number, raw_string, field_names):
  175. for line in raw_string.splitlines():
  176. for field_name in field_names:
  177. field_name = field_name.lower()
  178. if ':' in line:
  179. left, right = line.split(':', 1)
  180. left = left.strip().lower()
  181. right = right.strip()
  182. if left == field_name and len(right) > 0:
  183. if cant_be_number:
  184. if not right.isdigit():
  185. return right
  186. else:
  187. return right
  188. return None
  189. def _get_field(cant_be_number, raw_string, convert_to, default_value, *field_names):
  190. retval = _get_field_actual(cant_be_number, raw_string, field_names)
  191. # Convert the return value
  192. if retval and convert_to:
  193. try:
  194. retval = convert_to(retval)
  195. except:
  196. retval = default_value
  197. # Return the default if there is no return value
  198. if retval is None:
  199. retval = default_value
  200. return retval
  201. def _get_hz_string_from_brand(processor_brand):
  202. # Just return 0 if the processor brand does not have the Hz
  203. if not 'hz' in processor_brand.lower():
  204. return (1, '0.0')
  205. hz_brand = processor_brand.lower()
  206. scale = 1
  207. if hz_brand.endswith('mhz'):
  208. scale = 6
  209. elif hz_brand.endswith('ghz'):
  210. scale = 9
  211. if '@' in hz_brand:
  212. hz_brand = hz_brand.split('@')[1]
  213. else:
  214. hz_brand = hz_brand.rsplit(None, 1)[1]
  215. hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip()
  216. hz_brand = to_hz_string(hz_brand)
  217. return (scale, hz_brand)
  218. def _get_hz_string_from_beagle_bone():
  219. scale, hz_brand = 1, '0.0'
  220. if not DataSource.has_cpufreq_info():
  221. return scale, hz_brand
  222. returncode, output = DataSource.cpufreq_info()
  223. if returncode != 0:
  224. return (scale, hz_brand)
  225. hz_brand = output.split('current CPU frequency is')[1].split('.')[0].lower()
  226. if hz_brand.endswith('mhz'):
  227. scale = 6
  228. elif hz_brand.endswith('ghz'):
  229. scale = 9
  230. hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip()
  231. hz_brand = to_hz_string(hz_brand)
  232. return (scale, hz_brand)
  233. def _get_hz_string_from_lscpu():
  234. scale, hz_brand = 1, '0.0'
  235. if not DataSource.has_lscpu():
  236. return scale, hz_brand
  237. returncode, output = DataSource.lscpu()
  238. if returncode != 0:
  239. return (scale, hz_brand)
  240. new_hz = _get_field(False, output, None, None, 'CPU max MHz', 'CPU MHz')
  241. if new_hz == None:
  242. return (scale, hz_brand)
  243. new_hz = to_hz_string(new_hz)
  244. scale = 6
  245. return (scale, new_hz)
  246. def to_friendly_hz(ticks, scale):
  247. # Get the raw Hz as a string
  248. left, right = to_raw_hz(ticks, scale)
  249. ticks = '{0}.{1}'.format(left, right)
  250. # Get the location of the dot, and remove said dot
  251. dot_index = ticks.index('.')
  252. ticks = ticks.replace('.', '')
  253. # Get the Hz symbol and scale
  254. symbol = "Hz"
  255. scale = 0
  256. if dot_index > 9:
  257. symbol = "GHz"
  258. scale = 9
  259. elif dot_index > 6:
  260. symbol = "MHz"
  261. scale = 6
  262. elif dot_index > 3:
  263. symbol = "KHz"
  264. scale = 3
  265. # Get the Hz with the dot at the new scaled point
  266. ticks = '{0}.{1}'.format(ticks[:-scale-1], ticks[-scale-1:])
  267. # Format the ticks to have 4 numbers after the decimal
  268. # and remove any superfluous zeroes.
  269. ticks = '{0:.4f} {1}'.format(float(ticks), symbol)
  270. ticks = ticks.rstrip('0')
  271. return ticks
  272. def to_raw_hz(ticks, scale):
  273. # Scale the numbers
  274. ticks = ticks.lstrip('0')
  275. old_index = ticks.index('.')
  276. ticks = ticks.replace('.', '')
  277. ticks = ticks.ljust(scale + old_index+1, '0')
  278. new_index = old_index + scale
  279. ticks = '{0}.{1}'.format(ticks[:new_index], ticks[new_index:])
  280. left, right = ticks.split('.')
  281. left, right = int(left), int(right)
  282. return (left, right)
  283. def to_hz_string(ticks):
  284. # Convert to string
  285. ticks = '{0}'.format(ticks)
  286. # Add decimal if missing
  287. if '.' not in ticks:
  288. ticks = '{0}.0'.format(ticks)
  289. # Remove trailing zeros
  290. ticks = ticks.rstrip('0')
  291. # Add one trailing zero for empty right side
  292. if ticks.endswith('.'):
  293. ticks = '{0}0'.format(ticks)
  294. return ticks
  295. def parse_arch(raw_arch_string):
  296. arch, bits = None, None
  297. raw_arch_string = raw_arch_string.lower()
  298. # X86
  299. if re.match('^i\d86$|^x86$|^x86_32$|^i86pc$|^ia32$|^ia-32$|^bepc$', raw_arch_string):
  300. arch = 'X86_32'
  301. bits = 32
  302. elif re.match('^x64$|^x86_64$|^x86_64t$|^i686-64$|^amd64$|^ia64$|^ia-64$', raw_arch_string):
  303. arch = 'X86_64'
  304. bits = 64
  305. # ARM
  306. elif re.match('^armv8-a$', raw_arch_string):
  307. arch = 'ARM_8'
  308. bits = 64
  309. elif re.match('^armv7$|^armv7[a-z]$|^armv7-[a-z]$|^armv6[a-z]$', raw_arch_string):
  310. arch = 'ARM_7'
  311. bits = 32
  312. elif re.match('^armv8$|^armv8[a-z]$|^armv8-[a-z]$', raw_arch_string):
  313. arch = 'ARM_8'
  314. bits = 32
  315. # PPC
  316. elif re.match('^ppc32$|^prep$|^pmac$|^powermac$', raw_arch_string):
  317. arch = 'PPC_32'
  318. bits = 32
  319. elif re.match('^powerpc$|^ppc64$', raw_arch_string):
  320. arch = 'PPC_64'
  321. bits = 64
  322. # SPARC
  323. elif re.match('^sparc32$|^sparc$', raw_arch_string):
  324. arch = 'SPARC_32'
  325. bits = 32
  326. elif re.match('^sparc64$|^sun4u$|^sun4v$', raw_arch_string):
  327. arch = 'SPARC_64'
  328. bits = 64
  329. return (arch, bits)
  330. def is_bit_set(reg, bit):
  331. mask = 1 << bit
  332. is_set = reg & mask > 0
  333. return is_set
  334. class CPUID(object):
  335. def __init__(self):
  336. # Figure out if SE Linux is on and in enforcing mode
  337. self.is_selinux_enforcing = False
  338. # Just return if the SE Linux Status Tool is not installed
  339. if not DataSource.has_sestatus():
  340. return
  341. # Figure out if we can execute heap and execute memory
  342. can_selinux_exec_heap = DataSource.sestatus_allow_execheap()
  343. can_selinux_exec_memory = DataSource.sestatus_allow_execmem()
  344. self.is_selinux_enforcing = (not can_selinux_exec_heap or not can_selinux_exec_memory)
  345. def _asm_func(self, restype=None, argtypes=(), byte_code=[]):
  346. byte_code = bytes.join(b'', byte_code)
  347. address = None
  348. if DataSource.is_windows:
  349. # Allocate a memory segment the size of the byte code, and make it executable
  350. size = len(byte_code)
  351. MEM_COMMIT = ctypes.c_ulong(0x1000)
  352. PAGE_EXECUTE_READWRITE = ctypes.c_ulong(0x40)
  353. address = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_size_t(size), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
  354. if not address:
  355. raise Exception("Failed to VirtualAlloc")
  356. # Copy the byte code into the memory segment
  357. memmove = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)(ctypes._memmove_addr)
  358. if memmove(address, byte_code, size) < 0:
  359. raise Exception("Failed to memmove")
  360. else:
  361. # Allocate a memory segment the size of the byte code
  362. size = len(byte_code)
  363. address = ctypes.pythonapi.valloc(size)
  364. if not address:
  365. raise Exception("Failed to valloc")
  366. # Mark the memory segment as writeable only
  367. if not self.is_selinux_enforcing:
  368. WRITE = 0x2
  369. if ctypes.pythonapi.mprotect(address, size, WRITE) < 0:
  370. raise Exception("Failed to mprotect")
  371. # Copy the byte code into the memory segment
  372. if ctypes.pythonapi.memmove(address, byte_code, size) < 0:
  373. raise Exception("Failed to memmove")
  374. # Mark the memory segment as writeable and executable only
  375. if not self.is_selinux_enforcing:
  376. WRITE_EXECUTE = 0x2 | 0x4
  377. if ctypes.pythonapi.mprotect(address, size, WRITE_EXECUTE) < 0:
  378. raise Exception("Failed to mprotect")
  379. # Cast the memory segment into a function
  380. functype = ctypes.CFUNCTYPE(restype, *argtypes)
  381. fun = functype(address)
  382. return fun, address
  383. def _run_asm(self, *byte_code):
  384. # Convert the byte code into a function that returns an int
  385. restype = None
  386. if DataSource.bits == '64bit':
  387. restype = ctypes.c_uint64
  388. else:
  389. restype = ctypes.c_uint32
  390. argtypes = ()
  391. func, address = self._asm_func(restype, argtypes, byte_code)
  392. # Call the byte code like a function
  393. retval = func()
  394. size = ctypes.c_size_t(len(byte_code))
  395. # Free the function memory segment
  396. if DataSource.is_windows:
  397. MEM_RELEASE = ctypes.c_ulong(0x8000)
  398. ctypes.windll.kernel32.VirtualFree(address, size, MEM_RELEASE)
  399. else:
  400. # Remove the executable tag on the memory
  401. READ_WRITE = 0x1 | 0x2
  402. if ctypes.pythonapi.mprotect(address, size, READ_WRITE) < 0:
  403. raise Exception("Failed to mprotect")
  404. ctypes.pythonapi.free(address)
  405. return retval
  406. # FIXME: We should not have to use different instructions to
  407. # set eax to 0 or 1, on 32bit and 64bit machines.
  408. def _zero_eax(self):
  409. if DataSource.bits == '64bit':
  410. return (
  411. b"\x66\xB8\x00\x00" # mov eax,0x0"
  412. )
  413. else:
  414. return (
  415. b"\x31\xC0" # xor ax,ax
  416. )
  417. def _one_eax(self):
  418. if DataSource.bits == '64bit':
  419. return (
  420. b"\x66\xB8\x01\x00" # mov eax,0x1"
  421. )
  422. else:
  423. return (
  424. b"\x31\xC0" # xor ax,ax
  425. b"\x40" # inc ax
  426. )
  427. # http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
  428. def get_vendor_id(self):
  429. # EBX
  430. ebx = self._run_asm(
  431. self._zero_eax(),
  432. b"\x0F\xA2" # cpuid
  433. b"\x89\xD8" # mov ax,bx
  434. b"\xC3" # ret
  435. )
  436. # ECX
  437. ecx = self._run_asm(
  438. self._zero_eax(),
  439. b"\x0f\xa2" # cpuid
  440. b"\x89\xC8" # mov ax,cx
  441. b"\xC3" # ret
  442. )
  443. # EDX
  444. edx = self._run_asm(
  445. self._zero_eax(),
  446. b"\x0f\xa2" # cpuid
  447. b"\x89\xD0" # mov ax,dx
  448. b"\xC3" # ret
  449. )
  450. # Each 4bits is a ascii letter in the name
  451. vendor_id = []
  452. for reg in [ebx, edx, ecx]:
  453. for n in [0, 8, 16, 24]:
  454. vendor_id.append(chr((reg >> n) & 0xFF))
  455. vendor_id = ''.join(vendor_id)
  456. return vendor_id
  457. # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
  458. def get_info(self):
  459. # EAX
  460. eax = self._run_asm(
  461. self._one_eax(),
  462. b"\x0f\xa2" # cpuid
  463. b"\xC3" # ret
  464. )
  465. # Get the CPU info
  466. stepping = (eax >> 0) & 0xF # 4 bits
  467. model = (eax >> 4) & 0xF # 4 bits
  468. family = (eax >> 8) & 0xF # 4 bits
  469. processor_type = (eax >> 12) & 0x3 # 2 bits
  470. extended_model = (eax >> 16) & 0xF # 4 bits
  471. extended_family = (eax >> 20) & 0xFF # 8 bits
  472. return {
  473. 'stepping' : stepping,
  474. 'model' : model,
  475. 'family' : family,
  476. 'processor_type' : processor_type,
  477. 'extended_model' : extended_model,
  478. 'extended_family' : extended_family
  479. }
  480. # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000000h:_Get_Highest_Extended_Function_Supported
  481. def get_max_extension_support(self):
  482. # Check for extension support
  483. max_extension_support = self._run_asm(
  484. b"\xB8\x00\x00\x00\x80" # mov ax,0x80000000
  485. b"\x0f\xa2" # cpuid
  486. b"\xC3" # ret
  487. )
  488. return max_extension_support
  489. # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
  490. def get_flags(self, max_extension_support):
  491. # EDX
  492. edx = self._run_asm(
  493. self._one_eax(),
  494. b"\x0f\xa2" # cpuid
  495. b"\x89\xD0" # mov ax,dx
  496. b"\xC3" # ret
  497. )
  498. # ECX
  499. ecx = self._run_asm(
  500. self._one_eax(),
  501. b"\x0f\xa2" # cpuid
  502. b"\x89\xC8" # mov ax,cx
  503. b"\xC3" # ret
  504. )
  505. # Get the CPU flags
  506. flags = {
  507. 'fpu' : is_bit_set(edx, 0),
  508. 'vme' : is_bit_set(edx, 1),
  509. 'de' : is_bit_set(edx, 2),
  510. 'pse' : is_bit_set(edx, 3),
  511. 'tsc' : is_bit_set(edx, 4),
  512. 'msr' : is_bit_set(edx, 5),
  513. 'pae' : is_bit_set(edx, 6),
  514. 'mce' : is_bit_set(edx, 7),
  515. 'cx8' : is_bit_set(edx, 8),
  516. 'apic' : is_bit_set(edx, 9),
  517. #'reserved1' : is_bit_set(edx, 10),
  518. 'sep' : is_bit_set(edx, 11),
  519. 'mtrr' : is_bit_set(edx, 12),
  520. 'pge' : is_bit_set(edx, 13),
  521. 'mca' : is_bit_set(edx, 14),
  522. 'cmov' : is_bit_set(edx, 15),
  523. 'pat' : is_bit_set(edx, 16),
  524. 'pse36' : is_bit_set(edx, 17),
  525. 'pn' : is_bit_set(edx, 18),
  526. 'clflush' : is_bit_set(edx, 19),
  527. #'reserved2' : is_bit_set(edx, 20),
  528. 'dts' : is_bit_set(edx, 21),
  529. 'acpi' : is_bit_set(edx, 22),
  530. 'mmx' : is_bit_set(edx, 23),
  531. 'fxsr' : is_bit_set(edx, 24),
  532. 'sse' : is_bit_set(edx, 25),
  533. 'sse2' : is_bit_set(edx, 26),
  534. 'ss' : is_bit_set(edx, 27),
  535. 'ht' : is_bit_set(edx, 28),
  536. 'tm' : is_bit_set(edx, 29),
  537. 'ia64' : is_bit_set(edx, 30),
  538. 'pbe' : is_bit_set(edx, 31),
  539. 'pni' : is_bit_set(ecx, 0),
  540. 'pclmulqdq' : is_bit_set(ecx, 1),
  541. 'dtes64' : is_bit_set(ecx, 2),
  542. 'monitor' : is_bit_set(ecx, 3),
  543. 'ds_cpl' : is_bit_set(ecx, 4),
  544. 'vmx' : is_bit_set(ecx, 5),
  545. 'smx' : is_bit_set(ecx, 6),
  546. 'est' : is_bit_set(ecx, 7),
  547. 'tm2' : is_bit_set(ecx, 8),
  548. 'ssse3' : is_bit_set(ecx, 9),
  549. 'cid' : is_bit_set(ecx, 10),
  550. #'reserved3' : is_bit_set(ecx, 11),
  551. 'fma' : is_bit_set(ecx, 12),
  552. 'cx16' : is_bit_set(ecx, 13),
  553. 'xtpr' : is_bit_set(ecx, 14),
  554. 'pdcm' : is_bit_set(ecx, 15),
  555. #'reserved4' : is_bit_set(ecx, 16),
  556. 'pcid' : is_bit_set(ecx, 17),
  557. 'dca' : is_bit_set(ecx, 18),
  558. 'sse4_1' : is_bit_set(ecx, 19),
  559. 'sse4_2' : is_bit_set(ecx, 20),
  560. 'x2apic' : is_bit_set(ecx, 21),
  561. 'movbe' : is_bit_set(ecx, 22),
  562. 'popcnt' : is_bit_set(ecx, 23),
  563. 'tscdeadline' : is_bit_set(ecx, 24),
  564. 'aes' : is_bit_set(ecx, 25),
  565. 'xsave' : is_bit_set(ecx, 26),
  566. 'osxsave' : is_bit_set(ecx, 27),
  567. 'avx' : is_bit_set(ecx, 28),
  568. 'f16c' : is_bit_set(ecx, 29),
  569. 'rdrnd' : is_bit_set(ecx, 30),
  570. 'hypervisor' : is_bit_set(ecx, 31)
  571. }
  572. # Get a list of only the flags that are true
  573. flags = [k for k, v in flags.items() if v]
  574. # Get the Extended CPU flags
  575. extended_flags = {}
  576. # https://en.wikipedia.org/wiki/CPUID#EAX.3D7.2C_ECX.3D0:_Extended_Features
  577. if max_extension_support == 7:
  578. pass
  579. # FIXME: Are we missing all these flags too?
  580. # avx2 et cetera ...
  581. # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000001h:_Extended_Processor_Info_and_Feature_Bits
  582. if max_extension_support >= 0x80000001:
  583. # EBX # FIXME: This may need to be EDX instead
  584. ebx = self._run_asm(
  585. b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
  586. b"\x0f\xa2" # cpuid
  587. b"\x89\xD8" # mov ax,bx
  588. b"\xC3" # ret
  589. )
  590. # ECX
  591. ecx = self._run_asm(
  592. b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
  593. b"\x0f\xa2" # cpuid
  594. b"\x89\xC8" # mov ax,cx
  595. b"\xC3" # ret
  596. )
  597. # Get the extended CPU flags
  598. extended_flags = {
  599. 'fpu' : is_bit_set(ebx, 0),
  600. 'vme' : is_bit_set(ebx, 1),
  601. 'de' : is_bit_set(ebx, 2),
  602. 'pse' : is_bit_set(ebx, 3),
  603. 'tsc' : is_bit_set(ebx, 4),
  604. 'msr' : is_bit_set(ebx, 5),
  605. 'pae' : is_bit_set(ebx, 6),
  606. 'mce' : is_bit_set(ebx, 7),
  607. 'cx8' : is_bit_set(ebx, 8),
  608. 'apic' : is_bit_set(ebx, 9),
  609. #'reserved' : is_bit_set(ebx, 10),
  610. 'syscall' : is_bit_set(ebx, 11),
  611. 'mtrr' : is_bit_set(ebx, 12),
  612. 'pge' : is_bit_set(ebx, 13),
  613. 'mca' : is_bit_set(ebx, 14),
  614. 'cmov' : is_bit_set(ebx, 15),
  615. 'pat' : is_bit_set(ebx, 16),
  616. 'pse36' : is_bit_set(ebx, 17),
  617. #'reserved' : is_bit_set(ebx, 18),
  618. 'mp' : is_bit_set(ebx, 19),
  619. 'nx' : is_bit_set(ebx, 20),
  620. #'reserved' : is_bit_set(ebx, 21),
  621. 'mmxext' : is_bit_set(ebx, 22),
  622. 'mmx' : is_bit_set(ebx, 23),
  623. 'fxsr' : is_bit_set(ebx, 24),
  624. 'fxsr_opt' : is_bit_set(ebx, 25),
  625. 'pdpe1gp' : is_bit_set(ebx, 26),
  626. 'rdtscp' : is_bit_set(ebx, 27),
  627. #'reserved' : is_bit_set(ebx, 28),
  628. 'lm' : is_bit_set(ebx, 29),
  629. '3dnowext' : is_bit_set(ebx, 30),
  630. '3dnow' : is_bit_set(ebx, 31),
  631. 'lahf_lm' : is_bit_set(ecx, 0),
  632. 'cmp_legacy' : is_bit_set(ecx, 1),
  633. 'svm' : is_bit_set(ecx, 2),
  634. 'extapic' : is_bit_set(ecx, 3),
  635. 'cr8_legacy' : is_bit_set(ecx, 4),
  636. 'abm' : is_bit_set(ecx, 5),
  637. 'sse4a' : is_bit_set(ecx, 6),
  638. 'misalignsse' : is_bit_set(ecx, 7),
  639. '3dnowprefetch' : is_bit_set(ecx, 8),
  640. 'osvw' : is_bit_set(ecx, 9),
  641. 'ibs' : is_bit_set(ecx, 10),
  642. 'xop' : is_bit_set(ecx, 11),
  643. 'skinit' : is_bit_set(ecx, 12),
  644. 'wdt' : is_bit_set(ecx, 13),
  645. #'reserved' : is_bit_set(ecx, 14),
  646. 'lwp' : is_bit_set(ecx, 15),
  647. 'fma4' : is_bit_set(ecx, 16),
  648. 'tce' : is_bit_set(ecx, 17),
  649. #'reserved' : is_bit_set(ecx, 18),
  650. 'nodeid_msr' : is_bit_set(ecx, 19),
  651. #'reserved' : is_bit_set(ecx, 20),
  652. 'tbm' : is_bit_set(ecx, 21),
  653. 'topoext' : is_bit_set(ecx, 22),
  654. 'perfctr_core' : is_bit_set(ecx, 23),
  655. 'perfctr_nb' : is_bit_set(ecx, 24),
  656. #'reserved' : is_bit_set(ecx, 25),
  657. 'dbx' : is_bit_set(ecx, 26),
  658. 'perftsc' : is_bit_set(ecx, 27),
  659. 'pci_l2i' : is_bit_set(ecx, 28),
  660. #'reserved' : is_bit_set(ecx, 29),
  661. #'reserved' : is_bit_set(ecx, 30),
  662. #'reserved' : is_bit_set(ecx, 31)
  663. }
  664. # Get a list of only the flags that are true
  665. extended_flags = [k for k, v in extended_flags.items() if v]
  666. flags += extended_flags
  667. flags.sort()
  668. return flags
  669. # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000002h.2C80000003h.2C80000004h:_Processor_Brand_String
  670. def get_processor_brand(self, max_extension_support):
  671. processor_brand = ""
  672. # Processor brand string
  673. if max_extension_support >= 0x80000004:
  674. instructions = [
  675. b"\xB8\x02\x00\x00\x80", # mov ax,0x80000002
  676. b"\xB8\x03\x00\x00\x80", # mov ax,0x80000003
  677. b"\xB8\x04\x00\x00\x80" # mov ax,0x80000004
  678. ]
  679. for instruction in instructions:
  680. # EAX
  681. eax = self._run_asm(
  682. instruction, # mov ax,0x8000000?
  683. b"\x0f\xa2" # cpuid
  684. b"\x89\xC0" # mov ax,ax
  685. b"\xC3" # ret
  686. )
  687. # EBX
  688. ebx = self._run_asm(
  689. instruction, # mov ax,0x8000000?
  690. b"\x0f\xa2" # cpuid
  691. b"\x89\xD8" # mov ax,bx
  692. b"\xC3" # ret
  693. )
  694. # ECX
  695. ecx = self._run_asm(
  696. instruction, # mov ax,0x8000000?
  697. b"\x0f\xa2" # cpuid
  698. b"\x89\xC8" # mov ax,cx
  699. b"\xC3" # ret
  700. )
  701. # EDX
  702. edx = self._run_asm(
  703. instruction, # mov ax,0x8000000?
  704. b"\x0f\xa2" # cpuid
  705. b"\x89\xD0" # mov ax,dx
  706. b"\xC3" # ret
  707. )
  708. # Combine each of the 4 bytes in each register into the string
  709. for reg in [eax, ebx, ecx, edx]:
  710. for n in [0, 8, 16, 24]:
  711. processor_brand += chr((reg >> n) & 0xFF)
  712. # Strip off any trailing NULL terminators and white space
  713. processor_brand = processor_brand.strip("\0").strip()
  714. return processor_brand
  715. # https://en.wikipedia.org/wiki/CPUID#EAX.3D80000006h:_Extended_L2_Cache_Features
  716. def get_cache(self, max_extension_support):
  717. cache_info = {}
  718. # Just return if the cache feature is not supported
  719. if max_extension_support < 0x80000006:
  720. return cache_info
  721. # ECX
  722. ecx = self._run_asm(
  723. b"\xB8\x06\x00\x00\x80" # mov ax,0x80000006
  724. b"\x0f\xa2" # cpuid
  725. b"\x89\xC8" # mov ax,cx
  726. b"\xC3" # ret
  727. )
  728. cache_info = {
  729. 'size_kb' : ecx & 0xFF,
  730. 'line_size_b' : (ecx >> 12) & 0xF,
  731. 'associativity' : (ecx >> 16) & 0xFFFF
  732. }
  733. return cache_info
  734. def get_ticks(self):
  735. retval = None
  736. if DataSource.bits == '32bit':
  737. # Works on x86_32
  738. restype = None
  739. argtypes = (ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint))
  740. get_ticks_x86_32, address = self._asm_func(restype, argtypes,
  741. [
  742. b"\x55", # push bp
  743. b"\x89\xE5", # mov bp,sp
  744. b"\x31\xC0", # xor ax,ax
  745. b"\x0F\xA2", # cpuid
  746. b"\x0F\x31", # rdtsc
  747. b"\x8B\x5D\x08", # mov bx,[di+0x8]
  748. b"\x8B\x4D\x0C", # mov cx,[di+0xc]
  749. b"\x89\x13", # mov [bp+di],dx
  750. b"\x89\x01", # mov [bx+di],ax
  751. b"\x5D", # pop bp
  752. b"\xC3" # ret
  753. ]
  754. )
  755. high = ctypes.c_uint32(0)
  756. low = ctypes.c_uint32(0)
  757. get_ticks_x86_32(ctypes.byref(high), ctypes.byref(low))
  758. retval = ((high.value << 32) & 0xFFFFFFFF00000000) | low.value
  759. elif DataSource.bits == '64bit':
  760. # Works on x86_64
  761. restype = ctypes.c_uint64
  762. argtypes = ()
  763. get_ticks_x86_64, address = self._asm_func(restype, argtypes,
  764. [
  765. b"\x48", # dec ax
  766. b"\x31\xC0", # xor ax,ax
  767. b"\x0F\xA2", # cpuid
  768. b"\x0F\x31", # rdtsc
  769. b"\x48", # dec ax
  770. b"\xC1\xE2\x20", # shl dx,byte 0x20
  771. b"\x48", # dec ax
  772. b"\x09\xD0", # or ax,dx
  773. b"\xC3", # ret
  774. ]
  775. )
  776. retval = get_ticks_x86_64()
  777. return retval
  778. def get_raw_hz(self):
  779. start = self.get_ticks()
  780. time.sleep(1)
  781. end = self.get_ticks()
  782. ticks = (end - start)
  783. return ticks
  784. def get_cpu_info_from_cpuid():
  785. '''
  786. Returns the CPU info gathered by querying the X86 cpuid register in a new process.
  787. Returns None of non X86 cpus.
  788. Returns None if SELinux is in enforcing mode.
  789. '''
  790. returncode, output = run_and_get_stdout([sys.executable, "-c", "import cpuinfo; print(cpuinfo.actual_get_cpu_info_from_cpuid())"])
  791. if returncode != 0:
  792. return None
  793. info = b64_to_obj(output)
  794. return info
  795. def actual_get_cpu_info_from_cpuid():
  796. # Get the CPU arch and bits
  797. arch, bits = parse_arch(DataSource.raw_arch_string)
  798. # Return none if this is not an X86 CPU
  799. if not arch in ['X86_32', 'X86_64']:
  800. return None
  801. # Return none if SE Linux is in enforcing mode
  802. cpuid = CPUID()
  803. if cpuid.is_selinux_enforcing:
  804. return None
  805. # Get the cpu info from the CPUID register
  806. max_extension_support = cpuid.get_max_extension_support()
  807. cache_info = cpuid.get_cache(max_extension_support)
  808. info = cpuid.get_info()
  809. processor_brand = cpuid.get_processor_brand(max_extension_support)
  810. # Get the Hz and scale
  811. hz_actual = cpuid.get_raw_hz()
  812. hz_actual = to_hz_string(hz_actual)
  813. # Get the Hz and scale
  814. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  815. info = {
  816. 'vendor_id' : cpuid.get_vendor_id(),
  817. 'hardware' : '',
  818. 'brand' : processor_brand,
  819. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  820. 'hz_actual' : to_friendly_hz(hz_actual, 6),
  821. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  822. 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
  823. 'arch' : arch,
  824. 'bits' : bits,
  825. 'count' : DataSource.cpu_count,
  826. 'raw_arch_string' : DataSource.raw_arch_string,
  827. 'l2_cache_size' : cache_info['size_kb'],
  828. 'l2_cache_line_size' : cache_info['line_size_b'],
  829. 'l2_cache_associativity' : hex(cache_info['associativity']),
  830. 'stepping' : info['stepping'],
  831. 'model' : info['model'],
  832. 'family' : info['family'],
  833. 'processor_type' : info['processor_type'],
  834. 'extended_model' : info['extended_model'],
  835. 'extended_family' : info['extended_family'],
  836. 'flags' : cpuid.get_flags(max_extension_support)
  837. }
  838. return obj_to_b64(info)
  839. def get_cpu_info_from_proc_cpuinfo():
  840. '''
  841. Returns the CPU info gathered from /proc/cpuinfo. Will return None if
  842. /proc/cpuinfo is not found.
  843. '''
  844. try:
  845. # Just return None if there is no cpuinfo
  846. if not DataSource.has_proc_cpuinfo():
  847. return None
  848. returncode, output = DataSource.cat_proc_cpuinfo()
  849. if returncode != 0:
  850. return None
  851. # Various fields
  852. vendor_id = _get_field(False, output, None, '', 'vendor_id', 'vendor id', 'vendor')
  853. processor_brand = _get_field(True, output, None, None, 'model name','cpu', 'processor')
  854. cache_size = _get_field(False, output, None, '', 'cache size')
  855. stepping = _get_field(False, output, int, 0, 'stepping')
  856. model = _get_field(False, output, int, 0, 'model')
  857. family = _get_field(False, output, int, 0, 'cpu family')
  858. hardware = _get_field(False, output, None, '', 'Hardware')
  859. # Flags
  860. flags = _get_field(False, output, None, None, 'flags', 'Features').split()
  861. flags.sort()
  862. # Convert from MHz string to Hz
  863. hz_actual = _get_field(False, output, None, '', 'cpu MHz', 'cpu speed', 'clock')
  864. hz_actual = hz_actual.lower().rstrip('mhz').strip()
  865. hz_actual = to_hz_string(hz_actual)
  866. # Convert from GHz/MHz string to Hz
  867. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  868. # Try getting the Hz for a BeagleBone
  869. if hz_advertised == '0.0':
  870. scale, hz_advertised = _get_hz_string_from_beagle_bone()
  871. hz_actual = hz_advertised
  872. # Try getting the Hz for a lscpu
  873. if hz_advertised == '0.0':
  874. scale, hz_advertised = _get_hz_string_from_lscpu()
  875. hz_actual = hz_advertised
  876. # Get the CPU arch and bits
  877. arch, bits = parse_arch(DataSource.raw_arch_string)
  878. return {
  879. 'vendor_id' : vendor_id,
  880. 'hardware' : hardware,
  881. 'brand' : processor_brand,
  882. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  883. 'hz_actual' : to_friendly_hz(hz_actual, 6),
  884. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  885. 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
  886. 'arch' : arch,
  887. 'bits' : bits,
  888. 'count' : DataSource.cpu_count,
  889. 'raw_arch_string' : DataSource.raw_arch_string,
  890. 'l2_cache_size' : cache_size,
  891. 'l2_cache_line_size' : 0,
  892. 'l2_cache_associativity' : 0,
  893. 'stepping' : stepping,
  894. 'model' : model,
  895. 'family' : family,
  896. 'processor_type' : 0,
  897. 'extended_model' : 0,
  898. 'extended_family' : 0,
  899. 'flags' : flags
  900. }
  901. except:
  902. #raise # NOTE: To have this throw on error, uncomment this line
  903. return None
  904. def get_cpu_info_from_dmesg():
  905. '''
  906. Returns the CPU info gathered from dmesg. Will return None if
  907. dmesg is not found or does not have the desired info.
  908. '''
  909. try:
  910. # Just return None if there is no dmesg
  911. if not DataSource.has_dmesg():
  912. return None
  913. # If dmesg fails return None
  914. returncode, output = DataSource.dmesg_a()
  915. if output == None or returncode != 0:
  916. return None
  917. # Processor Brand
  918. long_brand = output.split('CPU: ')[1].split('\n')[0]
  919. processor_brand = long_brand.rsplit('(', 1)[0]
  920. processor_brand = processor_brand.strip()
  921. # Hz
  922. scale = 0
  923. hz_actual = long_brand.rsplit('(', 1)[1].split(' ')[0].lower()
  924. if hz_actual.endswith('mhz'):
  925. scale = 6
  926. elif hz_actual.endswith('ghz'):
  927. scale = 9
  928. hz_actual = hz_actual.split('-')[0]
  929. hz_actual = to_hz_string(hz_actual)
  930. # Various fields
  931. fields = output.split('CPU: ')[1].split('\n')[1].split('\n')[0].strip().split(' ')
  932. vendor_id = None
  933. stepping = None
  934. model = None
  935. family = None
  936. for field in fields:
  937. name, value = field.split('=')
  938. name = name.strip().lower()
  939. value = value.strip()
  940. if name == 'origin':
  941. vendor_id = value.strip('"')
  942. elif name == 'stepping':
  943. stepping = int(value)
  944. elif name == 'model':
  945. model = int(value, 16)
  946. elif name == 'family':
  947. family = int(value, 16)
  948. # Flags
  949. flag_lines = []
  950. for category in [' Features=', ' Features2=', ' AMD Features=', ' AMD Features2=']:
  951. if category in output:
  952. flag_lines.append(output.split(category)[1].split('\n')[0])
  953. flags = []
  954. for line in flag_lines:
  955. line = line.split('<')[1].split('>')[0].lower()
  956. for flag in line.split(','):
  957. flags.append(flag)
  958. flags.sort()
  959. # Convert from GHz/MHz string to Hz
  960. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  961. # Get the CPU arch and bits
  962. arch, bits = parse_arch(DataSource.raw_arch_string)
  963. return {
  964. 'vendor_id' : vendor_id,
  965. 'hardware' : '',
  966. 'brand' : processor_brand,
  967. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  968. 'hz_actual' : to_friendly_hz(hz_actual, 6),
  969. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  970. 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
  971. 'arch' : arch,
  972. 'bits' : bits,
  973. 'count' : DataSource.cpu_count,
  974. 'raw_arch_string' : DataSource.raw_arch_string,
  975. 'l2_cache_size' : 0,
  976. 'l2_cache_line_size' : 0,
  977. 'l2_cache_associativity' : 0,
  978. 'stepping' : stepping,
  979. 'model' : model,
  980. 'family' : family,
  981. 'processor_type' : 0,
  982. 'extended_model' : 0,
  983. 'extended_family' : 0,
  984. 'flags' : flags
  985. }
  986. except:
  987. return None
  988. def get_cpu_info_from_sysctl():
  989. '''
  990. Returns the CPU info gathered from sysctl. Will return None if
  991. sysctl is not found.
  992. '''
  993. try:
  994. # Just return None if there is no sysctl
  995. if not DataSource.has_sysctl():
  996. return None
  997. # If sysctl fails return None
  998. returncode, output = DataSource.sysctl_machdep_cpu_hw_cpufrequency()
  999. if output == None or returncode != 0:
  1000. return None
  1001. # Various fields
  1002. vendor_id = _get_field(False, output, None, None, 'machdep.cpu.vendor')
  1003. processor_brand = _get_field(True, output, None, None, 'machdep.cpu.brand_string')
  1004. cache_size = _get_field(False, output, None, None, 'machdep.cpu.cache.size')
  1005. stepping = _get_field(False, output, int, 0, 'machdep.cpu.stepping')
  1006. model = _get_field(False, output, int, 0, 'machdep.cpu.model')
  1007. family = _get_field(False, output, int, 0, 'machdep.cpu.family')
  1008. # Flags
  1009. flags = _get_field(False, output, None, None, 'machdep.cpu.features').lower().split()
  1010. flags.sort()
  1011. # Convert from GHz/MHz string to Hz
  1012. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1013. hz_actual = _get_field(False, output, None, None, 'hw.cpufrequency')
  1014. hz_actual = to_hz_string(hz_actual)
  1015. # Get the CPU arch and bits
  1016. arch, bits = parse_arch(DataSource.raw_arch_string)
  1017. return {
  1018. 'vendor_id' : vendor_id,
  1019. 'hardware' : '',
  1020. 'brand' : processor_brand,
  1021. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1022. 'hz_actual' : to_friendly_hz(hz_actual, 0),
  1023. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1024. 'hz_actual_raw' : to_raw_hz(hz_actual, 0),
  1025. 'arch' : arch,
  1026. 'bits' : bits,
  1027. 'count' : DataSource.cpu_count,
  1028. 'raw_arch_string' : DataSource.raw_arch_string,
  1029. 'l2_cache_size' : cache_size,
  1030. 'l2_cache_line_size' : 0,
  1031. 'l2_cache_associativity' : 0,
  1032. 'stepping' : stepping,
  1033. 'model' : model,
  1034. 'family' : family,
  1035. 'processor_type' : 0,
  1036. 'extended_model' : 0,
  1037. 'extended_family' : 0,
  1038. 'flags' : flags
  1039. }
  1040. except:
  1041. return None
  1042. def get_cpu_info_from_sysinfo():
  1043. '''
  1044. Returns the CPU info gathered from sysinfo. Will return None if
  1045. sysinfo is not found.
  1046. '''
  1047. try:
  1048. # Just return None if there is no sysinfo
  1049. if not DataSource.has_sysinfo():
  1050. return None
  1051. # If sysinfo fails return None
  1052. returncode, output = DataSource.sysinfo_cpu()
  1053. if output == None or returncode != 0:
  1054. return None
  1055. # Various fields
  1056. vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ')
  1057. processor_brand = output.split('CPU #0: "')[1].split('"\n')[0]
  1058. cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size')
  1059. stepping = int(output.split(', stepping ')[1].split(',')[0].strip())
  1060. model = int(output.split(', model ')[1].split(',')[0].strip())
  1061. family = int(output.split(', family ')[1].split(',')[0].strip())
  1062. # Flags
  1063. flags = []
  1064. for line in output.split('\n'):
  1065. if line.startswith('\t\t'):
  1066. for flag in line.strip().lower().split():
  1067. flags.append(flag)
  1068. flags.sort()
  1069. # Convert from GHz/MHz string to Hz
  1070. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1071. hz_actual = hz_advertised
  1072. # Get the CPU arch and bits
  1073. arch, bits = parse_arch(DataSource.raw_arch_string)
  1074. return {
  1075. 'vendor_id' : vendor_id,
  1076. 'hardware' : '',
  1077. 'brand' : processor_brand,
  1078. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1079. 'hz_actual' : to_friendly_hz(hz_actual, scale),
  1080. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1081. 'hz_actual_raw' : to_raw_hz(hz_actual, scale),
  1082. 'arch' : arch,
  1083. 'bits' : bits,
  1084. 'count' : DataSource.cpu_count,
  1085. 'raw_arch_string' : DataSource.raw_arch_string,
  1086. 'l2_cache_size' : cache_size,
  1087. 'l2_cache_line_size' : 0,
  1088. 'l2_cache_associativity' : 0,
  1089. 'stepping' : stepping,
  1090. 'model' : model,
  1091. 'family' : family,
  1092. 'processor_type' : 0,
  1093. 'extended_model' : 0,
  1094. 'extended_family' : 0,
  1095. 'flags' : flags
  1096. }
  1097. except:
  1098. return None
  1099. def get_cpu_info_from_registry():
  1100. '''
  1101. FIXME: Is missing many of the newer CPU flags like sse3
  1102. Returns the CPU info gathered from the Windows Registry. Will return None if
  1103. not on Windows.
  1104. '''
  1105. try:
  1106. # Just return None if not on Windows
  1107. if not DataSource.is_windows:
  1108. return None
  1109. # Get the CPU name
  1110. processor_brand = DataSource.winreg_processor_brand()
  1111. # Get the CPU vendor id
  1112. vendor_id = DataSource.winreg_vendor_id()
  1113. # Get the CPU arch and bits
  1114. raw_arch_string = DataSource.winreg_raw_arch_string()
  1115. arch, bits = parse_arch(raw_arch_string)
  1116. # Get the actual CPU Hz
  1117. hz_actual = DataSource.winreg_hz_actual()
  1118. hz_actual = to_hz_string(hz_actual)
  1119. # Get the advertised CPU Hz
  1120. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1121. # Get the CPU features
  1122. feature_bits = DataSource.winreg_feature_bits()
  1123. def is_set(bit):
  1124. mask = 0x80000000 >> bit
  1125. retval = mask & feature_bits > 0
  1126. return retval
  1127. # http://en.wikipedia.org/wiki/CPUID
  1128. # http://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean
  1129. # http://www.lohninger.com/helpcsuite/public_constants_cpuid.htm
  1130. flags = {
  1131. 'fpu' : is_set(0), # Floating Point Unit
  1132. 'vme' : is_set(1), # V86 Mode Extensions
  1133. 'de' : is_set(2), # Debug Extensions - I/O breakpoints supported
  1134. 'pse' : is_set(3), # Page Size Extensions (4 MB pages supported)
  1135. 'tsc' : is_set(4), # Time Stamp Counter and RDTSC instruction are available
  1136. 'msr' : is_set(5), # Model Specific Registers
  1137. 'pae' : is_set(6), # Physical Address Extensions (36 bit address, 2MB pages)
  1138. 'mce' : is_set(7), # Machine Check Exception supported
  1139. 'cx8' : is_set(8), # Compare Exchange Eight Byte instruction available
  1140. 'apic' : is_set(9), # Local APIC present (multiprocessor operation support)
  1141. 'sepamd' : is_set(10), # Fast system calls (AMD only)
  1142. 'sep' : is_set(11), # Fast system calls
  1143. 'mtrr' : is_set(12), # Memory Type Range Registers
  1144. 'pge' : is_set(13), # Page Global Enable
  1145. 'mca' : is_set(14), # Machine Check Architecture
  1146. 'cmov' : is_set(15), # Conditional MOVe instructions
  1147. 'pat' : is_set(16), # Page Attribute Table
  1148. 'pse36' : is_set(17), # 36 bit Page Size Extensions
  1149. 'serial' : is_set(18), # Processor Serial Number
  1150. 'clflush' : is_set(19), # Cache Flush
  1151. #'reserved1' : is_set(20), # reserved
  1152. 'dts' : is_set(21), # Debug Trace Store
  1153. 'acpi' : is_set(22), # ACPI support
  1154. 'mmx' : is_set(23), # MultiMedia Extensions
  1155. 'fxsr' : is_set(24), # FXSAVE and FXRSTOR instructions
  1156. 'sse' : is_set(25), # SSE instructions
  1157. 'sse2' : is_set(26), # SSE2 (WNI) instructions
  1158. 'ss' : is_set(27), # self snoop
  1159. #'reserved2' : is_set(28), # reserved
  1160. 'tm' : is_set(29), # Automatic clock control
  1161. 'ia64' : is_set(30), # IA64 instructions
  1162. '3dnow' : is_set(31) # 3DNow! instructions available
  1163. }
  1164. # Get a list of only the flags that are true
  1165. flags = [k for k, v in flags.items() if v]
  1166. flags.sort()
  1167. return {
  1168. 'vendor_id' : vendor_id,
  1169. 'hardware' : '',
  1170. 'brand' : processor_brand,
  1171. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1172. 'hz_actual' : to_friendly_hz(hz_actual, 6),
  1173. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1174. 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
  1175. 'arch' : arch,
  1176. 'bits' : bits,
  1177. 'count' : DataSource.cpu_count,
  1178. 'raw_arch_string' : raw_arch_string,
  1179. 'l2_cache_size' : 0,
  1180. 'l2_cache_line_size' : 0,
  1181. 'l2_cache_associativity' : 0,
  1182. 'stepping' : 0,
  1183. 'model' : 0,
  1184. 'family' : 0,
  1185. 'processor_type' : 0,
  1186. 'extended_model' : 0,
  1187. 'extended_family' : 0,
  1188. 'flags' : flags
  1189. }
  1190. except:
  1191. return None
  1192. def get_cpu_info_from_kstat():
  1193. '''
  1194. Returns the CPU info gathered from isainfo and kstat. Will
  1195. return None if isainfo or kstat are not found.
  1196. '''
  1197. try:
  1198. # Just return None if there is no isainfo or kstat
  1199. if not DataSource.has_isainfo() or not DataSource.has_kstat():
  1200. return None
  1201. # If isainfo fails return None
  1202. returncode, flag_output = DataSource.isainfo_vb()
  1203. if flag_output == None or returncode != 0:
  1204. return None
  1205. # If kstat fails return None
  1206. returncode, kstat = DataSource.kstat_m_cpu_info()
  1207. if kstat == None or returncode != 0:
  1208. return None
  1209. # Various fields
  1210. vendor_id = kstat.split('\tvendor_id ')[1].split('\n')[0].strip()
  1211. processor_brand = kstat.split('\tbrand ')[1].split('\n')[0].strip()
  1212. cache_size = 0
  1213. stepping = int(kstat.split('\tstepping ')[1].split('\n')[0].strip())
  1214. model = int(kstat.split('\tmodel ')[1].split('\n')[0].strip())
  1215. family = int(kstat.split('\tfamily ')[1].split('\n')[0].strip())
  1216. # Flags
  1217. flags = flag_output.strip().split('\n')[-1].strip().lower().split()
  1218. flags.sort()
  1219. # Convert from GHz/MHz string to Hz
  1220. scale = 6
  1221. hz_advertised = kstat.split('\tclock_MHz ')[1].split('\n')[0].strip()
  1222. hz_advertised = to_hz_string(hz_advertised)
  1223. # Convert from GHz/MHz string to Hz
  1224. hz_actual = kstat.split('\tcurrent_clock_Hz ')[1].split('\n')[0].strip()
  1225. hz_actual = to_hz_string(hz_actual)
  1226. # Get the CPU arch and bits
  1227. arch, bits = parse_arch(DataSource.raw_arch_string)
  1228. return {
  1229. 'vendor_id' : vendor_id,
  1230. 'hardware' : '',
  1231. 'brand' : processor_brand,
  1232. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1233. 'hz_actual' : to_friendly_hz(hz_actual, 0),
  1234. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1235. 'hz_actual_raw' : to_raw_hz(hz_actual, 0),
  1236. 'arch' : arch,
  1237. 'bits' : bits,
  1238. 'count' : DataSource.cpu_count,
  1239. 'raw_arch_string' : DataSource.raw_arch_string,
  1240. 'l2_cache_size' : cache_size,
  1241. 'l2_cache_line_size' : 0,
  1242. 'l2_cache_associativity' : 0,
  1243. 'stepping' : stepping,
  1244. 'model' : model,
  1245. 'family' : family,
  1246. 'processor_type' : 0,
  1247. 'extended_model' : 0,
  1248. 'extended_family' : 0,
  1249. 'flags' : flags
  1250. }
  1251. except:
  1252. return None
  1253. def get_cpu_info():
  1254. info = None
  1255. # Try the Windows registry
  1256. if not info:
  1257. info = get_cpu_info_from_registry()
  1258. # Try /proc/cpuinfo
  1259. if not info:
  1260. info = get_cpu_info_from_proc_cpuinfo()
  1261. # Try sysctl
  1262. if not info:
  1263. info = get_cpu_info_from_sysctl()
  1264. # Try kstat
  1265. if not info:
  1266. info = get_cpu_info_from_kstat()
  1267. # Try dmesg
  1268. if not info:
  1269. info = get_cpu_info_from_dmesg()
  1270. # Try sysinfo
  1271. if not info:
  1272. info = get_cpu_info_from_sysinfo()
  1273. # Try querying the CPU cpuid register
  1274. if not info:
  1275. info = get_cpu_info_from_cpuid()
  1276. return info
  1277. # Make sure we are running on a supported system
  1278. def _check_arch():
  1279. arch, bits = parse_arch(DataSource.raw_arch_string)
  1280. if not arch in ['X86_32', 'X86_64', 'ARM_7', 'ARM_8']:
  1281. raise Exception("py-cpuinfo currently only works on X86 and some ARM CPUs.")
  1282. def main():
  1283. try:
  1284. _check_arch()
  1285. except Exception as err:
  1286. sys.stderr.write(str(err) + "\n")
  1287. sys.exit(1)
  1288. info = get_cpu_info()
  1289. if info:
  1290. print('Vendor ID: {0}'.format(info.get('vendor_id', '')))
  1291. print('Hardware Raw: {0}'.format(info.get('hardware', '')))
  1292. print('Brand: {0}'.format(info.get('brand', '')))
  1293. print('Hz Advertised: {0}'.format(info.get('hz_advertised', '')))
  1294. print('Hz Actual: {0}'.format(info.get('hz_actual', '')))
  1295. print('Hz Advertised Raw: {0}'.format(info.get('hz_advertised_raw', '')))
  1296. print('Hz Actual Raw: {0}'.format(info.get('hz_actual_raw', '')))
  1297. print('Arch: {0}'.format(info.get('arch', '')))
  1298. print('Bits: {0}'.format(info.get('bits', '')))
  1299. print('Count: {0}'.format(info.get('count', '')))
  1300. print('Raw Arch String: {0}'.format(info.get('raw_arch_string', '')))
  1301. print('L2 Cache Size: {0}'.format(info.get('l2_cache_size', '')))
  1302. print('L2 Cache Line Size: {0}'.format(info.get('l2_cache_line_size', '')))
  1303. print('L2 Cache Associativity: {0}'.format(info.get('l2_cache_associativity', '')))
  1304. print('Stepping: {0}'.format(info.get('stepping', '')))
  1305. print('Model: {0}'.format(info.get('model', '')))
  1306. print('Family: {0}'.format(info.get('family', '')))
  1307. print('Processor Type: {0}'.format(info.get('processor_type', '')))
  1308. print('Extended Model: {0}'.format(info.get('extended_model', '')))
  1309. print('Extended Family: {0}'.format(info.get('extended_family', '')))
  1310. print('Flags: {0}'.format(', '.join(info.get('flags', ''))))
  1311. else:
  1312. sys.stderr.write("Failed to find cpu info\n")
  1313. sys.exit(1)
  1314. if __name__ == '__main__':
  1315. main()
  1316. else:
  1317. _check_arch()