cpuinfo.py 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210
  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3. # Copyright (c) 2014-2018, Matthew Brennan Jones <matthew.brennan.jones@gmail.com>
  4. # Py-cpuinfo gets CPU info with pure Python 2 & 3
  5. # It uses the MIT 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. CPUINFO_VERSION = (4, 0, 0)
  27. import os, sys
  28. import glob
  29. import re
  30. import time
  31. import platform
  32. import multiprocessing
  33. import ctypes
  34. import pickle
  35. import base64
  36. import subprocess
  37. try:
  38. import _winreg as winreg
  39. except ImportError as err:
  40. try:
  41. import winreg
  42. except ImportError as err:
  43. pass
  44. PY2 = sys.version_info[0] == 2
  45. # Load hacks for Windows
  46. if platform.system().lower() == 'windows':
  47. # Monkey patch multiprocessing's Popen to fork properly on Windows Pyinstaller
  48. # https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing
  49. try:
  50. import multiprocessing.popen_spawn_win32 as forking
  51. except ImportError as err:
  52. try:
  53. import multiprocessing.popen_fork as forking
  54. except ImportError as err:
  55. import multiprocessing.forking as forking
  56. class _Popen(forking.Popen):
  57. def __init__(self, *args, **kw):
  58. if hasattr(sys, 'frozen'):
  59. # We have to set original _MEIPASS2 value from sys._MEIPASS
  60. # to get --onefile mode working.
  61. os.putenv('_MEIPASS2', sys._MEIPASS)
  62. try:
  63. super(_Popen, self).__init__(*args, **kw)
  64. finally:
  65. if hasattr(sys, 'frozen'):
  66. # On some platforms (e.g. AIX) 'os.unsetenv()' is not
  67. # available. In those cases we cannot delete the variable
  68. # but only set it to the empty string. The bootloader
  69. # can handle this case.
  70. if hasattr(os, 'unsetenv'):
  71. os.unsetenv('_MEIPASS2')
  72. else:
  73. os.putenv('_MEIPASS2', '')
  74. forking.Popen = _Popen
  75. class DataSource(object):
  76. bits = platform.architecture()[0]
  77. cpu_count = multiprocessing.cpu_count()
  78. is_windows = platform.system().lower() == 'windows'
  79. raw_arch_string = platform.machine()
  80. can_cpuid = True
  81. @staticmethod
  82. def has_proc_cpuinfo():
  83. return os.path.exists('/proc/cpuinfo')
  84. @staticmethod
  85. def has_dmesg():
  86. return len(program_paths('dmesg')) > 0
  87. @staticmethod
  88. def has_var_run_dmesg_boot():
  89. uname = platform.system().strip().strip('"').strip("'").strip().lower()
  90. return 'linux' in uname and os.path.exists('/var/run/dmesg.boot')
  91. @staticmethod
  92. def has_cpufreq_info():
  93. return len(program_paths('cpufreq-info')) > 0
  94. @staticmethod
  95. def has_sestatus():
  96. return len(program_paths('sestatus')) > 0
  97. @staticmethod
  98. def has_sysctl():
  99. return len(program_paths('sysctl')) > 0
  100. @staticmethod
  101. def has_isainfo():
  102. return len(program_paths('isainfo')) > 0
  103. @staticmethod
  104. def has_kstat():
  105. return len(program_paths('kstat')) > 0
  106. @staticmethod
  107. def has_sysinfo():
  108. return len(program_paths('sysinfo')) > 0
  109. @staticmethod
  110. def has_lscpu():
  111. return len(program_paths('lscpu')) > 0
  112. @staticmethod
  113. def has_ibm_pa_features():
  114. return len(program_paths('lsprop')) > 0
  115. @staticmethod
  116. def has_wmic():
  117. returncode, output = run_and_get_stdout(['wmic', 'os', 'get', 'Version'])
  118. return returncode == 0 and len(output) > 0
  119. @staticmethod
  120. def cat_proc_cpuinfo():
  121. return run_and_get_stdout(['cat', '/proc/cpuinfo'])
  122. @staticmethod
  123. def cpufreq_info():
  124. return run_and_get_stdout(['cpufreq-info'])
  125. @staticmethod
  126. def sestatus_allow_execheap():
  127. return run_and_get_stdout(['sestatus', '-b'], ['grep', '-i', '"allow_execheap"'])[1].strip().lower().endswith('on')
  128. @staticmethod
  129. def sestatus_allow_execmem():
  130. return run_and_get_stdout(['sestatus', '-b'], ['grep', '-i', '"allow_execmem"'])[1].strip().lower().endswith('on')
  131. @staticmethod
  132. def dmesg_a():
  133. return run_and_get_stdout(['dmesg', '-a'])
  134. @staticmethod
  135. def cat_var_run_dmesg_boot():
  136. return run_and_get_stdout(['cat', '/var/run/dmesg.boot'])
  137. @staticmethod
  138. def sysctl_machdep_cpu_hw_cpufrequency():
  139. return run_and_get_stdout(['sysctl', 'machdep.cpu', 'hw.cpufrequency'])
  140. @staticmethod
  141. def isainfo_vb():
  142. return run_and_get_stdout(['isainfo', '-vb'])
  143. @staticmethod
  144. def kstat_m_cpu_info():
  145. return run_and_get_stdout(['kstat', '-m', 'cpu_info'])
  146. @staticmethod
  147. def sysinfo_cpu():
  148. return run_and_get_stdout(['sysinfo', '-cpu'])
  149. @staticmethod
  150. def lscpu():
  151. return run_and_get_stdout(['lscpu'])
  152. @staticmethod
  153. def ibm_pa_features():
  154. ibm_features = glob.glob('/proc/device-tree/cpus/*/ibm,pa-features')
  155. if ibm_features:
  156. return run_and_get_stdout(['lsprop', ibm_features[0]])
  157. @staticmethod
  158. def wmic_cpu():
  159. return run_and_get_stdout(['wmic', 'cpu', 'get', 'Name,CurrentClockSpeed,L2CacheSize,L3CacheSize,Description,Caption,Manufacturer', '/format:list'])
  160. @staticmethod
  161. def winreg_processor_brand():
  162. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  163. processor_brand = winreg.QueryValueEx(key, "ProcessorNameString")[0]
  164. winreg.CloseKey(key)
  165. return processor_brand
  166. @staticmethod
  167. def winreg_vendor_id():
  168. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  169. vendor_id = winreg.QueryValueEx(key, "VendorIdentifier")[0]
  170. winreg.CloseKey(key)
  171. return vendor_id
  172. @staticmethod
  173. def winreg_raw_arch_string():
  174. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")
  175. raw_arch_string = winreg.QueryValueEx(key, "PROCESSOR_ARCHITECTURE")[0]
  176. winreg.CloseKey(key)
  177. return raw_arch_string
  178. @staticmethod
  179. def winreg_hz_actual():
  180. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  181. hz_actual = winreg.QueryValueEx(key, "~Mhz")[0]
  182. winreg.CloseKey(key)
  183. hz_actual = to_hz_string(hz_actual)
  184. return hz_actual
  185. @staticmethod
  186. def winreg_feature_bits():
  187. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0")
  188. feature_bits = winreg.QueryValueEx(key, "FeatureSet")[0]
  189. winreg.CloseKey(key)
  190. return feature_bits
  191. def obj_to_b64(thing):
  192. a = thing
  193. b = pickle.dumps(a)
  194. c = base64.b64encode(b)
  195. d = c.decode('utf8')
  196. return d
  197. def b64_to_obj(thing):
  198. try:
  199. a = base64.b64decode(thing)
  200. b = pickle.loads(a)
  201. return b
  202. except:
  203. return {}
  204. def run_and_get_stdout(command, pipe_command=None):
  205. if not pipe_command:
  206. p1 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
  207. output = p1.communicate()[0]
  208. if not PY2:
  209. output = output.decode(encoding='UTF-8')
  210. return p1.returncode, output
  211. else:
  212. p1 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
  213. p2 = subprocess.Popen(pipe_command, stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  214. p1.stdout.close()
  215. output = p2.communicate()[0]
  216. if not PY2:
  217. output = output.decode(encoding='UTF-8')
  218. return p2.returncode, output
  219. def program_paths(program_name):
  220. paths = []
  221. exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
  222. path = os.environ['PATH']
  223. for p in os.environ['PATH'].split(os.pathsep):
  224. p = os.path.join(p, program_name)
  225. if os.access(p, os.X_OK):
  226. paths.append(p)
  227. for e in exts:
  228. pext = p + e
  229. if os.access(pext, os.X_OK):
  230. paths.append(pext)
  231. return paths
  232. def _get_field_actual(cant_be_number, raw_string, field_names):
  233. for line in raw_string.splitlines():
  234. for field_name in field_names:
  235. field_name = field_name.lower()
  236. if ':' in line:
  237. left, right = line.split(':', 1)
  238. left = left.strip().lower()
  239. right = right.strip()
  240. if left == field_name and len(right) > 0:
  241. if cant_be_number:
  242. if not right.isdigit():
  243. return right
  244. else:
  245. return right
  246. return None
  247. def _get_field(cant_be_number, raw_string, convert_to, default_value, *field_names):
  248. retval = _get_field_actual(cant_be_number, raw_string, field_names)
  249. # Convert the return value
  250. if retval and convert_to:
  251. try:
  252. retval = convert_to(retval)
  253. except:
  254. retval = default_value
  255. # Return the default if there is no return value
  256. if retval is None:
  257. retval = default_value
  258. return retval
  259. def _get_hz_string_from_brand(processor_brand):
  260. # Just return 0 if the processor brand does not have the Hz
  261. if not 'hz' in processor_brand.lower():
  262. return (1, '0.0')
  263. hz_brand = processor_brand.lower()
  264. scale = 1
  265. if hz_brand.endswith('mhz'):
  266. scale = 6
  267. elif hz_brand.endswith('ghz'):
  268. scale = 9
  269. if '@' in hz_brand:
  270. hz_brand = hz_brand.split('@')[1]
  271. else:
  272. hz_brand = hz_brand.rsplit(None, 1)[1]
  273. hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip()
  274. hz_brand = to_hz_string(hz_brand)
  275. return (scale, hz_brand)
  276. def to_friendly_hz(ticks, scale):
  277. # Get the raw Hz as a string
  278. left, right = to_raw_hz(ticks, scale)
  279. ticks = '{0}.{1}'.format(left, right)
  280. # Get the location of the dot, and remove said dot
  281. dot_index = ticks.index('.')
  282. ticks = ticks.replace('.', '')
  283. # Get the Hz symbol and scale
  284. symbol = "Hz"
  285. scale = 0
  286. if dot_index > 9:
  287. symbol = "GHz"
  288. scale = 9
  289. elif dot_index > 6:
  290. symbol = "MHz"
  291. scale = 6
  292. elif dot_index > 3:
  293. symbol = "KHz"
  294. scale = 3
  295. # Get the Hz with the dot at the new scaled point
  296. ticks = '{0}.{1}'.format(ticks[:-scale-1], ticks[-scale-1:])
  297. # Format the ticks to have 4 numbers after the decimal
  298. # and remove any superfluous zeroes.
  299. ticks = '{0:.4f} {1}'.format(float(ticks), symbol)
  300. ticks = ticks.rstrip('0')
  301. return ticks
  302. def to_raw_hz(ticks, scale):
  303. # Scale the numbers
  304. ticks = ticks.lstrip('0')
  305. old_index = ticks.index('.')
  306. ticks = ticks.replace('.', '')
  307. ticks = ticks.ljust(scale + old_index+1, '0')
  308. new_index = old_index + scale
  309. ticks = '{0}.{1}'.format(ticks[:new_index], ticks[new_index:])
  310. left, right = ticks.split('.')
  311. left, right = int(left), int(right)
  312. return (left, right)
  313. def to_hz_string(ticks):
  314. # Convert to string
  315. ticks = '{0}'.format(ticks)
  316. # Add decimal if missing
  317. if '.' not in ticks:
  318. ticks = '{0}.0'.format(ticks)
  319. # Remove trailing zeros
  320. ticks = ticks.rstrip('0')
  321. # Add one trailing zero for empty right side
  322. if ticks.endswith('.'):
  323. ticks = '{0}0'.format(ticks)
  324. return ticks
  325. def to_friendly_bytes(input):
  326. if not input:
  327. return input
  328. input = "{0}".format(input)
  329. formats = {
  330. r"^[0-9]+B$" : 'B',
  331. r"^[0-9]+K$" : 'KB',
  332. r"^[0-9]+M$" : 'MB',
  333. r"^[0-9]+G$" : 'GB'
  334. }
  335. for pattern, friendly_size in formats.items():
  336. if re.match(pattern, input):
  337. return "{0} {1}".format(input[ : -1].strip(), friendly_size)
  338. return input
  339. def _parse_cpu_string(cpu_string):
  340. # Get location of fields at end of string
  341. fields_index = cpu_string.find('(', cpu_string.find('@'))
  342. #print(fields_index)
  343. # Processor Brand
  344. processor_brand = cpu_string
  345. if fields_index != -1:
  346. processor_brand = cpu_string[0 : fields_index].strip()
  347. #print('processor_brand: ', processor_brand)
  348. fields = None
  349. if fields_index != -1:
  350. fields = cpu_string[fields_index : ]
  351. #print('fields: ', fields)
  352. # Hz
  353. scale, hz_brand = _get_hz_string_from_brand(processor_brand)
  354. # Various fields
  355. vendor_id, stepping, model, family = (None, None, None, None)
  356. if fields:
  357. try:
  358. fields = fields.rsplit('(', 1)[1].split(')')[0].split(',')
  359. fields = [f.strip().lower() for f in fields]
  360. fields = [f.split(':') for f in fields]
  361. fields = [{f[0].strip() : f[1].strip()} for f in fields]
  362. #print('fields: ', fields)
  363. for field in fields:
  364. name = list(field.keys())[0]
  365. value = list(field.values())[0]
  366. #print('name:{0}, value:{1}'.format(name, value))
  367. if name == 'origin':
  368. vendor_id = value.strip('"')
  369. elif name == 'stepping':
  370. stepping = int(value.lstrip('0x'), 16)
  371. elif name == 'model':
  372. model = int(value.lstrip('0x'), 16)
  373. elif name in ['fam', 'family']:
  374. family = int(value.lstrip('0x'), 16)
  375. except:
  376. #raise
  377. pass
  378. return (processor_brand, hz_brand, scale, vendor_id, stepping, model, family)
  379. def _parse_dmesg_output(output):
  380. try:
  381. # Get all the dmesg lines that might contain a CPU string
  382. lines = output.split(' CPU0:')[1:] + \
  383. output.split(' CPU1:')[1:] + \
  384. output.split(' CPU:')[1:] + \
  385. output.split('\nCPU0:')[1:] + \
  386. output.split('\nCPU1:')[1:] + \
  387. output.split('\nCPU:')[1:]
  388. lines = [l.split('\n')[0].strip() for l in lines]
  389. # Convert the lines to CPU strings
  390. cpu_strings = [_parse_cpu_string(l) for l in lines]
  391. # Find the CPU string that has the most fields
  392. best_string = None
  393. highest_count = 0
  394. for cpu_string in cpu_strings:
  395. count = sum([n is not None for n in cpu_string])
  396. if count > highest_count:
  397. highest_count = count
  398. best_string = cpu_string
  399. # If no CPU string was found, return {}
  400. if not best_string:
  401. return {}
  402. processor_brand, hz_actual, scale, vendor_id, stepping, model, family = best_string
  403. # Origin
  404. if ' Origin=' in output:
  405. fields = output[output.find(' Origin=') : ].split('\n')[0]
  406. fields = fields.strip().split()
  407. fields = [n.strip().split('=') for n in fields]
  408. fields = [{n[0].strip().lower() : n[1].strip()} for n in fields]
  409. #print('fields: ', fields)
  410. for field in fields:
  411. name = list(field.keys())[0]
  412. value = list(field.values())[0]
  413. #print('name:{0}, value:{1}'.format(name, value))
  414. if name == 'origin':
  415. vendor_id = value.strip('"')
  416. elif name == 'stepping':
  417. stepping = int(value.lstrip('0x'), 16)
  418. elif name == 'model':
  419. model = int(value.lstrip('0x'), 16)
  420. elif name in ['fam', 'family']:
  421. family = int(value.lstrip('0x'), 16)
  422. #print('FIELDS: ', (vendor_id, stepping, model, family))
  423. # Features
  424. flag_lines = []
  425. for category in [' Features=', ' Features2=', ' AMD Features=', ' AMD Features2=']:
  426. if category in output:
  427. flag_lines.append(output.split(category)[1].split('\n')[0])
  428. flags = []
  429. for line in flag_lines:
  430. line = line.split('<')[1].split('>')[0].lower()
  431. for flag in line.split(','):
  432. flags.append(flag)
  433. flags.sort()
  434. # Convert from GHz/MHz string to Hz
  435. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  436. info = {
  437. 'vendor_id' : vendor_id,
  438. 'brand' : processor_brand,
  439. 'stepping' : stepping,
  440. 'model' : model,
  441. 'family' : family,
  442. 'flags' : flags
  443. }
  444. if hz_advertised and hz_advertised != '0.0':
  445. info['hz_advertised'] = to_friendly_hz(hz_advertised, scale)
  446. info['hz_actual'] = to_friendly_hz(hz_actual, scale)
  447. if hz_advertised and hz_advertised != '0.0':
  448. info['hz_advertised_raw'] = to_raw_hz(hz_advertised, scale)
  449. info['hz_actual_raw'] = to_raw_hz(hz_actual, scale)
  450. return {k: v for k, v in info.items() if v}
  451. except:
  452. #raise
  453. pass
  454. return {}
  455. def parse_arch(raw_arch_string):
  456. arch, bits = None, None
  457. raw_arch_string = raw_arch_string.lower()
  458. # X86
  459. if re.match('^i\d86$|^x86$|^x86_32$|^i86pc$|^ia32$|^ia-32$|^bepc$', raw_arch_string):
  460. arch = 'X86_32'
  461. bits = 32
  462. elif re.match('^x64$|^x86_64$|^x86_64t$|^i686-64$|^amd64$|^ia64$|^ia-64$', raw_arch_string):
  463. arch = 'X86_64'
  464. bits = 64
  465. # ARM
  466. elif re.match('^armv8-a|aarch64$', raw_arch_string):
  467. arch = 'ARM_8'
  468. bits = 64
  469. elif re.match('^armv7$|^armv7[a-z]$|^armv7-[a-z]$|^armv6[a-z]$', raw_arch_string):
  470. arch = 'ARM_7'
  471. bits = 32
  472. elif re.match('^armv8$|^armv8[a-z]$|^armv8-[a-z]$', raw_arch_string):
  473. arch = 'ARM_8'
  474. bits = 32
  475. # PPC
  476. elif re.match('^ppc32$|^prep$|^pmac$|^powermac$', raw_arch_string):
  477. arch = 'PPC_32'
  478. bits = 32
  479. elif re.match('^powerpc$|^ppc64$|^ppc64le$', raw_arch_string):
  480. arch = 'PPC_64'
  481. bits = 64
  482. # SPARC
  483. elif re.match('^sparc32$|^sparc$', raw_arch_string):
  484. arch = 'SPARC_32'
  485. bits = 32
  486. elif re.match('^sparc64$|^sun4u$|^sun4v$', raw_arch_string):
  487. arch = 'SPARC_64'
  488. bits = 64
  489. return (arch, bits)
  490. def is_bit_set(reg, bit):
  491. mask = 1 << bit
  492. is_set = reg & mask > 0
  493. return is_set
  494. class CPUID(object):
  495. def __init__(self):
  496. self.prochandle = None
  497. # Figure out if SE Linux is on and in enforcing mode
  498. self.is_selinux_enforcing = False
  499. # Just return if the SE Linux Status Tool is not installed
  500. if not DataSource.has_sestatus():
  501. return
  502. # Figure out if we can execute heap and execute memory
  503. can_selinux_exec_heap = DataSource.sestatus_allow_execheap()
  504. can_selinux_exec_memory = DataSource.sestatus_allow_execmem()
  505. self.is_selinux_enforcing = (not can_selinux_exec_heap or not can_selinux_exec_memory)
  506. def _asm_func(self, restype=None, argtypes=(), byte_code=[]):
  507. byte_code = bytes.join(b'', byte_code)
  508. address = None
  509. if DataSource.is_windows:
  510. # Allocate a memory segment the size of the byte code, and make it executable
  511. size = len(byte_code)
  512. # Alloc at least 1 page to ensure we own all pages that we want to change protection on
  513. if size < 0x1000: size = 0x1000
  514. MEM_COMMIT = ctypes.c_ulong(0x1000)
  515. PAGE_READWRITE = ctypes.c_ulong(0x4)
  516. pfnVirtualAlloc = ctypes.windll.kernel32.VirtualAlloc
  517. pfnVirtualAlloc.restype = ctypes.c_void_p
  518. address = pfnVirtualAlloc(None, ctypes.c_size_t(size), MEM_COMMIT, PAGE_READWRITE)
  519. if not address:
  520. raise Exception("Failed to VirtualAlloc")
  521. # Copy the byte code into the memory segment
  522. memmove = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)(ctypes._memmove_addr)
  523. if memmove(address, byte_code, size) < 0:
  524. raise Exception("Failed to memmove")
  525. # Enable execute permissions
  526. PAGE_EXECUTE = ctypes.c_ulong(0x10)
  527. old_protect = ctypes.c_ulong(0)
  528. pfnVirtualProtect = ctypes.windll.kernel32.VirtualProtect
  529. res = pfnVirtualProtect(ctypes.c_void_p(address), ctypes.c_size_t(size), PAGE_EXECUTE, ctypes.byref(old_protect))
  530. if not res:
  531. raise Exception("Failed VirtualProtect")
  532. # Flush Instruction Cache
  533. # First, get process Handle
  534. if not self.prochandle:
  535. pfnGetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
  536. pfnGetCurrentProcess.restype = ctypes.c_void_p
  537. self.prochandle = ctypes.c_void_p(pfnGetCurrentProcess())
  538. # Actually flush cache
  539. res = ctypes.windll.kernel32.FlushInstructionCache(self.prochandle, ctypes.c_void_p(address), ctypes.c_size_t(size))
  540. if not res:
  541. raise Exception("Failed FlushInstructionCache")
  542. else:
  543. # Allocate a memory segment the size of the byte code
  544. size = len(byte_code)
  545. pfnvalloc = ctypes.pythonapi.valloc
  546. pfnvalloc.restype = ctypes.c_void_p
  547. address = pfnvalloc(ctypes.c_size_t(size))
  548. if not address:
  549. raise Exception("Failed to valloc")
  550. # Mark the memory segment as writeable only
  551. if not self.is_selinux_enforcing:
  552. WRITE = 0x2
  553. if ctypes.pythonapi.mprotect(ctypes.c_void_p(address), size, WRITE) < 0:
  554. raise Exception("Failed to mprotect")
  555. # Copy the byte code into the memory segment
  556. if ctypes.pythonapi.memmove(ctypes.c_void_p(address), byte_code, ctypes.c_size_t(size)) < 0:
  557. raise Exception("Failed to memmove")
  558. # Mark the memory segment as writeable and executable only
  559. if not self.is_selinux_enforcing:
  560. WRITE_EXECUTE = 0x2 | 0x4
  561. if ctypes.pythonapi.mprotect(ctypes.c_void_p(address), size, WRITE_EXECUTE) < 0:
  562. raise Exception("Failed to mprotect")
  563. # Cast the memory segment into a function
  564. functype = ctypes.CFUNCTYPE(restype, *argtypes)
  565. fun = functype(address)
  566. return fun, address
  567. def _run_asm(self, *byte_code):
  568. # Convert the byte code into a function that returns an int
  569. restype = ctypes.c_uint32
  570. argtypes = ()
  571. func, address = self._asm_func(restype, argtypes, byte_code)
  572. # Call the byte code like a function
  573. retval = func()
  574. byte_code = bytes.join(b'', byte_code)
  575. size = ctypes.c_size_t(len(byte_code))
  576. # Free the function memory segment
  577. if DataSource.is_windows:
  578. MEM_RELEASE = ctypes.c_ulong(0x8000)
  579. ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(address), ctypes.c_size_t(0), MEM_RELEASE)
  580. else:
  581. # Remove the executable tag on the memory
  582. READ_WRITE = 0x1 | 0x2
  583. if ctypes.pythonapi.mprotect(ctypes.c_void_p(address), size, READ_WRITE) < 0:
  584. raise Exception("Failed to mprotect")
  585. ctypes.pythonapi.free(ctypes.c_void_p(address))
  586. return retval
  587. # FIXME: We should not have to use different instructions to
  588. # set eax to 0 or 1, on 32bit and 64bit machines.
  589. def _zero_eax(self):
  590. return (
  591. b"\x31\xC0" # xor eax,eax
  592. )
  593. def _zero_ecx(self):
  594. return (
  595. b"\x31\xC9" # xor ecx,ecx
  596. )
  597. def _one_eax(self):
  598. return (
  599. b"\xB8\x01\x00\x00\x00" # mov eax,0x1"
  600. )
  601. # http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
  602. def get_vendor_id(self):
  603. # EBX
  604. ebx = self._run_asm(
  605. self._zero_eax(),
  606. b"\x0F\xA2" # cpuid
  607. b"\x89\xD8" # mov ax,bx
  608. b"\xC3" # ret
  609. )
  610. # ECX
  611. ecx = self._run_asm(
  612. self._zero_eax(),
  613. b"\x0f\xa2" # cpuid
  614. b"\x89\xC8" # mov ax,cx
  615. b"\xC3" # ret
  616. )
  617. # EDX
  618. edx = self._run_asm(
  619. self._zero_eax(),
  620. b"\x0f\xa2" # cpuid
  621. b"\x89\xD0" # mov ax,dx
  622. b"\xC3" # ret
  623. )
  624. # Each 4bits is a ascii letter in the name
  625. vendor_id = []
  626. for reg in [ebx, edx, ecx]:
  627. for n in [0, 8, 16, 24]:
  628. vendor_id.append(chr((reg >> n) & 0xFF))
  629. vendor_id = ''.join(vendor_id)
  630. return vendor_id
  631. # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
  632. def get_info(self):
  633. # EAX
  634. eax = self._run_asm(
  635. self._one_eax(),
  636. b"\x0f\xa2" # cpuid
  637. b"\xC3" # ret
  638. )
  639. # Get the CPU info
  640. stepping = (eax >> 0) & 0xF # 4 bits
  641. model = (eax >> 4) & 0xF # 4 bits
  642. family = (eax >> 8) & 0xF # 4 bits
  643. processor_type = (eax >> 12) & 0x3 # 2 bits
  644. extended_model = (eax >> 16) & 0xF # 4 bits
  645. extended_family = (eax >> 20) & 0xFF # 8 bits
  646. return {
  647. 'stepping' : stepping,
  648. 'model' : model,
  649. 'family' : family,
  650. 'processor_type' : processor_type,
  651. 'extended_model' : extended_model,
  652. 'extended_family' : extended_family
  653. }
  654. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000000h:_Get_Highest_Extended_Function_Supported
  655. def get_max_extension_support(self):
  656. # Check for extension support
  657. max_extension_support = self._run_asm(
  658. b"\xB8\x00\x00\x00\x80" # mov ax,0x80000000
  659. b"\x0f\xa2" # cpuid
  660. b"\xC3" # ret
  661. )
  662. return max_extension_support
  663. # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
  664. def get_flags(self, max_extension_support):
  665. # EDX
  666. edx = self._run_asm(
  667. self._one_eax(),
  668. b"\x0f\xa2" # cpuid
  669. b"\x89\xD0" # mov ax,dx
  670. b"\xC3" # ret
  671. )
  672. # ECX
  673. ecx = self._run_asm(
  674. self._one_eax(),
  675. b"\x0f\xa2" # cpuid
  676. b"\x89\xC8" # mov ax,cx
  677. b"\xC3" # ret
  678. )
  679. # Get the CPU flags
  680. flags = {
  681. 'fpu' : is_bit_set(edx, 0),
  682. 'vme' : is_bit_set(edx, 1),
  683. 'de' : is_bit_set(edx, 2),
  684. 'pse' : is_bit_set(edx, 3),
  685. 'tsc' : is_bit_set(edx, 4),
  686. 'msr' : is_bit_set(edx, 5),
  687. 'pae' : is_bit_set(edx, 6),
  688. 'mce' : is_bit_set(edx, 7),
  689. 'cx8' : is_bit_set(edx, 8),
  690. 'apic' : is_bit_set(edx, 9),
  691. #'reserved1' : is_bit_set(edx, 10),
  692. 'sep' : is_bit_set(edx, 11),
  693. 'mtrr' : is_bit_set(edx, 12),
  694. 'pge' : is_bit_set(edx, 13),
  695. 'mca' : is_bit_set(edx, 14),
  696. 'cmov' : is_bit_set(edx, 15),
  697. 'pat' : is_bit_set(edx, 16),
  698. 'pse36' : is_bit_set(edx, 17),
  699. 'pn' : is_bit_set(edx, 18),
  700. 'clflush' : is_bit_set(edx, 19),
  701. #'reserved2' : is_bit_set(edx, 20),
  702. 'dts' : is_bit_set(edx, 21),
  703. 'acpi' : is_bit_set(edx, 22),
  704. 'mmx' : is_bit_set(edx, 23),
  705. 'fxsr' : is_bit_set(edx, 24),
  706. 'sse' : is_bit_set(edx, 25),
  707. 'sse2' : is_bit_set(edx, 26),
  708. 'ss' : is_bit_set(edx, 27),
  709. 'ht' : is_bit_set(edx, 28),
  710. 'tm' : is_bit_set(edx, 29),
  711. 'ia64' : is_bit_set(edx, 30),
  712. 'pbe' : is_bit_set(edx, 31),
  713. 'pni' : is_bit_set(ecx, 0),
  714. 'pclmulqdq' : is_bit_set(ecx, 1),
  715. 'dtes64' : is_bit_set(ecx, 2),
  716. 'monitor' : is_bit_set(ecx, 3),
  717. 'ds_cpl' : is_bit_set(ecx, 4),
  718. 'vmx' : is_bit_set(ecx, 5),
  719. 'smx' : is_bit_set(ecx, 6),
  720. 'est' : is_bit_set(ecx, 7),
  721. 'tm2' : is_bit_set(ecx, 8),
  722. 'ssse3' : is_bit_set(ecx, 9),
  723. 'cid' : is_bit_set(ecx, 10),
  724. #'reserved3' : is_bit_set(ecx, 11),
  725. 'fma' : is_bit_set(ecx, 12),
  726. 'cx16' : is_bit_set(ecx, 13),
  727. 'xtpr' : is_bit_set(ecx, 14),
  728. 'pdcm' : is_bit_set(ecx, 15),
  729. #'reserved4' : is_bit_set(ecx, 16),
  730. 'pcid' : is_bit_set(ecx, 17),
  731. 'dca' : is_bit_set(ecx, 18),
  732. 'sse4_1' : is_bit_set(ecx, 19),
  733. 'sse4_2' : is_bit_set(ecx, 20),
  734. 'x2apic' : is_bit_set(ecx, 21),
  735. 'movbe' : is_bit_set(ecx, 22),
  736. 'popcnt' : is_bit_set(ecx, 23),
  737. 'tscdeadline' : is_bit_set(ecx, 24),
  738. 'aes' : is_bit_set(ecx, 25),
  739. 'xsave' : is_bit_set(ecx, 26),
  740. 'osxsave' : is_bit_set(ecx, 27),
  741. 'avx' : is_bit_set(ecx, 28),
  742. 'f16c' : is_bit_set(ecx, 29),
  743. 'rdrnd' : is_bit_set(ecx, 30),
  744. 'hypervisor' : is_bit_set(ecx, 31)
  745. }
  746. # Get a list of only the flags that are true
  747. flags = [k for k, v in flags.items() if v]
  748. # http://en.wikipedia.org/wiki/CPUID#EAX.3D7.2C_ECX.3D0:_Extended_Features
  749. if max_extension_support >= 7:
  750. # EBX
  751. ebx = self._run_asm(
  752. self._zero_ecx(),
  753. b"\xB8\x07\x00\x00\x00" # mov eax,7
  754. b"\x0f\xa2" # cpuid
  755. b"\x89\xD8" # mov ax,bx
  756. b"\xC3" # ret
  757. )
  758. # ECX
  759. ecx = self._run_asm(
  760. self._zero_ecx(),
  761. b"\xB8\x07\x00\x00\x00" # mov eax,7
  762. b"\x0f\xa2" # cpuid
  763. b"\x89\xC8" # mov ax,cx
  764. b"\xC3" # ret
  765. )
  766. # Get the extended CPU flags
  767. extended_flags = {
  768. #'fsgsbase' : is_bit_set(ebx, 0),
  769. #'IA32_TSC_ADJUST' : is_bit_set(ebx, 1),
  770. 'sgx' : is_bit_set(ebx, 2),
  771. 'bmi1' : is_bit_set(ebx, 3),
  772. 'hle' : is_bit_set(ebx, 4),
  773. 'avx2' : is_bit_set(ebx, 5),
  774. #'reserved' : is_bit_set(ebx, 6),
  775. 'smep' : is_bit_set(ebx, 7),
  776. 'bmi2' : is_bit_set(ebx, 8),
  777. 'erms' : is_bit_set(ebx, 9),
  778. 'invpcid' : is_bit_set(ebx, 10),
  779. 'rtm' : is_bit_set(ebx, 11),
  780. 'pqm' : is_bit_set(ebx, 12),
  781. #'FPU CS and FPU DS deprecated' : is_bit_set(ebx, 13),
  782. 'mpx' : is_bit_set(ebx, 14),
  783. 'pqe' : is_bit_set(ebx, 15),
  784. 'avx512f' : is_bit_set(ebx, 16),
  785. 'avx512dq' : is_bit_set(ebx, 17),
  786. 'rdseed' : is_bit_set(ebx, 18),
  787. 'adx' : is_bit_set(ebx, 19),
  788. 'smap' : is_bit_set(ebx, 20),
  789. 'avx512ifma' : is_bit_set(ebx, 21),
  790. 'pcommit' : is_bit_set(ebx, 22),
  791. 'clflushopt' : is_bit_set(ebx, 23),
  792. 'clwb' : is_bit_set(ebx, 24),
  793. 'intel_pt' : is_bit_set(ebx, 25),
  794. 'avx512pf' : is_bit_set(ebx, 26),
  795. 'avx512er' : is_bit_set(ebx, 27),
  796. 'avx512cd' : is_bit_set(ebx, 28),
  797. 'sha' : is_bit_set(ebx, 29),
  798. 'avx512bw' : is_bit_set(ebx, 30),
  799. 'avx512vl' : is_bit_set(ebx, 31),
  800. 'prefetchwt1' : is_bit_set(ecx, 0),
  801. 'avx512vbmi' : is_bit_set(ecx, 1),
  802. 'umip' : is_bit_set(ecx, 2),
  803. 'pku' : is_bit_set(ecx, 3),
  804. 'ospke' : is_bit_set(ecx, 4),
  805. #'reserved' : is_bit_set(ecx, 5),
  806. 'avx512vbmi2' : is_bit_set(ecx, 6),
  807. #'reserved' : is_bit_set(ecx, 7),
  808. 'gfni' : is_bit_set(ecx, 8),
  809. 'vaes' : is_bit_set(ecx, 9),
  810. 'vpclmulqdq' : is_bit_set(ecx, 10),
  811. 'avx512vnni' : is_bit_set(ecx, 11),
  812. 'avx512bitalg' : is_bit_set(ecx, 12),
  813. #'reserved' : is_bit_set(ecx, 13),
  814. 'avx512vpopcntdq' : is_bit_set(ecx, 14),
  815. #'reserved' : is_bit_set(ecx, 15),
  816. #'reserved' : is_bit_set(ecx, 16),
  817. #'mpx0' : is_bit_set(ecx, 17),
  818. #'mpx1' : is_bit_set(ecx, 18),
  819. #'mpx2' : is_bit_set(ecx, 19),
  820. #'mpx3' : is_bit_set(ecx, 20),
  821. #'mpx4' : is_bit_set(ecx, 21),
  822. 'rdpid' : is_bit_set(ecx, 22),
  823. #'reserved' : is_bit_set(ecx, 23),
  824. #'reserved' : is_bit_set(ecx, 24),
  825. #'reserved' : is_bit_set(ecx, 25),
  826. #'reserved' : is_bit_set(ecx, 26),
  827. #'reserved' : is_bit_set(ecx, 27),
  828. #'reserved' : is_bit_set(ecx, 28),
  829. #'reserved' : is_bit_set(ecx, 29),
  830. 'sgx_lc' : is_bit_set(ecx, 30),
  831. #'reserved' : is_bit_set(ecx, 31)
  832. }
  833. # Get a list of only the flags that are true
  834. extended_flags = [k for k, v in extended_flags.items() if v]
  835. flags += extended_flags
  836. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000001h:_Extended_Processor_Info_and_Feature_Bits
  837. if max_extension_support >= 0x80000001:
  838. # EBX
  839. ebx = self._run_asm(
  840. b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
  841. b"\x0f\xa2" # cpuid
  842. b"\x89\xD8" # mov ax,bx
  843. b"\xC3" # ret
  844. )
  845. # ECX
  846. ecx = self._run_asm(
  847. b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
  848. b"\x0f\xa2" # cpuid
  849. b"\x89\xC8" # mov ax,cx
  850. b"\xC3" # ret
  851. )
  852. # Get the extended CPU flags
  853. extended_flags = {
  854. 'fpu' : is_bit_set(ebx, 0),
  855. 'vme' : is_bit_set(ebx, 1),
  856. 'de' : is_bit_set(ebx, 2),
  857. 'pse' : is_bit_set(ebx, 3),
  858. 'tsc' : is_bit_set(ebx, 4),
  859. 'msr' : is_bit_set(ebx, 5),
  860. 'pae' : is_bit_set(ebx, 6),
  861. 'mce' : is_bit_set(ebx, 7),
  862. 'cx8' : is_bit_set(ebx, 8),
  863. 'apic' : is_bit_set(ebx, 9),
  864. #'reserved' : is_bit_set(ebx, 10),
  865. 'syscall' : is_bit_set(ebx, 11),
  866. 'mtrr' : is_bit_set(ebx, 12),
  867. 'pge' : is_bit_set(ebx, 13),
  868. 'mca' : is_bit_set(ebx, 14),
  869. 'cmov' : is_bit_set(ebx, 15),
  870. 'pat' : is_bit_set(ebx, 16),
  871. 'pse36' : is_bit_set(ebx, 17),
  872. #'reserved' : is_bit_set(ebx, 18),
  873. 'mp' : is_bit_set(ebx, 19),
  874. 'nx' : is_bit_set(ebx, 20),
  875. #'reserved' : is_bit_set(ebx, 21),
  876. 'mmxext' : is_bit_set(ebx, 22),
  877. 'mmx' : is_bit_set(ebx, 23),
  878. 'fxsr' : is_bit_set(ebx, 24),
  879. 'fxsr_opt' : is_bit_set(ebx, 25),
  880. 'pdpe1gp' : is_bit_set(ebx, 26),
  881. 'rdtscp' : is_bit_set(ebx, 27),
  882. #'reserved' : is_bit_set(ebx, 28),
  883. 'lm' : is_bit_set(ebx, 29),
  884. '3dnowext' : is_bit_set(ebx, 30),
  885. '3dnow' : is_bit_set(ebx, 31),
  886. 'lahf_lm' : is_bit_set(ecx, 0),
  887. 'cmp_legacy' : is_bit_set(ecx, 1),
  888. 'svm' : is_bit_set(ecx, 2),
  889. 'extapic' : is_bit_set(ecx, 3),
  890. 'cr8_legacy' : is_bit_set(ecx, 4),
  891. 'abm' : is_bit_set(ecx, 5),
  892. 'sse4a' : is_bit_set(ecx, 6),
  893. 'misalignsse' : is_bit_set(ecx, 7),
  894. '3dnowprefetch' : is_bit_set(ecx, 8),
  895. 'osvw' : is_bit_set(ecx, 9),
  896. 'ibs' : is_bit_set(ecx, 10),
  897. 'xop' : is_bit_set(ecx, 11),
  898. 'skinit' : is_bit_set(ecx, 12),
  899. 'wdt' : is_bit_set(ecx, 13),
  900. #'reserved' : is_bit_set(ecx, 14),
  901. 'lwp' : is_bit_set(ecx, 15),
  902. 'fma4' : is_bit_set(ecx, 16),
  903. 'tce' : is_bit_set(ecx, 17),
  904. #'reserved' : is_bit_set(ecx, 18),
  905. 'nodeid_msr' : is_bit_set(ecx, 19),
  906. #'reserved' : is_bit_set(ecx, 20),
  907. 'tbm' : is_bit_set(ecx, 21),
  908. 'topoext' : is_bit_set(ecx, 22),
  909. 'perfctr_core' : is_bit_set(ecx, 23),
  910. 'perfctr_nb' : is_bit_set(ecx, 24),
  911. #'reserved' : is_bit_set(ecx, 25),
  912. 'dbx' : is_bit_set(ecx, 26),
  913. 'perftsc' : is_bit_set(ecx, 27),
  914. 'pci_l2i' : is_bit_set(ecx, 28),
  915. #'reserved' : is_bit_set(ecx, 29),
  916. #'reserved' : is_bit_set(ecx, 30),
  917. #'reserved' : is_bit_set(ecx, 31)
  918. }
  919. # Get a list of only the flags that are true
  920. extended_flags = [k for k, v in extended_flags.items() if v]
  921. flags += extended_flags
  922. flags.sort()
  923. return flags
  924. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000002h.2C80000003h.2C80000004h:_Processor_Brand_String
  925. def get_processor_brand(self, max_extension_support):
  926. processor_brand = ""
  927. # Processor brand string
  928. if max_extension_support >= 0x80000004:
  929. instructions = [
  930. b"\xB8\x02\x00\x00\x80", # mov ax,0x80000002
  931. b"\xB8\x03\x00\x00\x80", # mov ax,0x80000003
  932. b"\xB8\x04\x00\x00\x80" # mov ax,0x80000004
  933. ]
  934. for instruction in instructions:
  935. # EAX
  936. eax = self._run_asm(
  937. instruction, # mov ax,0x8000000?
  938. b"\x0f\xa2" # cpuid
  939. b"\x89\xC0" # mov ax,ax
  940. b"\xC3" # ret
  941. )
  942. # EBX
  943. ebx = self._run_asm(
  944. instruction, # mov ax,0x8000000?
  945. b"\x0f\xa2" # cpuid
  946. b"\x89\xD8" # mov ax,bx
  947. b"\xC3" # ret
  948. )
  949. # ECX
  950. ecx = self._run_asm(
  951. instruction, # mov ax,0x8000000?
  952. b"\x0f\xa2" # cpuid
  953. b"\x89\xC8" # mov ax,cx
  954. b"\xC3" # ret
  955. )
  956. # EDX
  957. edx = self._run_asm(
  958. instruction, # mov ax,0x8000000?
  959. b"\x0f\xa2" # cpuid
  960. b"\x89\xD0" # mov ax,dx
  961. b"\xC3" # ret
  962. )
  963. # Combine each of the 4 bytes in each register into the string
  964. for reg in [eax, ebx, ecx, edx]:
  965. for n in [0, 8, 16, 24]:
  966. processor_brand += chr((reg >> n) & 0xFF)
  967. # Strip off any trailing NULL terminators and white space
  968. processor_brand = processor_brand.strip("\0").strip()
  969. return processor_brand
  970. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000006h:_Extended_L2_Cache_Features
  971. def get_cache(self, max_extension_support):
  972. cache_info = {}
  973. # Just return if the cache feature is not supported
  974. if max_extension_support < 0x80000006:
  975. return cache_info
  976. # ECX
  977. ecx = self._run_asm(
  978. b"\xB8\x06\x00\x00\x80" # mov ax,0x80000006
  979. b"\x0f\xa2" # cpuid
  980. b"\x89\xC8" # mov ax,cx
  981. b"\xC3" # ret
  982. )
  983. cache_info = {
  984. 'size_kb' : ecx & 0xFF,
  985. 'line_size_b' : (ecx >> 12) & 0xF,
  986. 'associativity' : (ecx >> 16) & 0xFFFF
  987. }
  988. return cache_info
  989. def get_ticks(self):
  990. retval = None
  991. if DataSource.bits == '32bit':
  992. # Works on x86_32
  993. restype = None
  994. argtypes = (ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint))
  995. get_ticks_x86_32, address = self._asm_func(restype, argtypes,
  996. [
  997. b"\x55", # push bp
  998. b"\x89\xE5", # mov bp,sp
  999. b"\x31\xC0", # xor ax,ax
  1000. b"\x0F\xA2", # cpuid
  1001. b"\x0F\x31", # rdtsc
  1002. b"\x8B\x5D\x08", # mov bx,[di+0x8]
  1003. b"\x8B\x4D\x0C", # mov cx,[di+0xc]
  1004. b"\x89\x13", # mov [bp+di],dx
  1005. b"\x89\x01", # mov [bx+di],ax
  1006. b"\x5D", # pop bp
  1007. b"\xC3" # ret
  1008. ]
  1009. )
  1010. high = ctypes.c_uint32(0)
  1011. low = ctypes.c_uint32(0)
  1012. get_ticks_x86_32(ctypes.byref(high), ctypes.byref(low))
  1013. retval = ((high.value << 32) & 0xFFFFFFFF00000000) | low.value
  1014. elif DataSource.bits == '64bit':
  1015. # Works on x86_64
  1016. restype = ctypes.c_uint64
  1017. argtypes = ()
  1018. get_ticks_x86_64, address = self._asm_func(restype, argtypes,
  1019. [
  1020. b"\x48", # dec ax
  1021. b"\x31\xC0", # xor ax,ax
  1022. b"\x0F\xA2", # cpuid
  1023. b"\x0F\x31", # rdtsc
  1024. b"\x48", # dec ax
  1025. b"\xC1\xE2\x20", # shl dx,byte 0x20
  1026. b"\x48", # dec ax
  1027. b"\x09\xD0", # or ax,dx
  1028. b"\xC3", # ret
  1029. ]
  1030. )
  1031. retval = get_ticks_x86_64()
  1032. return retval
  1033. def get_raw_hz(self):
  1034. start = self.get_ticks()
  1035. time.sleep(1)
  1036. end = self.get_ticks()
  1037. ticks = (end - start)
  1038. return ticks
  1039. def _actual_get_cpu_info_from_cpuid(queue):
  1040. '''
  1041. Warning! This function has the potential to crash the Python runtime.
  1042. Do not call it directly. Use the _get_cpu_info_from_cpuid function instead.
  1043. It will safely call this function in another process.
  1044. '''
  1045. # Pipe all output to nothing
  1046. sys.stdout = open(os.devnull, 'w')
  1047. sys.stderr = open(os.devnull, 'w')
  1048. # Get the CPU arch and bits
  1049. arch, bits = parse_arch(DataSource.raw_arch_string)
  1050. # Return none if this is not an X86 CPU
  1051. if not arch in ['X86_32', 'X86_64']:
  1052. queue.put(obj_to_b64({}))
  1053. return
  1054. # Return none if SE Linux is in enforcing mode
  1055. cpuid = CPUID()
  1056. if cpuid.is_selinux_enforcing:
  1057. queue.put(obj_to_b64({}))
  1058. return
  1059. # Get the cpu info from the CPUID register
  1060. max_extension_support = cpuid.get_max_extension_support()
  1061. cache_info = cpuid.get_cache(max_extension_support)
  1062. info = cpuid.get_info()
  1063. processor_brand = cpuid.get_processor_brand(max_extension_support)
  1064. # Get the Hz and scale
  1065. hz_actual = cpuid.get_raw_hz()
  1066. hz_actual = to_hz_string(hz_actual)
  1067. # Get the Hz and scale
  1068. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1069. info = {
  1070. 'vendor_id' : cpuid.get_vendor_id(),
  1071. 'hardware' : '',
  1072. 'brand' : processor_brand,
  1073. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1074. 'hz_actual' : to_friendly_hz(hz_actual, 0),
  1075. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1076. 'hz_actual_raw' : to_raw_hz(hz_actual, 0),
  1077. 'l2_cache_size' : to_friendly_bytes(cache_info['size_kb']),
  1078. 'l2_cache_line_size' : cache_info['line_size_b'],
  1079. 'l2_cache_associativity' : hex(cache_info['associativity']),
  1080. 'stepping' : info['stepping'],
  1081. 'model' : info['model'],
  1082. 'family' : info['family'],
  1083. 'processor_type' : info['processor_type'],
  1084. 'extended_model' : info['extended_model'],
  1085. 'extended_family' : info['extended_family'],
  1086. 'flags' : cpuid.get_flags(max_extension_support)
  1087. }
  1088. info = {k: v for k, v in info.items() if v}
  1089. queue.put(obj_to_b64(info))
  1090. def _get_cpu_info_from_cpuid():
  1091. '''
  1092. Returns the CPU info gathered by querying the X86 cpuid register in a new process.
  1093. Returns {} on non X86 cpus.
  1094. Returns {} if SELinux is in enforcing mode.
  1095. '''
  1096. from multiprocessing import Process, Queue
  1097. # Return {} if can't cpuid
  1098. if not DataSource.can_cpuid:
  1099. return {}
  1100. # Get the CPU arch and bits
  1101. arch, bits = parse_arch(DataSource.raw_arch_string)
  1102. # Return {} if this is not an X86 CPU
  1103. if not arch in ['X86_32', 'X86_64']:
  1104. return {}
  1105. try:
  1106. # Start running the function in a subprocess
  1107. queue = Queue()
  1108. p = Process(target=_actual_get_cpu_info_from_cpuid, args=(queue,))
  1109. p.start()
  1110. # Wait for the process to end, while it is still alive
  1111. while p.is_alive():
  1112. p.join(0)
  1113. # Return {} if it failed
  1114. if p.exitcode != 0:
  1115. return {}
  1116. # Return the result, only if there is something to read
  1117. if not queue.empty():
  1118. output = queue.get()
  1119. return b64_to_obj(output)
  1120. except:
  1121. pass
  1122. # Return {} if everything failed
  1123. return {}
  1124. def _get_cpu_info_from_proc_cpuinfo():
  1125. '''
  1126. Returns the CPU info gathered from /proc/cpuinfo.
  1127. Returns {} if /proc/cpuinfo is not found.
  1128. '''
  1129. try:
  1130. # Just return {} if there is no cpuinfo
  1131. if not DataSource.has_proc_cpuinfo():
  1132. return {}
  1133. returncode, output = DataSource.cat_proc_cpuinfo()
  1134. if returncode != 0:
  1135. return {}
  1136. # Various fields
  1137. vendor_id = _get_field(False, output, None, '', 'vendor_id', 'vendor id', 'vendor')
  1138. processor_brand = _get_field(True, output, None, None, 'model name','cpu', 'processor')
  1139. cache_size = _get_field(False, output, None, '', 'cache size')
  1140. stepping = _get_field(False, output, int, 0, 'stepping')
  1141. model = _get_field(False, output, int, 0, 'model')
  1142. family = _get_field(False, output, int, 0, 'cpu family')
  1143. hardware = _get_field(False, output, None, '', 'Hardware')
  1144. # Flags
  1145. flags = _get_field(False, output, None, None, 'flags', 'Features')
  1146. if flags:
  1147. flags = flags.split()
  1148. flags.sort()
  1149. # Convert from MHz string to Hz
  1150. hz_actual = _get_field(False, output, None, '', 'cpu MHz', 'cpu speed', 'clock')
  1151. hz_actual = hz_actual.lower().rstrip('mhz').strip()
  1152. hz_actual = to_hz_string(hz_actual)
  1153. # Convert from GHz/MHz string to Hz
  1154. scale, hz_advertised = (0, None)
  1155. try:
  1156. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1157. except Exception:
  1158. pass
  1159. info = {
  1160. 'hardware' : hardware,
  1161. 'brand' : processor_brand,
  1162. 'l3_cache_size' : to_friendly_bytes(cache_size),
  1163. 'flags' : flags,
  1164. 'vendor_id' : vendor_id,
  1165. 'stepping' : stepping,
  1166. 'model' : model,
  1167. 'family' : family,
  1168. }
  1169. # Make the Hz the same for actual and advertised if missing any
  1170. if not hz_advertised or hz_advertised == '0.0':
  1171. hz_advertised = hz_actual
  1172. scale = 6
  1173. elif not hz_actual or hz_actual == '0.0':
  1174. hz_actual = hz_advertised
  1175. # Add the Hz if there is one
  1176. if to_raw_hz(hz_advertised, scale) > (0, 0):
  1177. info['hz_advertised'] = to_friendly_hz(hz_advertised, scale)
  1178. info['hz_advertised_raw'] = to_raw_hz(hz_advertised, scale)
  1179. if to_raw_hz(hz_actual, scale) > (0, 0):
  1180. info['hz_actual'] = to_friendly_hz(hz_actual, 6)
  1181. info['hz_actual_raw'] = to_raw_hz(hz_actual, 6)
  1182. info = {k: v for k, v in info.items() if v}
  1183. return info
  1184. except:
  1185. #raise # NOTE: To have this throw on error, uncomment this line
  1186. return {}
  1187. def _get_cpu_info_from_cpufreq_info():
  1188. '''
  1189. Returns the CPU info gathered from cpufreq-info.
  1190. Returns {} if cpufreq-info is not found.
  1191. '''
  1192. try:
  1193. scale, hz_brand = 1, '0.0'
  1194. if not DataSource.has_cpufreq_info():
  1195. return {}
  1196. returncode, output = DataSource.cpufreq_info()
  1197. if returncode != 0:
  1198. return {}
  1199. hz_brand = output.split('current CPU frequency is')[1].split('\n')[0]
  1200. i = hz_brand.find('Hz')
  1201. assert(i != -1)
  1202. hz_brand = hz_brand[0 : i+2].strip().lower()
  1203. if hz_brand.endswith('mhz'):
  1204. scale = 6
  1205. elif hz_brand.endswith('ghz'):
  1206. scale = 9
  1207. hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip()
  1208. hz_brand = to_hz_string(hz_brand)
  1209. info = {
  1210. 'hz_advertised' : to_friendly_hz(hz_brand, scale),
  1211. 'hz_actual' : to_friendly_hz(hz_brand, scale),
  1212. 'hz_advertised_raw' : to_raw_hz(hz_brand, scale),
  1213. 'hz_actual_raw' : to_raw_hz(hz_brand, scale),
  1214. }
  1215. info = {k: v for k, v in info.items() if v}
  1216. return info
  1217. except:
  1218. #raise # NOTE: To have this throw on error, uncomment this line
  1219. return {}
  1220. def _get_cpu_info_from_lscpu():
  1221. '''
  1222. Returns the CPU info gathered from lscpu.
  1223. Returns {} if lscpu is not found.
  1224. '''
  1225. try:
  1226. if not DataSource.has_lscpu():
  1227. return {}
  1228. returncode, output = DataSource.lscpu()
  1229. if returncode != 0:
  1230. return {}
  1231. info = {}
  1232. new_hz = _get_field(False, output, None, None, 'CPU max MHz', 'CPU MHz')
  1233. if new_hz:
  1234. new_hz = to_hz_string(new_hz)
  1235. scale = 6
  1236. info['hz_advertised'] = to_friendly_hz(new_hz, scale)
  1237. info['hz_actual'] = to_friendly_hz(new_hz, scale)
  1238. info['hz_advertised_raw'] = to_raw_hz(new_hz, scale)
  1239. info['hz_actual_raw'] = to_raw_hz(new_hz, scale)
  1240. vendor_id = _get_field(False, output, None, None, 'Vendor ID')
  1241. if vendor_id:
  1242. info['vendor_id'] = vendor_id
  1243. brand = _get_field(False, output, None, None, 'Model name')
  1244. if brand:
  1245. info['brand'] = brand
  1246. family = _get_field(False, output, None, None, 'CPU family')
  1247. if family and family.isdigit():
  1248. info['family'] = int(family)
  1249. stepping = _get_field(False, output, None, None, 'Stepping')
  1250. if stepping and stepping.isdigit():
  1251. info['stepping'] = int(stepping)
  1252. model = _get_field(False, output, None, None, 'Model')
  1253. if model and model.isdigit():
  1254. info['model'] = int(model)
  1255. l1_data_cache_size = _get_field(False, output, None, None, 'L1d cache')
  1256. if l1_data_cache_size:
  1257. info['l1_data_cache_size'] = to_friendly_bytes(l1_data_cache_size)
  1258. l1_instruction_cache_size = _get_field(False, output, None, None, 'L1i cache')
  1259. if l1_instruction_cache_size:
  1260. info['l1_instruction_cache_size'] = to_friendly_bytes(l1_instruction_cache_size)
  1261. l2_cache_size = _get_field(False, output, None, None, 'L2 cache')
  1262. if l2_cache_size:
  1263. info['l2_cache_size'] = to_friendly_bytes(l2_cache_size)
  1264. l3_cache_size = _get_field(False, output, None, None, 'L3 cache')
  1265. if l3_cache_size:
  1266. info['l3_cache_size'] = to_friendly_bytes(l3_cache_size)
  1267. # Flags
  1268. flags = _get_field(False, output, None, None, 'flags', 'Features')
  1269. if flags:
  1270. flags = flags.split()
  1271. flags.sort()
  1272. info['flags'] = flags
  1273. info = {k: v for k, v in info.items() if v}
  1274. return info
  1275. except:
  1276. #raise # NOTE: To have this throw on error, uncomment this line
  1277. return {}
  1278. def _get_cpu_info_from_dmesg():
  1279. '''
  1280. Returns the CPU info gathered from dmesg.
  1281. Returns {} if dmesg is not found or does not have the desired info.
  1282. '''
  1283. # Just return {} if there is no dmesg
  1284. if not DataSource.has_dmesg():
  1285. return {}
  1286. # If dmesg fails return {}
  1287. returncode, output = DataSource.dmesg_a()
  1288. if output == None or returncode != 0:
  1289. return {}
  1290. return _parse_dmesg_output(output)
  1291. # https://openpowerfoundation.org/wp-content/uploads/2016/05/LoPAPR_DRAFT_v11_24March2016_cmt1.pdf
  1292. # page 767
  1293. def _get_cpu_info_from_ibm_pa_features():
  1294. '''
  1295. Returns the CPU info gathered from lsprop /proc/device-tree/cpus/*/ibm,pa-features
  1296. Returns {} if lsprop is not found or ibm,pa-features does not have the desired info.
  1297. '''
  1298. try:
  1299. # Just return {} if there is no lsprop
  1300. if not DataSource.has_ibm_pa_features():
  1301. return {}
  1302. # If ibm,pa-features fails return {}
  1303. returncode, output = DataSource.ibm_pa_features()
  1304. if output == None or returncode != 0:
  1305. return {}
  1306. # Filter out invalid characters from output
  1307. value = output.split("ibm,pa-features")[1].lower()
  1308. value = [s for s in value if s in list('0123456789abcfed')]
  1309. value = ''.join(value)
  1310. # Get data converted to Uint32 chunks
  1311. left = int(value[0 : 8], 16)
  1312. right = int(value[8 : 16], 16)
  1313. # Get the CPU flags
  1314. flags = {
  1315. # Byte 0
  1316. 'mmu' : is_bit_set(left, 0),
  1317. 'fpu' : is_bit_set(left, 1),
  1318. 'slb' : is_bit_set(left, 2),
  1319. 'run' : is_bit_set(left, 3),
  1320. #'reserved' : is_bit_set(left, 4),
  1321. 'dabr' : is_bit_set(left, 5),
  1322. 'ne' : is_bit_set(left, 6),
  1323. 'wtr' : is_bit_set(left, 7),
  1324. # Byte 1
  1325. 'mcr' : is_bit_set(left, 8),
  1326. 'dsisr' : is_bit_set(left, 9),
  1327. 'lp' : is_bit_set(left, 10),
  1328. 'ri' : is_bit_set(left, 11),
  1329. 'dabrx' : is_bit_set(left, 12),
  1330. 'sprg3' : is_bit_set(left, 13),
  1331. 'rislb' : is_bit_set(left, 14),
  1332. 'pp' : is_bit_set(left, 15),
  1333. # Byte 2
  1334. 'vpm' : is_bit_set(left, 16),
  1335. 'dss_2.05' : is_bit_set(left, 17),
  1336. #'reserved' : is_bit_set(left, 18),
  1337. 'dar' : is_bit_set(left, 19),
  1338. #'reserved' : is_bit_set(left, 20),
  1339. 'ppr' : is_bit_set(left, 21),
  1340. 'dss_2.02' : is_bit_set(left, 22),
  1341. 'dss_2.06' : is_bit_set(left, 23),
  1342. # Byte 3
  1343. 'lsd_in_dscr' : is_bit_set(left, 24),
  1344. 'ugr_in_dscr' : is_bit_set(left, 25),
  1345. #'reserved' : is_bit_set(left, 26),
  1346. #'reserved' : is_bit_set(left, 27),
  1347. #'reserved' : is_bit_set(left, 28),
  1348. #'reserved' : is_bit_set(left, 29),
  1349. #'reserved' : is_bit_set(left, 30),
  1350. #'reserved' : is_bit_set(left, 31),
  1351. # Byte 4
  1352. 'sso_2.06' : is_bit_set(right, 0),
  1353. #'reserved' : is_bit_set(right, 1),
  1354. #'reserved' : is_bit_set(right, 2),
  1355. #'reserved' : is_bit_set(right, 3),
  1356. #'reserved' : is_bit_set(right, 4),
  1357. #'reserved' : is_bit_set(right, 5),
  1358. #'reserved' : is_bit_set(right, 6),
  1359. #'reserved' : is_bit_set(right, 7),
  1360. # Byte 5
  1361. 'le' : is_bit_set(right, 8),
  1362. 'cfar' : is_bit_set(right, 9),
  1363. 'eb' : is_bit_set(right, 10),
  1364. 'lsq_2.07' : is_bit_set(right, 11),
  1365. #'reserved' : is_bit_set(right, 12),
  1366. #'reserved' : is_bit_set(right, 13),
  1367. #'reserved' : is_bit_set(right, 14),
  1368. #'reserved' : is_bit_set(right, 15),
  1369. # Byte 6
  1370. 'dss_2.07' : is_bit_set(right, 16),
  1371. #'reserved' : is_bit_set(right, 17),
  1372. #'reserved' : is_bit_set(right, 18),
  1373. #'reserved' : is_bit_set(right, 19),
  1374. #'reserved' : is_bit_set(right, 20),
  1375. #'reserved' : is_bit_set(right, 21),
  1376. #'reserved' : is_bit_set(right, 22),
  1377. #'reserved' : is_bit_set(right, 23),
  1378. # Byte 7
  1379. #'reserved' : is_bit_set(right, 24),
  1380. #'reserved' : is_bit_set(right, 25),
  1381. #'reserved' : is_bit_set(right, 26),
  1382. #'reserved' : is_bit_set(right, 27),
  1383. #'reserved' : is_bit_set(right, 28),
  1384. #'reserved' : is_bit_set(right, 29),
  1385. #'reserved' : is_bit_set(right, 30),
  1386. #'reserved' : is_bit_set(right, 31),
  1387. }
  1388. # Get a list of only the flags that are true
  1389. flags = [k for k, v in flags.items() if v]
  1390. flags.sort()
  1391. info = {
  1392. 'flags' : flags
  1393. }
  1394. info = {k: v for k, v in info.items() if v}
  1395. return info
  1396. except:
  1397. return {}
  1398. def _get_cpu_info_from_cat_var_run_dmesg_boot():
  1399. '''
  1400. Returns the CPU info gathered from /var/run/dmesg.boot.
  1401. Returns {} if dmesg is not found or does not have the desired info.
  1402. '''
  1403. # Just return {} if there is no /var/run/dmesg.boot
  1404. if not DataSource.has_var_run_dmesg_boot():
  1405. return {}
  1406. # If dmesg.boot fails return {}
  1407. returncode, output = DataSource.cat_var_run_dmesg_boot()
  1408. if output == None or returncode != 0:
  1409. return {}
  1410. return _parse_dmesg_output(output)
  1411. def _get_cpu_info_from_sysctl():
  1412. '''
  1413. Returns the CPU info gathered from sysctl.
  1414. Returns {} if sysctl is not found.
  1415. '''
  1416. try:
  1417. # Just return {} if there is no sysctl
  1418. if not DataSource.has_sysctl():
  1419. return {}
  1420. # If sysctl fails return {}
  1421. returncode, output = DataSource.sysctl_machdep_cpu_hw_cpufrequency()
  1422. if output == None or returncode != 0:
  1423. return {}
  1424. # Various fields
  1425. vendor_id = _get_field(False, output, None, None, 'machdep.cpu.vendor')
  1426. processor_brand = _get_field(True, output, None, None, 'machdep.cpu.brand_string')
  1427. cache_size = _get_field(False, output, None, None, 'machdep.cpu.cache.size')
  1428. stepping = _get_field(False, output, int, 0, 'machdep.cpu.stepping')
  1429. model = _get_field(False, output, int, 0, 'machdep.cpu.model')
  1430. family = _get_field(False, output, int, 0, 'machdep.cpu.family')
  1431. # Flags
  1432. flags = _get_field(False, output, None, '', 'machdep.cpu.features').lower().split()
  1433. flags.extend(_get_field(False, output, None, '', 'machdep.cpu.leaf7_features').lower().split())
  1434. flags.extend(_get_field(False, output, None, '', 'machdep.cpu.extfeatures').lower().split())
  1435. flags.sort()
  1436. # Convert from GHz/MHz string to Hz
  1437. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1438. hz_actual = _get_field(False, output, None, None, 'hw.cpufrequency')
  1439. hz_actual = to_hz_string(hz_actual)
  1440. info = {
  1441. 'vendor_id' : vendor_id,
  1442. 'brand' : processor_brand,
  1443. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1444. 'hz_actual' : to_friendly_hz(hz_actual, 0),
  1445. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1446. 'hz_actual_raw' : to_raw_hz(hz_actual, 0),
  1447. 'l2_cache_size' : to_friendly_bytes(cache_size),
  1448. 'stepping' : stepping,
  1449. 'model' : model,
  1450. 'family' : family,
  1451. 'flags' : flags
  1452. }
  1453. info = {k: v for k, v in info.items() if v}
  1454. return info
  1455. except:
  1456. return {}
  1457. def _get_cpu_info_from_sysinfo():
  1458. '''
  1459. Returns the CPU info gathered from sysinfo.
  1460. Returns {} if sysinfo is not found.
  1461. '''
  1462. info = _get_cpu_info_from_sysinfo_v1()
  1463. info.update(_get_cpu_info_from_sysinfo_v2())
  1464. return info
  1465. def _get_cpu_info_from_sysinfo_v1():
  1466. '''
  1467. Returns the CPU info gathered from sysinfo.
  1468. Returns {} if sysinfo is not found.
  1469. '''
  1470. try:
  1471. # Just return {} if there is no sysinfo
  1472. if not DataSource.has_sysinfo():
  1473. return {}
  1474. # If sysinfo fails return {}
  1475. returncode, output = DataSource.sysinfo_cpu()
  1476. if output == None or returncode != 0:
  1477. return {}
  1478. # Various fields
  1479. vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ')
  1480. processor_brand = output.split('CPU #0: "')[1].split('"\n')[0]
  1481. cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size')
  1482. stepping = int(output.split(', stepping ')[1].split(',')[0].strip())
  1483. model = int(output.split(', model ')[1].split(',')[0].strip())
  1484. family = int(output.split(', family ')[1].split(',')[0].strip())
  1485. # Flags
  1486. flags = []
  1487. for line in output.split('\n'):
  1488. if line.startswith('\t\t'):
  1489. for flag in line.strip().lower().split():
  1490. flags.append(flag)
  1491. flags.sort()
  1492. # Convert from GHz/MHz string to Hz
  1493. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1494. hz_actual = hz_advertised
  1495. info = {
  1496. 'vendor_id' : vendor_id,
  1497. 'brand' : processor_brand,
  1498. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1499. 'hz_actual' : to_friendly_hz(hz_actual, scale),
  1500. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1501. 'hz_actual_raw' : to_raw_hz(hz_actual, scale),
  1502. 'l2_cache_size' : to_friendly_bytes(cache_size),
  1503. 'stepping' : stepping,
  1504. 'model' : model,
  1505. 'family' : family,
  1506. 'flags' : flags
  1507. }
  1508. info = {k: v for k, v in info.items() if v}
  1509. return info
  1510. except:
  1511. return {}
  1512. def _get_cpu_info_from_sysinfo_v2():
  1513. '''
  1514. Returns the CPU info gathered from sysinfo.
  1515. Returns {} if sysinfo is not found.
  1516. '''
  1517. try:
  1518. # Just return {} if there is no sysinfo
  1519. if not DataSource.has_sysinfo():
  1520. return {}
  1521. # If sysinfo fails return {}
  1522. returncode, output = DataSource.sysinfo_cpu()
  1523. if output == None or returncode != 0:
  1524. return {}
  1525. # Various fields
  1526. vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ')
  1527. processor_brand = output.split('CPU #0: "')[1].split('"\n')[0]
  1528. cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size')
  1529. signature = output.split('Signature:')[1].split('\n')[0].strip()
  1530. #
  1531. stepping = int(signature.split('stepping ')[1].split(',')[0].strip())
  1532. model = int(signature.split('model ')[1].split(',')[0].strip())
  1533. family = int(signature.split('family ')[1].split(',')[0].strip())
  1534. # Flags
  1535. def get_subsection_flags(output):
  1536. retval = []
  1537. for line in output.split('\n')[1:]:
  1538. if not line.startswith(' '): break
  1539. for entry in line.strip().lower().split(' '):
  1540. retval.append(entry)
  1541. return retval
  1542. flags = get_subsection_flags(output.split('Features: ')[1]) + \
  1543. get_subsection_flags(output.split('Extended Features (0x00000001): ')[1]) + \
  1544. get_subsection_flags(output.split('Extended Features (0x80000001): ')[1])
  1545. flags.sort()
  1546. # Convert from GHz/MHz string to Hz
  1547. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1548. hz_actual = hz_advertised
  1549. info = {
  1550. 'vendor_id' : vendor_id,
  1551. 'brand' : processor_brand,
  1552. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1553. 'hz_actual' : to_friendly_hz(hz_actual, scale),
  1554. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1555. 'hz_actual_raw' : to_raw_hz(hz_actual, scale),
  1556. 'l2_cache_size' : to_friendly_bytes(cache_size),
  1557. 'stepping' : stepping,
  1558. 'model' : model,
  1559. 'family' : family,
  1560. 'flags' : flags
  1561. }
  1562. info = {k: v for k, v in info.items() if v}
  1563. return info
  1564. except:
  1565. return {}
  1566. def _get_cpu_info_from_wmic():
  1567. '''
  1568. Returns the CPU info gathered from WMI.
  1569. Returns {} if not on Windows, or wmic is not installed.
  1570. '''
  1571. try:
  1572. # Just return {} if not Windows or there is no wmic
  1573. if not DataSource.is_windows or not DataSource.has_wmic():
  1574. return {}
  1575. returncode, output = DataSource.wmic_cpu()
  1576. if output == None or returncode != 0:
  1577. return {}
  1578. # Break the list into key values pairs
  1579. value = output.split("\n")
  1580. value = [s.rstrip().split('=') for s in value if '=' in s]
  1581. value = {k: v for k, v in value if v}
  1582. # Get the advertised MHz
  1583. processor_brand = value.get('Name')
  1584. scale_advertised, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1585. # Get the actual MHz
  1586. hz_actual = value.get('CurrentClockSpeed')
  1587. scale_actual = 6
  1588. if hz_actual:
  1589. hz_actual = to_hz_string(hz_actual)
  1590. # Get cache sizes
  1591. l2_cache_size = value.get('L2CacheSize')
  1592. if l2_cache_size:
  1593. l2_cache_size = l2_cache_size + ' KB'
  1594. l3_cache_size = value.get('L3CacheSize')
  1595. if l3_cache_size:
  1596. l3_cache_size = l3_cache_size + ' KB'
  1597. # Get family, model, and stepping
  1598. family, model, stepping = '', '', ''
  1599. description = value.get('Description') or value.get('Caption')
  1600. entries = description.split(' ')
  1601. if 'Family' in entries and entries.index('Family') < len(entries)-1:
  1602. i = entries.index('Family')
  1603. family = int(entries[i + 1])
  1604. if 'Model' in entries and entries.index('Model') < len(entries)-1:
  1605. i = entries.index('Model')
  1606. model = int(entries[i + 1])
  1607. if 'Stepping' in entries and entries.index('Stepping') < len(entries)-1:
  1608. i = entries.index('Stepping')
  1609. stepping = int(entries[i + 1])
  1610. info = {
  1611. 'vendor_id' : value.get('Manufacturer'),
  1612. 'brand' : processor_brand,
  1613. 'hz_advertised' : to_friendly_hz(hz_advertised, scale_advertised),
  1614. 'hz_actual' : to_friendly_hz(hz_actual, scale_actual),
  1615. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale_advertised),
  1616. 'hz_actual_raw' : to_raw_hz(hz_actual, scale_actual),
  1617. 'l2_cache_size' : l2_cache_size,
  1618. 'l3_cache_size' : l3_cache_size,
  1619. 'stepping' : stepping,
  1620. 'model' : model,
  1621. 'family' : family,
  1622. }
  1623. info = {k: v for k, v in info.items() if v}
  1624. return info
  1625. except:
  1626. #raise # NOTE: To have this throw on error, uncomment this line
  1627. return {}
  1628. def _get_cpu_info_from_registry():
  1629. '''
  1630. FIXME: Is missing many of the newer CPU flags like sse3
  1631. Returns the CPU info gathered from the Windows Registry.
  1632. Returns {} if not on Windows.
  1633. '''
  1634. try:
  1635. # Just return {} if not on Windows
  1636. if not DataSource.is_windows:
  1637. return {}
  1638. # Get the CPU name
  1639. processor_brand = DataSource.winreg_processor_brand()
  1640. # Get the CPU vendor id
  1641. vendor_id = DataSource.winreg_vendor_id()
  1642. # Get the CPU arch and bits
  1643. raw_arch_string = DataSource.winreg_raw_arch_string()
  1644. arch, bits = parse_arch(raw_arch_string)
  1645. # Get the actual CPU Hz
  1646. hz_actual = DataSource.winreg_hz_actual()
  1647. hz_actual = to_hz_string(hz_actual)
  1648. # Get the advertised CPU Hz
  1649. scale, hz_advertised = _get_hz_string_from_brand(processor_brand)
  1650. # Get the CPU features
  1651. feature_bits = DataSource.winreg_feature_bits()
  1652. def is_set(bit):
  1653. mask = 0x80000000 >> bit
  1654. retval = mask & feature_bits > 0
  1655. return retval
  1656. # http://en.wikipedia.org/wiki/CPUID
  1657. # http://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean
  1658. # http://www.lohninger.com/helpcsuite/public_constants_cpuid.htm
  1659. flags = {
  1660. 'fpu' : is_set(0), # Floating Point Unit
  1661. 'vme' : is_set(1), # V86 Mode Extensions
  1662. 'de' : is_set(2), # Debug Extensions - I/O breakpoints supported
  1663. 'pse' : is_set(3), # Page Size Extensions (4 MB pages supported)
  1664. 'tsc' : is_set(4), # Time Stamp Counter and RDTSC instruction are available
  1665. 'msr' : is_set(5), # Model Specific Registers
  1666. 'pae' : is_set(6), # Physical Address Extensions (36 bit address, 2MB pages)
  1667. 'mce' : is_set(7), # Machine Check Exception supported
  1668. 'cx8' : is_set(8), # Compare Exchange Eight Byte instruction available
  1669. 'apic' : is_set(9), # Local APIC present (multiprocessor operation support)
  1670. 'sepamd' : is_set(10), # Fast system calls (AMD only)
  1671. 'sep' : is_set(11), # Fast system calls
  1672. 'mtrr' : is_set(12), # Memory Type Range Registers
  1673. 'pge' : is_set(13), # Page Global Enable
  1674. 'mca' : is_set(14), # Machine Check Architecture
  1675. 'cmov' : is_set(15), # Conditional MOVe instructions
  1676. 'pat' : is_set(16), # Page Attribute Table
  1677. 'pse36' : is_set(17), # 36 bit Page Size Extensions
  1678. 'serial' : is_set(18), # Processor Serial Number
  1679. 'clflush' : is_set(19), # Cache Flush
  1680. #'reserved1' : is_set(20), # reserved
  1681. 'dts' : is_set(21), # Debug Trace Store
  1682. 'acpi' : is_set(22), # ACPI support
  1683. 'mmx' : is_set(23), # MultiMedia Extensions
  1684. 'fxsr' : is_set(24), # FXSAVE and FXRSTOR instructions
  1685. 'sse' : is_set(25), # SSE instructions
  1686. 'sse2' : is_set(26), # SSE2 (WNI) instructions
  1687. 'ss' : is_set(27), # self snoop
  1688. #'reserved2' : is_set(28), # reserved
  1689. 'tm' : is_set(29), # Automatic clock control
  1690. 'ia64' : is_set(30), # IA64 instructions
  1691. '3dnow' : is_set(31) # 3DNow! instructions available
  1692. }
  1693. # Get a list of only the flags that are true
  1694. flags = [k for k, v in flags.items() if v]
  1695. flags.sort()
  1696. info = {
  1697. 'vendor_id' : vendor_id,
  1698. 'brand' : processor_brand,
  1699. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1700. 'hz_actual' : to_friendly_hz(hz_actual, 6),
  1701. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1702. 'hz_actual_raw' : to_raw_hz(hz_actual, 6),
  1703. 'flags' : flags
  1704. }
  1705. info = {k: v for k, v in info.items() if v}
  1706. return info
  1707. except:
  1708. return {}
  1709. def _get_cpu_info_from_kstat():
  1710. '''
  1711. Returns the CPU info gathered from isainfo and kstat.
  1712. Returns {} if isainfo or kstat are not found.
  1713. '''
  1714. try:
  1715. # Just return {} if there is no isainfo or kstat
  1716. if not DataSource.has_isainfo() or not DataSource.has_kstat():
  1717. return {}
  1718. # If isainfo fails return {}
  1719. returncode, flag_output = DataSource.isainfo_vb()
  1720. if flag_output == None or returncode != 0:
  1721. return {}
  1722. # If kstat fails return {}
  1723. returncode, kstat = DataSource.kstat_m_cpu_info()
  1724. if kstat == None or returncode != 0:
  1725. return {}
  1726. # Various fields
  1727. vendor_id = kstat.split('\tvendor_id ')[1].split('\n')[0].strip()
  1728. processor_brand = kstat.split('\tbrand ')[1].split('\n')[0].strip()
  1729. stepping = int(kstat.split('\tstepping ')[1].split('\n')[0].strip())
  1730. model = int(kstat.split('\tmodel ')[1].split('\n')[0].strip())
  1731. family = int(kstat.split('\tfamily ')[1].split('\n')[0].strip())
  1732. # Flags
  1733. flags = flag_output.strip().split('\n')[-1].strip().lower().split()
  1734. flags.sort()
  1735. # Convert from GHz/MHz string to Hz
  1736. scale = 6
  1737. hz_advertised = kstat.split('\tclock_MHz ')[1].split('\n')[0].strip()
  1738. hz_advertised = to_hz_string(hz_advertised)
  1739. # Convert from GHz/MHz string to Hz
  1740. hz_actual = kstat.split('\tcurrent_clock_Hz ')[1].split('\n')[0].strip()
  1741. hz_actual = to_hz_string(hz_actual)
  1742. info = {
  1743. 'vendor_id' : vendor_id,
  1744. 'brand' : processor_brand,
  1745. 'hz_advertised' : to_friendly_hz(hz_advertised, scale),
  1746. 'hz_actual' : to_friendly_hz(hz_actual, 0),
  1747. 'hz_advertised_raw' : to_raw_hz(hz_advertised, scale),
  1748. 'hz_actual_raw' : to_raw_hz(hz_actual, 0),
  1749. 'stepping' : stepping,
  1750. 'model' : model,
  1751. 'family' : family,
  1752. 'flags' : flags
  1753. }
  1754. info = {k: v for k, v in info.items() if v}
  1755. return info
  1756. except:
  1757. return {}
  1758. def CopyNewFields(info, new_info):
  1759. keys = [
  1760. 'vendor_id', 'hardware', 'brand', 'hz_advertised', 'hz_actual',
  1761. 'hz_advertised_raw', 'hz_actual_raw', 'arch', 'bits', 'count',
  1762. 'raw_arch_string', 'l2_cache_size', 'l2_cache_line_size',
  1763. 'l2_cache_associativity', 'stepping', 'model', 'family',
  1764. 'processor_type', 'extended_model', 'extended_family', 'flags',
  1765. 'l3_cache_size', 'l1_data_cache_size', 'l1_instruction_cache_size'
  1766. ]
  1767. for key in keys:
  1768. if new_info.get(key, None) and not info.get(key, None):
  1769. info[key] = new_info[key]
  1770. elif key == 'flags' and new_info.get('flags'):
  1771. for f in new_info['flags']:
  1772. if f not in info['flags']: info['flags'].append(f)
  1773. info['flags'].sort()
  1774. def get_cpu_info():
  1775. '''
  1776. Returns the CPU info by using the best sources of information for your OS.
  1777. Returns {} if nothing is found.
  1778. '''
  1779. # Get the CPU arch and bits
  1780. arch, bits = parse_arch(DataSource.raw_arch_string)
  1781. friendly_maxsize = { 2**31-1: '32 bit', 2**63-1: '64 bit' }.get(sys.maxsize) or 'unknown bits'
  1782. friendly_version = "{0}.{1}.{2}.{3}.{4}".format(*sys.version_info)
  1783. PYTHON_VERSION = "{0} ({1})".format(friendly_version, friendly_maxsize)
  1784. info = {
  1785. 'python_version' : PYTHON_VERSION,
  1786. 'cpuinfo_version' : CPUINFO_VERSION,
  1787. 'arch' : arch,
  1788. 'bits' : bits,
  1789. 'count' : DataSource.cpu_count,
  1790. 'raw_arch_string' : DataSource.raw_arch_string,
  1791. }
  1792. # Try the Windows wmic
  1793. CopyNewFields(info, _get_cpu_info_from_wmic())
  1794. # Try the Windows registry
  1795. CopyNewFields(info, _get_cpu_info_from_registry())
  1796. # Try /proc/cpuinfo
  1797. CopyNewFields(info, _get_cpu_info_from_proc_cpuinfo())
  1798. # Try cpufreq-info
  1799. CopyNewFields(info, _get_cpu_info_from_cpufreq_info())
  1800. # Try LSCPU
  1801. CopyNewFields(info, _get_cpu_info_from_lscpu())
  1802. # Try sysctl
  1803. CopyNewFields(info, _get_cpu_info_from_sysctl())
  1804. # Try kstat
  1805. CopyNewFields(info, _get_cpu_info_from_kstat())
  1806. # Try dmesg
  1807. CopyNewFields(info, _get_cpu_info_from_dmesg())
  1808. # Try /var/run/dmesg.boot
  1809. CopyNewFields(info, _get_cpu_info_from_cat_var_run_dmesg_boot())
  1810. # Try lsprop ibm,pa-features
  1811. CopyNewFields(info, _get_cpu_info_from_ibm_pa_features())
  1812. # Try sysinfo
  1813. CopyNewFields(info, _get_cpu_info_from_sysinfo())
  1814. # Try querying the CPU cpuid register
  1815. CopyNewFields(info, _get_cpu_info_from_cpuid())
  1816. return info
  1817. # Make sure we are running on a supported system
  1818. def _check_arch():
  1819. arch, bits = parse_arch(DataSource.raw_arch_string)
  1820. if not arch in ['X86_32', 'X86_64', 'ARM_7', 'ARM_8', 'PPC_64']:
  1821. raise Exception("py-cpuinfo currently only works on X86 and some PPC and ARM CPUs.")
  1822. def main():
  1823. try:
  1824. _check_arch()
  1825. except Exception as err:
  1826. sys.stderr.write(str(err) + "\n")
  1827. sys.exit(1)
  1828. info = get_cpu_info()
  1829. if info:
  1830. print('Python Version: {0}'.format(info.get('python_version', '')))
  1831. print('Cpuinfo Version: {0}'.format(info.get('cpuinfo_version', '')))
  1832. print('Vendor ID: {0}'.format(info.get('vendor_id', '')))
  1833. print('Hardware Raw: {0}'.format(info.get('hardware', '')))
  1834. print('Brand: {0}'.format(info.get('brand', '')))
  1835. print('Hz Advertised: {0}'.format(info.get('hz_advertised', '')))
  1836. print('Hz Actual: {0}'.format(info.get('hz_actual', '')))
  1837. print('Hz Advertised Raw: {0}'.format(info.get('hz_advertised_raw', '')))
  1838. print('Hz Actual Raw: {0}'.format(info.get('hz_actual_raw', '')))
  1839. print('Arch: {0}'.format(info.get('arch', '')))
  1840. print('Bits: {0}'.format(info.get('bits', '')))
  1841. print('Count: {0}'.format(info.get('count', '')))
  1842. print('Raw Arch String: {0}'.format(info.get('raw_arch_string', '')))
  1843. print('L1 Data Cache Size: {0}'.format(info.get('l1_data_cache_size', '')))
  1844. print('L1 Instruction Cache Size: {0}'.format(info.get('l1_instruction_cache_size', '')))
  1845. print('L2 Cache Size: {0}'.format(info.get('l2_cache_size', '')))
  1846. print('L2 Cache Line Size: {0}'.format(info.get('l2_cache_line_size', '')))
  1847. print('L2 Cache Associativity: {0}'.format(info.get('l2_cache_associativity', '')))
  1848. print('L3 Cache Size: {0}'.format(info.get('l3_cache_size', '')))
  1849. print('Stepping: {0}'.format(info.get('stepping', '')))
  1850. print('Model: {0}'.format(info.get('model', '')))
  1851. print('Family: {0}'.format(info.get('family', '')))
  1852. print('Processor Type: {0}'.format(info.get('processor_type', '')))
  1853. print('Extended Model: {0}'.format(info.get('extended_model', '')))
  1854. print('Extended Family: {0}'.format(info.get('extended_family', '')))
  1855. print('Flags: {0}'.format(', '.join(info.get('flags', ''))))
  1856. else:
  1857. sys.stderr.write("Failed to find cpu info\n")
  1858. sys.exit(1)
  1859. if __name__ == '__main__':
  1860. from multiprocessing import freeze_support
  1861. freeze_support()
  1862. main()
  1863. else:
  1864. _check_arch()