cpuinfo.py 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827
  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3. # Copyright (c) 2014-2022 Matthew Brennan Jones <matthew.brennan.jones@gmail.com>
  4. # Py-cpuinfo gets CPU info with pure Python
  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 = (9, 0, 0)
  27. CPUINFO_VERSION_STRING = '.'.join([str(n) for n in CPUINFO_VERSION])
  28. import os, sys
  29. import platform
  30. import multiprocessing
  31. import ctypes
  32. CAN_CALL_CPUID_IN_SUBPROCESS = True
  33. g_trace = None
  34. class Trace(object):
  35. def __init__(self, is_active, is_stored_in_string):
  36. self._is_active = is_active
  37. if not self._is_active:
  38. return
  39. from datetime import datetime
  40. from io import StringIO
  41. if is_stored_in_string:
  42. self._output = StringIO()
  43. else:
  44. date = datetime.now().strftime("%Y-%m-%d_%H-%M-%S-%f")
  45. self._output = open('cpuinfo_trace_{0}.trace'.format(date), 'w')
  46. self._stdout = StringIO()
  47. self._stderr = StringIO()
  48. self._err = None
  49. def header(self, msg):
  50. if not self._is_active: return
  51. from inspect import stack
  52. frame = stack()[1]
  53. file = frame[1]
  54. line = frame[2]
  55. self._output.write("{0} ({1} {2})\n".format(msg, file, line))
  56. self._output.flush()
  57. def success(self):
  58. if not self._is_active: return
  59. from inspect import stack
  60. frame = stack()[1]
  61. file = frame[1]
  62. line = frame[2]
  63. self._output.write("Success ... ({0} {1})\n\n".format(file, line))
  64. self._output.flush()
  65. def fail(self, msg):
  66. if not self._is_active: return
  67. from inspect import stack
  68. frame = stack()[1]
  69. file = frame[1]
  70. line = frame[2]
  71. if isinstance(msg, str):
  72. msg = ''.join(['\t' + line for line in msg.split('\n')]) + '\n'
  73. self._output.write(msg)
  74. self._output.write("Failed ... ({0} {1})\n\n".format(file, line))
  75. self._output.flush()
  76. elif isinstance(msg, Exception):
  77. from traceback import format_exc
  78. err_string = format_exc()
  79. self._output.write("\tFailed ... ({0} {1})\n".format(file, line))
  80. self._output.write(''.join(['\t\t{0}\n'.format(n) for n in err_string.split('\n')]) + '\n')
  81. self._output.flush()
  82. def command_header(self, msg):
  83. if not self._is_active: return
  84. from inspect import stack
  85. frame = stack()[3]
  86. file = frame[1]
  87. line = frame[2]
  88. self._output.write("\t{0} ({1} {2})\n".format(msg, file, line))
  89. self._output.flush()
  90. def command_output(self, msg, output):
  91. if not self._is_active: return
  92. self._output.write("\t\t{0}\n".format(msg))
  93. self._output.write(''.join(['\t\t\t{0}\n'.format(n) for n in output.split('\n')]) + '\n')
  94. self._output.flush()
  95. def keys(self, keys, info, new_info):
  96. if not self._is_active: return
  97. from inspect import stack
  98. frame = stack()[2]
  99. file = frame[1]
  100. line = frame[2]
  101. # List updated keys
  102. self._output.write("\tChanged keys ({0} {1})\n".format(file, line))
  103. changed_keys = [key for key in keys if key in info and key in new_info and info[key] != new_info[key]]
  104. if changed_keys:
  105. for key in changed_keys:
  106. self._output.write('\t\t{0}: {1} to {2}\n'.format(key, info[key], new_info[key]))
  107. else:
  108. self._output.write('\t\tNone\n')
  109. # List new keys
  110. self._output.write("\tNew keys ({0} {1})\n".format(file, line))
  111. new_keys = [key for key in keys if key in new_info and key not in info]
  112. if new_keys:
  113. for key in new_keys:
  114. self._output.write('\t\t{0}: {1}\n'.format(key, new_info[key]))
  115. else:
  116. self._output.write('\t\tNone\n')
  117. self._output.write('\n')
  118. self._output.flush()
  119. def write(self, msg):
  120. if not self._is_active: return
  121. self._output.write(msg + '\n')
  122. self._output.flush()
  123. def to_dict(self, info, is_fail):
  124. return {
  125. 'output' : self._output.getvalue(),
  126. 'stdout' : self._stdout.getvalue(),
  127. 'stderr' : self._stderr.getvalue(),
  128. 'info' : info,
  129. 'err' : self._err,
  130. 'is_fail' : is_fail
  131. }
  132. class DataSource(object):
  133. bits = platform.architecture()[0]
  134. cpu_count = multiprocessing.cpu_count()
  135. is_windows = platform.system().lower() == 'windows'
  136. arch_string_raw = platform.machine()
  137. uname_string_raw = platform.uname()[5]
  138. can_cpuid = True
  139. @staticmethod
  140. def has_proc_cpuinfo():
  141. return os.path.exists('/proc/cpuinfo')
  142. @staticmethod
  143. def has_dmesg():
  144. return len(_program_paths('dmesg')) > 0
  145. @staticmethod
  146. def has_var_run_dmesg_boot():
  147. uname = platform.system().strip().strip('"').strip("'").strip().lower()
  148. return 'linux' in uname and os.path.exists('/var/run/dmesg.boot')
  149. @staticmethod
  150. def has_cpufreq_info():
  151. return len(_program_paths('cpufreq-info')) > 0
  152. @staticmethod
  153. def has_sestatus():
  154. return len(_program_paths('sestatus')) > 0
  155. @staticmethod
  156. def has_sysctl():
  157. return len(_program_paths('sysctl')) > 0
  158. @staticmethod
  159. def has_isainfo():
  160. return len(_program_paths('isainfo')) > 0
  161. @staticmethod
  162. def has_kstat():
  163. return len(_program_paths('kstat')) > 0
  164. @staticmethod
  165. def has_sysinfo():
  166. uname = platform.system().strip().strip('"').strip("'").strip().lower()
  167. is_beos = 'beos' in uname or 'haiku' in uname
  168. return is_beos and len(_program_paths('sysinfo')) > 0
  169. @staticmethod
  170. def has_lscpu():
  171. return len(_program_paths('lscpu')) > 0
  172. @staticmethod
  173. def has_ibm_pa_features():
  174. return len(_program_paths('lsprop')) > 0
  175. @staticmethod
  176. def has_wmic():
  177. returncode, output = _run_and_get_stdout(['wmic', 'os', 'get', 'Version'])
  178. return returncode == 0 and len(output) > 0
  179. @staticmethod
  180. def cat_proc_cpuinfo():
  181. return _run_and_get_stdout(['cat', '/proc/cpuinfo'])
  182. @staticmethod
  183. def cpufreq_info():
  184. return _run_and_get_stdout(['cpufreq-info'])
  185. @staticmethod
  186. def sestatus_b():
  187. return _run_and_get_stdout(['sestatus', '-b'])
  188. @staticmethod
  189. def dmesg_a():
  190. return _run_and_get_stdout(['dmesg', '-a'])
  191. @staticmethod
  192. def cat_var_run_dmesg_boot():
  193. return _run_and_get_stdout(['cat', '/var/run/dmesg.boot'])
  194. @staticmethod
  195. def sysctl_machdep_cpu_hw_cpufrequency():
  196. return _run_and_get_stdout(['sysctl', 'machdep.cpu', 'hw.cpufrequency'])
  197. @staticmethod
  198. def isainfo_vb():
  199. return _run_and_get_stdout(['isainfo', '-vb'])
  200. @staticmethod
  201. def kstat_m_cpu_info():
  202. return _run_and_get_stdout(['kstat', '-m', 'cpu_info'])
  203. @staticmethod
  204. def sysinfo_cpu():
  205. return _run_and_get_stdout(['sysinfo', '-cpu'])
  206. @staticmethod
  207. def lscpu():
  208. return _run_and_get_stdout(['lscpu'])
  209. @staticmethod
  210. def ibm_pa_features():
  211. import glob
  212. ibm_features = glob.glob('/proc/device-tree/cpus/*/ibm,pa-features')
  213. if ibm_features:
  214. return _run_and_get_stdout(['lsprop', ibm_features[0]])
  215. @staticmethod
  216. def wmic_cpu():
  217. return _run_and_get_stdout(['wmic', 'cpu', 'get', 'Name,CurrentClockSpeed,L2CacheSize,L3CacheSize,Description,Caption,Manufacturer', '/format:list'])
  218. @staticmethod
  219. def winreg_processor_brand():
  220. processor_brand = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "ProcessorNameString")
  221. return processor_brand.strip()
  222. @staticmethod
  223. def winreg_vendor_id_raw():
  224. vendor_id_raw = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "VendorIdentifier")
  225. return vendor_id_raw
  226. @staticmethod
  227. def winreg_arch_string_raw():
  228. arch_string_raw = _read_windows_registry_key(r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", "PROCESSOR_ARCHITECTURE")
  229. return arch_string_raw
  230. @staticmethod
  231. def winreg_hz_actual():
  232. hz_actual = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "~Mhz")
  233. hz_actual = _to_decimal_string(hz_actual)
  234. return hz_actual
  235. @staticmethod
  236. def winreg_feature_bits():
  237. feature_bits = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "FeatureSet")
  238. return feature_bits
  239. def _program_paths(program_name):
  240. paths = []
  241. exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
  242. for p in os.environ['PATH'].split(os.pathsep):
  243. p = os.path.join(p, program_name)
  244. if os.access(p, os.X_OK):
  245. paths.append(p)
  246. for e in exts:
  247. pext = p + e
  248. if os.access(pext, os.X_OK):
  249. paths.append(pext)
  250. return paths
  251. def _run_and_get_stdout(command, pipe_command=None):
  252. from subprocess import Popen, PIPE
  253. g_trace.command_header('Running command "' + ' '.join(command) + '" ...')
  254. # Run the command normally
  255. if not pipe_command:
  256. p1 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
  257. # Run the command and pipe it into another command
  258. else:
  259. p2 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
  260. p1 = Popen(pipe_command, stdin=p2.stdout, stdout=PIPE, stderr=PIPE)
  261. p2.stdout.close()
  262. # Get the stdout and stderr
  263. stdout_output, stderr_output = p1.communicate()
  264. stdout_output = stdout_output.decode(encoding='UTF-8')
  265. stderr_output = stderr_output.decode(encoding='UTF-8')
  266. # Send the result to the logger
  267. g_trace.command_output('return code:', str(p1.returncode))
  268. g_trace.command_output('stdout:', stdout_output)
  269. # Return the return code and stdout
  270. return p1.returncode, stdout_output
  271. def _read_windows_registry_key(key_name, field_name):
  272. g_trace.command_header('Reading Registry key "{0}" field "{1}" ...'.format(key_name, field_name))
  273. try:
  274. import _winreg as winreg
  275. except ImportError as err:
  276. try:
  277. import winreg
  278. except ImportError as err:
  279. pass
  280. key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_name)
  281. value = winreg.QueryValueEx(key, field_name)[0]
  282. winreg.CloseKey(key)
  283. g_trace.command_output('value:', str(value))
  284. return value
  285. # Make sure we are running on a supported system
  286. def _check_arch():
  287. arch, bits = _parse_arch(DataSource.arch_string_raw)
  288. if not arch in ['X86_32', 'X86_64', 'ARM_7', 'ARM_8',
  289. 'PPC_64', 'S390X', 'MIPS_32', 'MIPS_64',
  290. "RISCV_32", "RISCV_64"]:
  291. raise Exception("py-cpuinfo currently only works on X86 "
  292. "and some ARM/PPC/S390X/MIPS/RISCV CPUs.")
  293. def _obj_to_b64(thing):
  294. import pickle
  295. import base64
  296. a = thing
  297. b = pickle.dumps(a)
  298. c = base64.b64encode(b)
  299. d = c.decode('utf8')
  300. return d
  301. def _b64_to_obj(thing):
  302. import pickle
  303. import base64
  304. try:
  305. a = base64.b64decode(thing)
  306. b = pickle.loads(a)
  307. return b
  308. except Exception:
  309. return {}
  310. def _utf_to_str(input):
  311. if isinstance(input, list):
  312. return [_utf_to_str(element) for element in input]
  313. elif isinstance(input, dict):
  314. return {_utf_to_str(key): _utf_to_str(value)
  315. for key, value in input.items()}
  316. else:
  317. return input
  318. def _copy_new_fields(info, new_info):
  319. keys = [
  320. 'vendor_id_raw', 'hardware_raw', 'brand_raw', 'hz_advertised_friendly', 'hz_actual_friendly',
  321. 'hz_advertised', 'hz_actual', 'arch', 'bits', 'count',
  322. 'arch_string_raw', 'uname_string_raw',
  323. 'l2_cache_size', 'l2_cache_line_size', 'l2_cache_associativity',
  324. 'stepping', 'model', 'family',
  325. 'processor_type', 'flags',
  326. 'l3_cache_size', 'l1_data_cache_size', 'l1_instruction_cache_size'
  327. ]
  328. g_trace.keys(keys, info, new_info)
  329. # Update the keys with new values
  330. for key in keys:
  331. if new_info.get(key, None) and not info.get(key, None):
  332. info[key] = new_info[key]
  333. elif key == 'flags' and new_info.get('flags'):
  334. for f in new_info['flags']:
  335. if f not in info['flags']: info['flags'].append(f)
  336. info['flags'].sort()
  337. def _get_field_actual(cant_be_number, raw_string, field_names):
  338. for line in raw_string.splitlines():
  339. for field_name in field_names:
  340. field_name = field_name.lower()
  341. if ':' in line:
  342. left, right = line.split(':', 1)
  343. left = left.strip().lower()
  344. right = right.strip()
  345. if left == field_name and len(right) > 0:
  346. if cant_be_number:
  347. if not right.isdigit():
  348. return right
  349. else:
  350. return right
  351. return None
  352. def _get_field(cant_be_number, raw_string, convert_to, default_value, *field_names):
  353. retval = _get_field_actual(cant_be_number, raw_string, field_names)
  354. # Convert the return value
  355. if retval and convert_to:
  356. try:
  357. retval = convert_to(retval)
  358. except Exception:
  359. retval = default_value
  360. # Return the default if there is no return value
  361. if retval is None:
  362. retval = default_value
  363. return retval
  364. def _to_decimal_string(ticks):
  365. try:
  366. # Convert to string
  367. ticks = '{0}'.format(ticks)
  368. # Sometimes ',' is used as a decimal separator
  369. ticks = ticks.replace(',', '.')
  370. # Strip off non numbers and decimal places
  371. ticks = "".join(n for n in ticks if n.isdigit() or n=='.').strip()
  372. if ticks == '':
  373. ticks = '0'
  374. # Add decimal if missing
  375. if '.' not in ticks:
  376. ticks = '{0}.0'.format(ticks)
  377. # Remove trailing zeros
  378. ticks = ticks.rstrip('0')
  379. # Add one trailing zero for empty right side
  380. if ticks.endswith('.'):
  381. ticks = '{0}0'.format(ticks)
  382. # Make sure the number can be converted to a float
  383. ticks = float(ticks)
  384. ticks = '{0}'.format(ticks)
  385. return ticks
  386. except Exception:
  387. return '0.0'
  388. def _hz_short_to_full(ticks, scale):
  389. try:
  390. # Make sure the number can be converted to a float
  391. ticks = float(ticks)
  392. ticks = '{0}'.format(ticks)
  393. # Scale the numbers
  394. hz = ticks.lstrip('0')
  395. old_index = hz.index('.')
  396. hz = hz.replace('.', '')
  397. hz = hz.ljust(scale + old_index+1, '0')
  398. new_index = old_index + scale
  399. hz = '{0}.{1}'.format(hz[:new_index], hz[new_index:])
  400. left, right = hz.split('.')
  401. left, right = int(left), int(right)
  402. return (left, right)
  403. except Exception:
  404. return (0, 0)
  405. def _hz_friendly_to_full(hz_string):
  406. try:
  407. hz_string = hz_string.strip().lower()
  408. hz, scale = (None, None)
  409. if hz_string.endswith('ghz'):
  410. scale = 9
  411. elif hz_string.endswith('mhz'):
  412. scale = 6
  413. elif hz_string.endswith('hz'):
  414. scale = 0
  415. hz = "".join(n for n in hz_string if n.isdigit() or n=='.').strip()
  416. if not '.' in hz:
  417. hz += '.0'
  418. hz, scale = _hz_short_to_full(hz, scale)
  419. return (hz, scale)
  420. except Exception:
  421. return (0, 0)
  422. def _hz_short_to_friendly(ticks, scale):
  423. try:
  424. # Get the raw Hz as a string
  425. left, right = _hz_short_to_full(ticks, scale)
  426. result = '{0}.{1}'.format(left, right)
  427. # Get the location of the dot, and remove said dot
  428. dot_index = result.index('.')
  429. result = result.replace('.', '')
  430. # Get the Hz symbol and scale
  431. symbol = "Hz"
  432. scale = 0
  433. if dot_index > 9:
  434. symbol = "GHz"
  435. scale = 9
  436. elif dot_index > 6:
  437. symbol = "MHz"
  438. scale = 6
  439. elif dot_index > 3:
  440. symbol = "KHz"
  441. scale = 3
  442. # Get the Hz with the dot at the new scaled point
  443. result = '{0}.{1}'.format(result[:-scale-1], result[-scale-1:])
  444. # Format the ticks to have 4 numbers after the decimal
  445. # and remove any superfluous zeroes.
  446. result = '{0:.4f} {1}'.format(float(result), symbol)
  447. result = result.rstrip('0')
  448. return result
  449. except Exception:
  450. return '0.0000 Hz'
  451. def _to_friendly_bytes(input):
  452. import re
  453. if not input:
  454. return input
  455. input = "{0}".format(input)
  456. formats = {
  457. r"^[0-9]+B$" : 'B',
  458. r"^[0-9]+K$" : 'KB',
  459. r"^[0-9]+M$" : 'MB',
  460. r"^[0-9]+G$" : 'GB'
  461. }
  462. for pattern, friendly_size in formats.items():
  463. if re.match(pattern, input):
  464. return "{0} {1}".format(input[ : -1].strip(), friendly_size)
  465. return input
  466. def _friendly_bytes_to_int(friendly_bytes):
  467. input = friendly_bytes.lower()
  468. formats = [
  469. {'gib' : 1024 * 1024 * 1024},
  470. {'mib' : 1024 * 1024},
  471. {'kib' : 1024},
  472. {'gb' : 1024 * 1024 * 1024},
  473. {'mb' : 1024 * 1024},
  474. {'kb' : 1024},
  475. {'g' : 1024 * 1024 * 1024},
  476. {'m' : 1024 * 1024},
  477. {'k' : 1024},
  478. {'b' : 1},
  479. ]
  480. try:
  481. for entry in formats:
  482. pattern = list(entry.keys())[0]
  483. multiplier = list(entry.values())[0]
  484. if input.endswith(pattern):
  485. return int(input.split(pattern)[0].strip()) * multiplier
  486. except Exception as err:
  487. pass
  488. return friendly_bytes
  489. def _parse_cpu_brand_string(cpu_string):
  490. # Just return 0 if the processor brand does not have the Hz
  491. if not 'hz' in cpu_string.lower():
  492. return ('0.0', 0)
  493. hz = cpu_string.lower()
  494. scale = 0
  495. if hz.endswith('mhz'):
  496. scale = 6
  497. elif hz.endswith('ghz'):
  498. scale = 9
  499. if '@' in hz:
  500. hz = hz.split('@')[1]
  501. else:
  502. hz = hz.rsplit(None, 1)[1]
  503. hz = hz.rstrip('mhz').rstrip('ghz').strip()
  504. hz = _to_decimal_string(hz)
  505. return (hz, scale)
  506. def _parse_cpu_brand_string_dx(cpu_string):
  507. import re
  508. # Find all the strings inside brackets ()
  509. starts = [m.start() for m in re.finditer(r"\(", cpu_string)]
  510. ends = [m.start() for m in re.finditer(r"\)", cpu_string)]
  511. insides = {k: v for k, v in zip(starts, ends)}
  512. insides = [cpu_string[start+1 : end] for start, end in insides.items()]
  513. # Find all the fields
  514. vendor_id, stepping, model, family = (None, None, None, None)
  515. for inside in insides:
  516. for pair in inside.split(','):
  517. pair = [n.strip() for n in pair.split(':')]
  518. if len(pair) > 1:
  519. name, value = pair[0], pair[1]
  520. if name == 'origin':
  521. vendor_id = value.strip('"')
  522. elif name == 'stepping':
  523. stepping = int(value.lstrip('0x'), 16)
  524. elif name == 'model':
  525. model = int(value.lstrip('0x'), 16)
  526. elif name in ['fam', 'family']:
  527. family = int(value.lstrip('0x'), 16)
  528. # Find the Processor Brand
  529. # Strip off extra strings in brackets at end
  530. brand = cpu_string.strip()
  531. is_working = True
  532. while is_working:
  533. is_working = False
  534. for inside in insides:
  535. full = "({0})".format(inside)
  536. if brand.endswith(full):
  537. brand = brand[ :-len(full)].strip()
  538. is_working = True
  539. # Find the Hz in the brand string
  540. hz_brand, scale = _parse_cpu_brand_string(brand)
  541. # Find Hz inside brackets () after the brand string
  542. if hz_brand == '0.0':
  543. for inside in insides:
  544. hz = inside
  545. for entry in ['GHz', 'MHz', 'Hz']:
  546. if entry in hz:
  547. hz = "CPU @ " + hz[ : hz.find(entry) + len(entry)]
  548. hz_brand, scale = _parse_cpu_brand_string(hz)
  549. break
  550. return (hz_brand, scale, brand, vendor_id, stepping, model, family)
  551. def _parse_dmesg_output(output):
  552. try:
  553. # Get all the dmesg lines that might contain a CPU string
  554. lines = output.split(' CPU0:')[1:] + \
  555. output.split(' CPU1:')[1:] + \
  556. output.split(' CPU:')[1:] + \
  557. output.split('\nCPU0:')[1:] + \
  558. output.split('\nCPU1:')[1:] + \
  559. output.split('\nCPU:')[1:]
  560. lines = [l.split('\n')[0].strip() for l in lines]
  561. # Convert the lines to CPU strings
  562. cpu_strings = [_parse_cpu_brand_string_dx(l) for l in lines]
  563. # Find the CPU string that has the most fields
  564. best_string = None
  565. highest_count = 0
  566. for cpu_string in cpu_strings:
  567. count = sum([n is not None for n in cpu_string])
  568. if count > highest_count:
  569. highest_count = count
  570. best_string = cpu_string
  571. # If no CPU string was found, return {}
  572. if not best_string:
  573. return {}
  574. hz_actual, scale, processor_brand, vendor_id, stepping, model, family = best_string
  575. # Origin
  576. if ' Origin=' in output:
  577. fields = output[output.find(' Origin=') : ].split('\n')[0]
  578. fields = fields.strip().split()
  579. fields = [n.strip().split('=') for n in fields]
  580. fields = [{n[0].strip().lower() : n[1].strip()} for n in fields]
  581. for field in fields:
  582. name = list(field.keys())[0]
  583. value = list(field.values())[0]
  584. if name == 'origin':
  585. vendor_id = value.strip('"')
  586. elif name == 'stepping':
  587. stepping = int(value.lstrip('0x'), 16)
  588. elif name == 'model':
  589. model = int(value.lstrip('0x'), 16)
  590. elif name in ['fam', 'family']:
  591. family = int(value.lstrip('0x'), 16)
  592. # Features
  593. flag_lines = []
  594. for category in [' Features=', ' Features2=', ' AMD Features=', ' AMD Features2=']:
  595. if category in output:
  596. flag_lines.append(output.split(category)[1].split('\n')[0])
  597. flags = []
  598. for line in flag_lines:
  599. line = line.split('<')[1].split('>')[0].lower()
  600. for flag in line.split(','):
  601. flags.append(flag)
  602. flags.sort()
  603. # Convert from GHz/MHz string to Hz
  604. hz_advertised, scale = _parse_cpu_brand_string(processor_brand)
  605. # If advertised hz not found, use the actual hz
  606. if hz_advertised == '0.0':
  607. scale = 6
  608. hz_advertised = _to_decimal_string(hz_actual)
  609. info = {
  610. 'vendor_id_raw' : vendor_id,
  611. 'brand_raw' : processor_brand,
  612. 'stepping' : stepping,
  613. 'model' : model,
  614. 'family' : family,
  615. 'flags' : flags
  616. }
  617. if hz_advertised and hz_advertised != '0.0':
  618. info['hz_advertised_friendly'] = _hz_short_to_friendly(hz_advertised, scale)
  619. info['hz_actual_friendly'] = _hz_short_to_friendly(hz_actual, scale)
  620. if hz_advertised and hz_advertised != '0.0':
  621. info['hz_advertised'] = _hz_short_to_full(hz_advertised, scale)
  622. info['hz_actual'] = _hz_short_to_full(hz_actual, scale)
  623. return {k: v for k, v in info.items() if v}
  624. except Exception as err:
  625. g_trace.fail(err)
  626. #raise
  627. return {}
  628. def _parse_arch(arch_string_raw):
  629. import re
  630. arch, bits = None, None
  631. arch_string_raw = arch_string_raw.lower()
  632. # X86
  633. if re.match(r'^i\d86$|^x86$|^x86_32$|^i86pc$|^ia32$|^ia-32$|^bepc$', arch_string_raw):
  634. arch = 'X86_32'
  635. bits = 32
  636. elif re.match(r'^x64$|^x86_64$|^x86_64t$|^i686-64$|^amd64$|^ia64$|^ia-64$', arch_string_raw):
  637. arch = 'X86_64'
  638. bits = 64
  639. # ARM
  640. elif re.match(r'^armv8-a|aarch64|arm64$', arch_string_raw):
  641. arch = 'ARM_8'
  642. bits = 64
  643. elif re.match(r'^armv7$|^armv7[a-z]$|^armv7-[a-z]$|^armv6[a-z]$', arch_string_raw):
  644. arch = 'ARM_7'
  645. bits = 32
  646. elif re.match(r'^armv8$|^armv8[a-z]$|^armv8-[a-z]$', arch_string_raw):
  647. arch = 'ARM_8'
  648. bits = 32
  649. # PPC
  650. elif re.match(r'^ppc32$|^prep$|^pmac$|^powermac$', arch_string_raw):
  651. arch = 'PPC_32'
  652. bits = 32
  653. elif re.match(r'^powerpc$|^ppc64$|^ppc64le$', arch_string_raw):
  654. arch = 'PPC_64'
  655. bits = 64
  656. # SPARC
  657. elif re.match(r'^sparc32$|^sparc$', arch_string_raw):
  658. arch = 'SPARC_32'
  659. bits = 32
  660. elif re.match(r'^sparc64$|^sun4u$|^sun4v$', arch_string_raw):
  661. arch = 'SPARC_64'
  662. bits = 64
  663. # S390X
  664. elif re.match(r'^s390x$', arch_string_raw):
  665. arch = 'S390X'
  666. bits = 64
  667. elif arch_string_raw == 'mips':
  668. arch = 'MIPS_32'
  669. bits = 32
  670. elif arch_string_raw == 'mips64':
  671. arch = 'MIPS_64'
  672. bits = 64
  673. # RISCV
  674. elif re.match(r'^riscv$|^riscv32$|^riscv32be$', arch_string_raw):
  675. arch = 'RISCV_32'
  676. bits = 32
  677. elif re.match(r'^riscv64$|^riscv64be$', arch_string_raw):
  678. arch = 'RISCV_64'
  679. bits = 64
  680. return (arch, bits)
  681. def _is_bit_set(reg, bit):
  682. mask = 1 << bit
  683. is_set = reg & mask > 0
  684. return is_set
  685. def _is_selinux_enforcing(trace):
  686. # Just return if the SE Linux Status Tool is not installed
  687. if not DataSource.has_sestatus():
  688. trace.fail('Failed to find sestatus.')
  689. return False
  690. # Run the sestatus, and just return if it failed to run
  691. returncode, output = DataSource.sestatus_b()
  692. if returncode != 0:
  693. trace.fail('Failed to run sestatus. Skipping ...')
  694. return False
  695. # Figure out if explicitly in enforcing mode
  696. for line in output.splitlines():
  697. line = line.strip().lower()
  698. if line.startswith("current mode:"):
  699. if line.endswith("enforcing"):
  700. return True
  701. else:
  702. return False
  703. # Figure out if we can execute heap and execute memory
  704. can_selinux_exec_heap = False
  705. can_selinux_exec_memory = False
  706. for line in output.splitlines():
  707. line = line.strip().lower()
  708. if line.startswith("allow_execheap") and line.endswith("on"):
  709. can_selinux_exec_heap = True
  710. elif line.startswith("allow_execmem") and line.endswith("on"):
  711. can_selinux_exec_memory = True
  712. trace.command_output('can_selinux_exec_heap:', can_selinux_exec_heap)
  713. trace.command_output('can_selinux_exec_memory:', can_selinux_exec_memory)
  714. return (not can_selinux_exec_heap or not can_selinux_exec_memory)
  715. def _filter_dict_keys_with_empty_values(info, acceptable_values = {}):
  716. filtered_info = {}
  717. for key in info:
  718. value = info[key]
  719. # Keep if value is acceptable
  720. if key in acceptable_values:
  721. if acceptable_values[key] == value:
  722. filtered_info[key] = value
  723. continue
  724. # Filter out None, 0, "", (), {}, []
  725. if not value:
  726. continue
  727. # Filter out (0, 0)
  728. if value == (0, 0):
  729. continue
  730. # Filter out -1
  731. if value == -1:
  732. continue
  733. # Filter out strings that start with "0.0"
  734. if type(value) == str and value.startswith('0.0'):
  735. continue
  736. filtered_info[key] = value
  737. return filtered_info
  738. class ASM(object):
  739. def __init__(self, restype=None, argtypes=(), machine_code=[]):
  740. self.restype = restype
  741. self.argtypes = argtypes
  742. self.machine_code = machine_code
  743. self.prochandle = None
  744. self.mm = None
  745. self.func = None
  746. self.address = None
  747. self.size = 0
  748. def compile(self):
  749. machine_code = bytes.join(b'', self.machine_code)
  750. self.size = ctypes.c_size_t(len(machine_code))
  751. if DataSource.is_windows:
  752. # Allocate a memory segment the size of the machine code, and make it executable
  753. size = len(machine_code)
  754. # Alloc at least 1 page to ensure we own all pages that we want to change protection on
  755. if size < 0x1000: size = 0x1000
  756. MEM_COMMIT = ctypes.c_ulong(0x1000)
  757. PAGE_READWRITE = ctypes.c_ulong(0x4)
  758. pfnVirtualAlloc = ctypes.windll.kernel32.VirtualAlloc
  759. pfnVirtualAlloc.restype = ctypes.c_void_p
  760. self.address = pfnVirtualAlloc(None, ctypes.c_size_t(size), MEM_COMMIT, PAGE_READWRITE)
  761. if not self.address:
  762. raise Exception("Failed to VirtualAlloc")
  763. # Copy the machine code into the memory segment
  764. memmove = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)(ctypes._memmove_addr)
  765. if memmove(self.address, machine_code, size) < 0:
  766. raise Exception("Failed to memmove")
  767. # Enable execute permissions
  768. PAGE_EXECUTE = ctypes.c_ulong(0x10)
  769. old_protect = ctypes.c_ulong(0)
  770. pfnVirtualProtect = ctypes.windll.kernel32.VirtualProtect
  771. res = pfnVirtualProtect(ctypes.c_void_p(self.address), ctypes.c_size_t(size), PAGE_EXECUTE, ctypes.byref(old_protect))
  772. if not res:
  773. raise Exception("Failed VirtualProtect")
  774. # Flush Instruction Cache
  775. # First, get process Handle
  776. if not self.prochandle:
  777. pfnGetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
  778. pfnGetCurrentProcess.restype = ctypes.c_void_p
  779. self.prochandle = ctypes.c_void_p(pfnGetCurrentProcess())
  780. # Actually flush cache
  781. res = ctypes.windll.kernel32.FlushInstructionCache(self.prochandle, ctypes.c_void_p(self.address), ctypes.c_size_t(size))
  782. if not res:
  783. raise Exception("Failed FlushInstructionCache")
  784. else:
  785. from mmap import mmap, MAP_PRIVATE, MAP_ANONYMOUS, PROT_WRITE, PROT_READ, PROT_EXEC
  786. # Allocate a private and executable memory segment the size of the machine code
  787. machine_code = bytes.join(b'', self.machine_code)
  788. self.size = len(machine_code)
  789. self.mm = mmap(-1, self.size, flags=MAP_PRIVATE | MAP_ANONYMOUS, prot=PROT_WRITE | PROT_READ | PROT_EXEC)
  790. # Copy the machine code into the memory segment
  791. self.mm.write(machine_code)
  792. self.address = ctypes.addressof(ctypes.c_int.from_buffer(self.mm))
  793. # Cast the memory segment into a function
  794. functype = ctypes.CFUNCTYPE(self.restype, *self.argtypes)
  795. self.func = functype(self.address)
  796. def run(self):
  797. # Call the machine code like a function
  798. retval = self.func()
  799. return retval
  800. def free(self):
  801. # Free the function memory segment
  802. if DataSource.is_windows:
  803. MEM_RELEASE = ctypes.c_ulong(0x8000)
  804. ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(self.address), ctypes.c_size_t(0), MEM_RELEASE)
  805. else:
  806. self.mm.close()
  807. self.prochandle = None
  808. self.mm = None
  809. self.func = None
  810. self.address = None
  811. self.size = 0
  812. class CPUID(object):
  813. def __init__(self, trace=None):
  814. if trace is None:
  815. trace = Trace(False, False)
  816. # Figure out if SE Linux is on and in enforcing mode
  817. self.is_selinux_enforcing = _is_selinux_enforcing(trace)
  818. def _asm_func(self, restype=None, argtypes=(), machine_code=[]):
  819. asm = ASM(restype, argtypes, machine_code)
  820. asm.compile()
  821. return asm
  822. def _run_asm(self, *machine_code):
  823. asm = ASM(ctypes.c_uint32, (), machine_code)
  824. asm.compile()
  825. retval = asm.run()
  826. asm.free()
  827. return retval
  828. # http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
  829. def get_vendor_id(self):
  830. # EBX
  831. ebx = self._run_asm(
  832. b"\x31\xC0", # xor eax,eax
  833. b"\x0F\xA2" # cpuid
  834. b"\x89\xD8" # mov ax,bx
  835. b"\xC3" # ret
  836. )
  837. # ECX
  838. ecx = self._run_asm(
  839. b"\x31\xC0", # xor eax,eax
  840. b"\x0f\xa2" # cpuid
  841. b"\x89\xC8" # mov ax,cx
  842. b"\xC3" # ret
  843. )
  844. # EDX
  845. edx = self._run_asm(
  846. b"\x31\xC0", # xor eax,eax
  847. b"\x0f\xa2" # cpuid
  848. b"\x89\xD0" # mov ax,dx
  849. b"\xC3" # ret
  850. )
  851. # Each 4bits is a ascii letter in the name
  852. vendor_id = []
  853. for reg in [ebx, edx, ecx]:
  854. for n in [0, 8, 16, 24]:
  855. vendor_id.append(chr((reg >> n) & 0xFF))
  856. vendor_id = ''.join(vendor_id)
  857. return vendor_id
  858. # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
  859. def get_info(self):
  860. # EAX
  861. eax = self._run_asm(
  862. b"\xB8\x01\x00\x00\x00", # mov eax,0x1"
  863. b"\x0f\xa2" # cpuid
  864. b"\xC3" # ret
  865. )
  866. # Get the CPU info
  867. stepping_id = (eax >> 0) & 0xF # 4 bits
  868. model = (eax >> 4) & 0xF # 4 bits
  869. family_id = (eax >> 8) & 0xF # 4 bits
  870. processor_type = (eax >> 12) & 0x3 # 2 bits
  871. extended_model_id = (eax >> 16) & 0xF # 4 bits
  872. extended_family_id = (eax >> 20) & 0xFF # 8 bits
  873. family = 0
  874. if family_id in [15]:
  875. family = extended_family_id + family_id
  876. else:
  877. family = family_id
  878. if family_id in [6, 15]:
  879. model = (extended_model_id << 4) + model
  880. return {
  881. 'stepping' : stepping_id,
  882. 'model' : model,
  883. 'family' : family,
  884. 'processor_type' : processor_type
  885. }
  886. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000000h:_Get_Highest_Extended_Function_Supported
  887. def get_max_extension_support(self):
  888. # Check for extension support
  889. max_extension_support = self._run_asm(
  890. b"\xB8\x00\x00\x00\x80" # mov ax,0x80000000
  891. b"\x0f\xa2" # cpuid
  892. b"\xC3" # ret
  893. )
  894. return max_extension_support
  895. # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
  896. def get_flags(self, max_extension_support):
  897. # EDX
  898. edx = self._run_asm(
  899. b"\xB8\x01\x00\x00\x00", # mov eax,0x1"
  900. b"\x0f\xa2" # cpuid
  901. b"\x89\xD0" # mov ax,dx
  902. b"\xC3" # ret
  903. )
  904. # ECX
  905. ecx = self._run_asm(
  906. b"\xB8\x01\x00\x00\x00", # mov eax,0x1"
  907. b"\x0f\xa2" # cpuid
  908. b"\x89\xC8" # mov ax,cx
  909. b"\xC3" # ret
  910. )
  911. # Get the CPU flags
  912. flags = {
  913. 'fpu' : _is_bit_set(edx, 0),
  914. 'vme' : _is_bit_set(edx, 1),
  915. 'de' : _is_bit_set(edx, 2),
  916. 'pse' : _is_bit_set(edx, 3),
  917. 'tsc' : _is_bit_set(edx, 4),
  918. 'msr' : _is_bit_set(edx, 5),
  919. 'pae' : _is_bit_set(edx, 6),
  920. 'mce' : _is_bit_set(edx, 7),
  921. 'cx8' : _is_bit_set(edx, 8),
  922. 'apic' : _is_bit_set(edx, 9),
  923. #'reserved1' : _is_bit_set(edx, 10),
  924. 'sep' : _is_bit_set(edx, 11),
  925. 'mtrr' : _is_bit_set(edx, 12),
  926. 'pge' : _is_bit_set(edx, 13),
  927. 'mca' : _is_bit_set(edx, 14),
  928. 'cmov' : _is_bit_set(edx, 15),
  929. 'pat' : _is_bit_set(edx, 16),
  930. 'pse36' : _is_bit_set(edx, 17),
  931. 'pn' : _is_bit_set(edx, 18),
  932. 'clflush' : _is_bit_set(edx, 19),
  933. #'reserved2' : _is_bit_set(edx, 20),
  934. 'dts' : _is_bit_set(edx, 21),
  935. 'acpi' : _is_bit_set(edx, 22),
  936. 'mmx' : _is_bit_set(edx, 23),
  937. 'fxsr' : _is_bit_set(edx, 24),
  938. 'sse' : _is_bit_set(edx, 25),
  939. 'sse2' : _is_bit_set(edx, 26),
  940. 'ss' : _is_bit_set(edx, 27),
  941. 'ht' : _is_bit_set(edx, 28),
  942. 'tm' : _is_bit_set(edx, 29),
  943. 'ia64' : _is_bit_set(edx, 30),
  944. 'pbe' : _is_bit_set(edx, 31),
  945. 'pni' : _is_bit_set(ecx, 0),
  946. 'pclmulqdq' : _is_bit_set(ecx, 1),
  947. 'dtes64' : _is_bit_set(ecx, 2),
  948. 'monitor' : _is_bit_set(ecx, 3),
  949. 'ds_cpl' : _is_bit_set(ecx, 4),
  950. 'vmx' : _is_bit_set(ecx, 5),
  951. 'smx' : _is_bit_set(ecx, 6),
  952. 'est' : _is_bit_set(ecx, 7),
  953. 'tm2' : _is_bit_set(ecx, 8),
  954. 'ssse3' : _is_bit_set(ecx, 9),
  955. 'cid' : _is_bit_set(ecx, 10),
  956. #'reserved3' : _is_bit_set(ecx, 11),
  957. 'fma' : _is_bit_set(ecx, 12),
  958. 'cx16' : _is_bit_set(ecx, 13),
  959. 'xtpr' : _is_bit_set(ecx, 14),
  960. 'pdcm' : _is_bit_set(ecx, 15),
  961. #'reserved4' : _is_bit_set(ecx, 16),
  962. 'pcid' : _is_bit_set(ecx, 17),
  963. 'dca' : _is_bit_set(ecx, 18),
  964. 'sse4_1' : _is_bit_set(ecx, 19),
  965. 'sse4_2' : _is_bit_set(ecx, 20),
  966. 'x2apic' : _is_bit_set(ecx, 21),
  967. 'movbe' : _is_bit_set(ecx, 22),
  968. 'popcnt' : _is_bit_set(ecx, 23),
  969. 'tscdeadline' : _is_bit_set(ecx, 24),
  970. 'aes' : _is_bit_set(ecx, 25),
  971. 'xsave' : _is_bit_set(ecx, 26),
  972. 'osxsave' : _is_bit_set(ecx, 27),
  973. 'avx' : _is_bit_set(ecx, 28),
  974. 'f16c' : _is_bit_set(ecx, 29),
  975. 'rdrnd' : _is_bit_set(ecx, 30),
  976. 'hypervisor' : _is_bit_set(ecx, 31)
  977. }
  978. # Get a list of only the flags that are true
  979. flags = [k for k, v in flags.items() if v]
  980. # http://en.wikipedia.org/wiki/CPUID#EAX.3D7.2C_ECX.3D0:_Extended_Features
  981. if max_extension_support >= 7:
  982. # EBX
  983. ebx = self._run_asm(
  984. b"\x31\xC9", # xor ecx,ecx
  985. b"\xB8\x07\x00\x00\x00" # mov eax,7
  986. b"\x0f\xa2" # cpuid
  987. b"\x89\xD8" # mov ax,bx
  988. b"\xC3" # ret
  989. )
  990. # ECX
  991. ecx = self._run_asm(
  992. b"\x31\xC9", # xor ecx,ecx
  993. b"\xB8\x07\x00\x00\x00" # mov eax,7
  994. b"\x0f\xa2" # cpuid
  995. b"\x89\xC8" # mov ax,cx
  996. b"\xC3" # ret
  997. )
  998. # Get the extended CPU flags
  999. extended_flags = {
  1000. #'fsgsbase' : _is_bit_set(ebx, 0),
  1001. #'IA32_TSC_ADJUST' : _is_bit_set(ebx, 1),
  1002. 'sgx' : _is_bit_set(ebx, 2),
  1003. 'bmi1' : _is_bit_set(ebx, 3),
  1004. 'hle' : _is_bit_set(ebx, 4),
  1005. 'avx2' : _is_bit_set(ebx, 5),
  1006. #'reserved' : _is_bit_set(ebx, 6),
  1007. 'smep' : _is_bit_set(ebx, 7),
  1008. 'bmi2' : _is_bit_set(ebx, 8),
  1009. 'erms' : _is_bit_set(ebx, 9),
  1010. 'invpcid' : _is_bit_set(ebx, 10),
  1011. 'rtm' : _is_bit_set(ebx, 11),
  1012. 'pqm' : _is_bit_set(ebx, 12),
  1013. #'FPU CS and FPU DS deprecated' : _is_bit_set(ebx, 13),
  1014. 'mpx' : _is_bit_set(ebx, 14),
  1015. 'pqe' : _is_bit_set(ebx, 15),
  1016. 'avx512f' : _is_bit_set(ebx, 16),
  1017. 'avx512dq' : _is_bit_set(ebx, 17),
  1018. 'rdseed' : _is_bit_set(ebx, 18),
  1019. 'adx' : _is_bit_set(ebx, 19),
  1020. 'smap' : _is_bit_set(ebx, 20),
  1021. 'avx512ifma' : _is_bit_set(ebx, 21),
  1022. 'pcommit' : _is_bit_set(ebx, 22),
  1023. 'clflushopt' : _is_bit_set(ebx, 23),
  1024. 'clwb' : _is_bit_set(ebx, 24),
  1025. 'intel_pt' : _is_bit_set(ebx, 25),
  1026. 'avx512pf' : _is_bit_set(ebx, 26),
  1027. 'avx512er' : _is_bit_set(ebx, 27),
  1028. 'avx512cd' : _is_bit_set(ebx, 28),
  1029. 'sha' : _is_bit_set(ebx, 29),
  1030. 'avx512bw' : _is_bit_set(ebx, 30),
  1031. 'avx512vl' : _is_bit_set(ebx, 31),
  1032. 'prefetchwt1' : _is_bit_set(ecx, 0),
  1033. 'avx512vbmi' : _is_bit_set(ecx, 1),
  1034. 'umip' : _is_bit_set(ecx, 2),
  1035. 'pku' : _is_bit_set(ecx, 3),
  1036. 'ospke' : _is_bit_set(ecx, 4),
  1037. #'reserved' : _is_bit_set(ecx, 5),
  1038. 'avx512vbmi2' : _is_bit_set(ecx, 6),
  1039. #'reserved' : _is_bit_set(ecx, 7),
  1040. 'gfni' : _is_bit_set(ecx, 8),
  1041. 'vaes' : _is_bit_set(ecx, 9),
  1042. 'vpclmulqdq' : _is_bit_set(ecx, 10),
  1043. 'avx512vnni' : _is_bit_set(ecx, 11),
  1044. 'avx512bitalg' : _is_bit_set(ecx, 12),
  1045. #'reserved' : _is_bit_set(ecx, 13),
  1046. 'avx512vpopcntdq' : _is_bit_set(ecx, 14),
  1047. #'reserved' : _is_bit_set(ecx, 15),
  1048. #'reserved' : _is_bit_set(ecx, 16),
  1049. #'mpx0' : _is_bit_set(ecx, 17),
  1050. #'mpx1' : _is_bit_set(ecx, 18),
  1051. #'mpx2' : _is_bit_set(ecx, 19),
  1052. #'mpx3' : _is_bit_set(ecx, 20),
  1053. #'mpx4' : _is_bit_set(ecx, 21),
  1054. 'rdpid' : _is_bit_set(ecx, 22),
  1055. #'reserved' : _is_bit_set(ecx, 23),
  1056. #'reserved' : _is_bit_set(ecx, 24),
  1057. #'reserved' : _is_bit_set(ecx, 25),
  1058. #'reserved' : _is_bit_set(ecx, 26),
  1059. #'reserved' : _is_bit_set(ecx, 27),
  1060. #'reserved' : _is_bit_set(ecx, 28),
  1061. #'reserved' : _is_bit_set(ecx, 29),
  1062. 'sgx_lc' : _is_bit_set(ecx, 30),
  1063. #'reserved' : _is_bit_set(ecx, 31)
  1064. }
  1065. # Get a list of only the flags that are true
  1066. extended_flags = [k for k, v in extended_flags.items() if v]
  1067. flags += extended_flags
  1068. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000001h:_Extended_Processor_Info_and_Feature_Bits
  1069. if max_extension_support >= 0x80000001:
  1070. # EBX
  1071. ebx = self._run_asm(
  1072. b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
  1073. b"\x0f\xa2" # cpuid
  1074. b"\x89\xD8" # mov ax,bx
  1075. b"\xC3" # ret
  1076. )
  1077. # ECX
  1078. ecx = self._run_asm(
  1079. b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001
  1080. b"\x0f\xa2" # cpuid
  1081. b"\x89\xC8" # mov ax,cx
  1082. b"\xC3" # ret
  1083. )
  1084. # Get the extended CPU flags
  1085. extended_flags = {
  1086. 'fpu' : _is_bit_set(ebx, 0),
  1087. 'vme' : _is_bit_set(ebx, 1),
  1088. 'de' : _is_bit_set(ebx, 2),
  1089. 'pse' : _is_bit_set(ebx, 3),
  1090. 'tsc' : _is_bit_set(ebx, 4),
  1091. 'msr' : _is_bit_set(ebx, 5),
  1092. 'pae' : _is_bit_set(ebx, 6),
  1093. 'mce' : _is_bit_set(ebx, 7),
  1094. 'cx8' : _is_bit_set(ebx, 8),
  1095. 'apic' : _is_bit_set(ebx, 9),
  1096. #'reserved' : _is_bit_set(ebx, 10),
  1097. 'syscall' : _is_bit_set(ebx, 11),
  1098. 'mtrr' : _is_bit_set(ebx, 12),
  1099. 'pge' : _is_bit_set(ebx, 13),
  1100. 'mca' : _is_bit_set(ebx, 14),
  1101. 'cmov' : _is_bit_set(ebx, 15),
  1102. 'pat' : _is_bit_set(ebx, 16),
  1103. 'pse36' : _is_bit_set(ebx, 17),
  1104. #'reserved' : _is_bit_set(ebx, 18),
  1105. 'mp' : _is_bit_set(ebx, 19),
  1106. 'nx' : _is_bit_set(ebx, 20),
  1107. #'reserved' : _is_bit_set(ebx, 21),
  1108. 'mmxext' : _is_bit_set(ebx, 22),
  1109. 'mmx' : _is_bit_set(ebx, 23),
  1110. 'fxsr' : _is_bit_set(ebx, 24),
  1111. 'fxsr_opt' : _is_bit_set(ebx, 25),
  1112. 'pdpe1gp' : _is_bit_set(ebx, 26),
  1113. 'rdtscp' : _is_bit_set(ebx, 27),
  1114. #'reserved' : _is_bit_set(ebx, 28),
  1115. 'lm' : _is_bit_set(ebx, 29),
  1116. '3dnowext' : _is_bit_set(ebx, 30),
  1117. '3dnow' : _is_bit_set(ebx, 31),
  1118. 'lahf_lm' : _is_bit_set(ecx, 0),
  1119. 'cmp_legacy' : _is_bit_set(ecx, 1),
  1120. 'svm' : _is_bit_set(ecx, 2),
  1121. 'extapic' : _is_bit_set(ecx, 3),
  1122. 'cr8_legacy' : _is_bit_set(ecx, 4),
  1123. 'abm' : _is_bit_set(ecx, 5),
  1124. 'sse4a' : _is_bit_set(ecx, 6),
  1125. 'misalignsse' : _is_bit_set(ecx, 7),
  1126. '3dnowprefetch' : _is_bit_set(ecx, 8),
  1127. 'osvw' : _is_bit_set(ecx, 9),
  1128. 'ibs' : _is_bit_set(ecx, 10),
  1129. 'xop' : _is_bit_set(ecx, 11),
  1130. 'skinit' : _is_bit_set(ecx, 12),
  1131. 'wdt' : _is_bit_set(ecx, 13),
  1132. #'reserved' : _is_bit_set(ecx, 14),
  1133. 'lwp' : _is_bit_set(ecx, 15),
  1134. 'fma4' : _is_bit_set(ecx, 16),
  1135. 'tce' : _is_bit_set(ecx, 17),
  1136. #'reserved' : _is_bit_set(ecx, 18),
  1137. 'nodeid_msr' : _is_bit_set(ecx, 19),
  1138. #'reserved' : _is_bit_set(ecx, 20),
  1139. 'tbm' : _is_bit_set(ecx, 21),
  1140. 'topoext' : _is_bit_set(ecx, 22),
  1141. 'perfctr_core' : _is_bit_set(ecx, 23),
  1142. 'perfctr_nb' : _is_bit_set(ecx, 24),
  1143. #'reserved' : _is_bit_set(ecx, 25),
  1144. 'dbx' : _is_bit_set(ecx, 26),
  1145. 'perftsc' : _is_bit_set(ecx, 27),
  1146. 'pci_l2i' : _is_bit_set(ecx, 28),
  1147. #'reserved' : _is_bit_set(ecx, 29),
  1148. #'reserved' : _is_bit_set(ecx, 30),
  1149. #'reserved' : _is_bit_set(ecx, 31)
  1150. }
  1151. # Get a list of only the flags that are true
  1152. extended_flags = [k for k, v in extended_flags.items() if v]
  1153. flags += extended_flags
  1154. flags.sort()
  1155. return flags
  1156. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000002h.2C80000003h.2C80000004h:_Processor_Brand_String
  1157. def get_processor_brand(self, max_extension_support):
  1158. processor_brand = ""
  1159. # Processor brand string
  1160. if max_extension_support >= 0x80000004:
  1161. instructions = [
  1162. b"\xB8\x02\x00\x00\x80", # mov ax,0x80000002
  1163. b"\xB8\x03\x00\x00\x80", # mov ax,0x80000003
  1164. b"\xB8\x04\x00\x00\x80" # mov ax,0x80000004
  1165. ]
  1166. for instruction in instructions:
  1167. # EAX
  1168. eax = self._run_asm(
  1169. instruction, # mov ax,0x8000000?
  1170. b"\x0f\xa2" # cpuid
  1171. b"\x89\xC0" # mov ax,ax
  1172. b"\xC3" # ret
  1173. )
  1174. # EBX
  1175. ebx = self._run_asm(
  1176. instruction, # mov ax,0x8000000?
  1177. b"\x0f\xa2" # cpuid
  1178. b"\x89\xD8" # mov ax,bx
  1179. b"\xC3" # ret
  1180. )
  1181. # ECX
  1182. ecx = self._run_asm(
  1183. instruction, # mov ax,0x8000000?
  1184. b"\x0f\xa2" # cpuid
  1185. b"\x89\xC8" # mov ax,cx
  1186. b"\xC3" # ret
  1187. )
  1188. # EDX
  1189. edx = self._run_asm(
  1190. instruction, # mov ax,0x8000000?
  1191. b"\x0f\xa2" # cpuid
  1192. b"\x89\xD0" # mov ax,dx
  1193. b"\xC3" # ret
  1194. )
  1195. # Combine each of the 4 bytes in each register into the string
  1196. for reg in [eax, ebx, ecx, edx]:
  1197. for n in [0, 8, 16, 24]:
  1198. processor_brand += chr((reg >> n) & 0xFF)
  1199. # Strip off any trailing NULL terminators and white space
  1200. processor_brand = processor_brand.strip("\0").strip()
  1201. return processor_brand
  1202. # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000006h:_Extended_L2_Cache_Features
  1203. def get_cache(self, max_extension_support):
  1204. cache_info = {}
  1205. # Just return if the cache feature is not supported
  1206. if max_extension_support < 0x80000006:
  1207. return cache_info
  1208. # ECX
  1209. ecx = self._run_asm(
  1210. b"\xB8\x06\x00\x00\x80" # mov ax,0x80000006
  1211. b"\x0f\xa2" # cpuid
  1212. b"\x89\xC8" # mov ax,cx
  1213. b"\xC3" # ret
  1214. )
  1215. cache_info = {
  1216. 'size_b' : (ecx & 0xFF) * 1024,
  1217. 'associativity' : (ecx >> 12) & 0xF,
  1218. 'line_size_b' : (ecx >> 16) & 0xFFFF
  1219. }
  1220. return cache_info
  1221. def get_ticks_func(self):
  1222. retval = None
  1223. if DataSource.bits == '32bit':
  1224. # Works on x86_32
  1225. restype = None
  1226. argtypes = (ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint))
  1227. get_ticks_x86_32 = self._asm_func(restype, argtypes,
  1228. [
  1229. b"\x55", # push bp
  1230. b"\x89\xE5", # mov bp,sp
  1231. b"\x31\xC0", # xor ax,ax
  1232. b"\x0F\xA2", # cpuid
  1233. b"\x0F\x31", # rdtsc
  1234. b"\x8B\x5D\x08", # mov bx,[di+0x8]
  1235. b"\x8B\x4D\x0C", # mov cx,[di+0xc]
  1236. b"\x89\x13", # mov [bp+di],dx
  1237. b"\x89\x01", # mov [bx+di],ax
  1238. b"\x5D", # pop bp
  1239. b"\xC3" # ret
  1240. ]
  1241. )
  1242. # Monkey patch func to combine high and low args into one return
  1243. old_func = get_ticks_x86_32.func
  1244. def new_func():
  1245. # Pass two uint32s into function
  1246. high = ctypes.c_uint32(0)
  1247. low = ctypes.c_uint32(0)
  1248. old_func(ctypes.byref(high), ctypes.byref(low))
  1249. # Shift the two uint32s into one uint64
  1250. retval = ((high.value << 32) & 0xFFFFFFFF00000000) | low.value
  1251. return retval
  1252. get_ticks_x86_32.func = new_func
  1253. retval = get_ticks_x86_32
  1254. elif DataSource.bits == '64bit':
  1255. # Works on x86_64
  1256. restype = ctypes.c_uint64
  1257. argtypes = ()
  1258. get_ticks_x86_64 = self._asm_func(restype, argtypes,
  1259. [
  1260. b"\x48", # dec ax
  1261. b"\x31\xC0", # xor ax,ax
  1262. b"\x0F\xA2", # cpuid
  1263. b"\x0F\x31", # rdtsc
  1264. b"\x48", # dec ax
  1265. b"\xC1\xE2\x20", # shl dx,byte 0x20
  1266. b"\x48", # dec ax
  1267. b"\x09\xD0", # or ax,dx
  1268. b"\xC3", # ret
  1269. ]
  1270. )
  1271. retval = get_ticks_x86_64
  1272. return retval
  1273. def get_raw_hz(self):
  1274. from time import sleep
  1275. ticks_fn = self.get_ticks_func()
  1276. start = ticks_fn.func()
  1277. sleep(1)
  1278. end = ticks_fn.func()
  1279. ticks = (end - start)
  1280. ticks_fn.free()
  1281. return ticks
  1282. def _get_cpu_info_from_cpuid_actual():
  1283. '''
  1284. Warning! This function has the potential to crash the Python runtime.
  1285. Do not call it directly. Use the _get_cpu_info_from_cpuid function instead.
  1286. It will safely call this function in another process.
  1287. '''
  1288. from io import StringIO
  1289. trace = Trace(True, True)
  1290. info = {}
  1291. # Pipe stdout and stderr to strings
  1292. sys.stdout = trace._stdout
  1293. sys.stderr = trace._stderr
  1294. try:
  1295. # Get the CPU arch and bits
  1296. arch, bits = _parse_arch(DataSource.arch_string_raw)
  1297. # Return none if this is not an X86 CPU
  1298. if not arch in ['X86_32', 'X86_64']:
  1299. trace.fail('Not running on X86_32 or X86_64. Skipping ...')
  1300. return trace.to_dict(info, True)
  1301. # Return none if SE Linux is in enforcing mode
  1302. cpuid = CPUID(trace)
  1303. if cpuid.is_selinux_enforcing:
  1304. trace.fail('SELinux is enforcing. Skipping ...')
  1305. return trace.to_dict(info, True)
  1306. # Get the cpu info from the CPUID register
  1307. max_extension_support = cpuid.get_max_extension_support()
  1308. cache_info = cpuid.get_cache(max_extension_support)
  1309. info = cpuid.get_info()
  1310. processor_brand = cpuid.get_processor_brand(max_extension_support)
  1311. # Get the Hz and scale
  1312. hz_actual = cpuid.get_raw_hz()
  1313. hz_actual = _to_decimal_string(hz_actual)
  1314. # Get the Hz and scale
  1315. hz_advertised, scale = _parse_cpu_brand_string(processor_brand)
  1316. info = {
  1317. 'vendor_id_raw' : cpuid.get_vendor_id(),
  1318. 'hardware_raw' : '',
  1319. 'brand_raw' : processor_brand,
  1320. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale),
  1321. 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 0),
  1322. 'hz_advertised' : _hz_short_to_full(hz_advertised, scale),
  1323. 'hz_actual' : _hz_short_to_full(hz_actual, 0),
  1324. 'l2_cache_size' : cache_info['size_b'],
  1325. 'l2_cache_line_size' : cache_info['line_size_b'],
  1326. 'l2_cache_associativity' : cache_info['associativity'],
  1327. 'stepping' : info['stepping'],
  1328. 'model' : info['model'],
  1329. 'family' : info['family'],
  1330. 'processor_type' : info['processor_type'],
  1331. 'flags' : cpuid.get_flags(max_extension_support)
  1332. }
  1333. info = _filter_dict_keys_with_empty_values(info)
  1334. trace.success()
  1335. except Exception as err:
  1336. from traceback import format_exc
  1337. err_string = format_exc()
  1338. trace._err = ''.join(['\t\t{0}\n'.format(n) for n in err_string.split('\n')]) + '\n'
  1339. return trace.to_dict(info, True)
  1340. return trace.to_dict(info, False)
  1341. def _get_cpu_info_from_cpuid_subprocess_wrapper(queue):
  1342. orig_stdout = sys.stdout
  1343. orig_stderr = sys.stderr
  1344. output = _get_cpu_info_from_cpuid_actual()
  1345. sys.stdout = orig_stdout
  1346. sys.stderr = orig_stderr
  1347. queue.put(_obj_to_b64(output))
  1348. def _get_cpu_info_from_cpuid():
  1349. '''
  1350. Returns the CPU info gathered by querying the X86 cpuid register in a new process.
  1351. Returns {} on non X86 cpus.
  1352. Returns {} if SELinux is in enforcing mode.
  1353. '''
  1354. g_trace.header('Tying to get info from CPUID ...')
  1355. from multiprocessing import Process, Queue
  1356. # Return {} if can't cpuid
  1357. if not DataSource.can_cpuid:
  1358. g_trace.fail('Can\'t CPUID. Skipping ...')
  1359. return {}
  1360. # Get the CPU arch and bits
  1361. arch, bits = _parse_arch(DataSource.arch_string_raw)
  1362. # Return {} if this is not an X86 CPU
  1363. if not arch in ['X86_32', 'X86_64']:
  1364. g_trace.fail('Not running on X86_32 or X86_64. Skipping ...')
  1365. return {}
  1366. try:
  1367. if CAN_CALL_CPUID_IN_SUBPROCESS:
  1368. # Start running the function in a subprocess
  1369. queue = Queue()
  1370. p = Process(target=_get_cpu_info_from_cpuid_subprocess_wrapper, args=(queue,))
  1371. p.start()
  1372. # Wait for the process to end, while it is still alive
  1373. while p.is_alive():
  1374. p.join(0)
  1375. # Return {} if it failed
  1376. if p.exitcode != 0:
  1377. g_trace.fail('Failed to run CPUID in process. Skipping ...')
  1378. return {}
  1379. # Return {} if no results
  1380. if queue.empty():
  1381. g_trace.fail('Failed to get anything from CPUID process. Skipping ...')
  1382. return {}
  1383. # Return the result, only if there is something to read
  1384. else:
  1385. output = _b64_to_obj(queue.get())
  1386. import pprint
  1387. pp = pprint.PrettyPrinter(indent=4)
  1388. #pp.pprint(output)
  1389. if 'output' in output and output['output']:
  1390. g_trace.write(output['output'])
  1391. if 'stdout' in output and output['stdout']:
  1392. sys.stdout.write('{0}\n'.format(output['stdout']))
  1393. sys.stdout.flush()
  1394. if 'stderr' in output and output['stderr']:
  1395. sys.stderr.write('{0}\n'.format(output['stderr']))
  1396. sys.stderr.flush()
  1397. if 'is_fail' not in output:
  1398. g_trace.fail('Failed to get is_fail from CPUID process. Skipping ...')
  1399. return {}
  1400. # Fail if there was an exception
  1401. if 'err' in output and output['err']:
  1402. g_trace.fail('Failed to run CPUID in process. Skipping ...')
  1403. g_trace.write(output['err'])
  1404. g_trace.write('Failed ...')
  1405. return {}
  1406. if 'is_fail' in output and output['is_fail']:
  1407. g_trace.write('Failed ...')
  1408. return {}
  1409. if 'info' not in output or not output['info']:
  1410. g_trace.fail('Failed to get return info from CPUID process. Skipping ...')
  1411. return {}
  1412. return output['info']
  1413. else:
  1414. # FIXME: This should write the values like in the above call to actual
  1415. orig_stdout = sys.stdout
  1416. orig_stderr = sys.stderr
  1417. output = _get_cpu_info_from_cpuid_actual()
  1418. sys.stdout = orig_stdout
  1419. sys.stderr = orig_stderr
  1420. g_trace.success()
  1421. return output['info']
  1422. except Exception as err:
  1423. g_trace.fail(err)
  1424. # Return {} if everything failed
  1425. return {}
  1426. def _get_cpu_info_from_proc_cpuinfo():
  1427. '''
  1428. Returns the CPU info gathered from /proc/cpuinfo.
  1429. Returns {} if /proc/cpuinfo is not found.
  1430. '''
  1431. g_trace.header('Tying to get info from /proc/cpuinfo ...')
  1432. try:
  1433. # Just return {} if there is no cpuinfo
  1434. if not DataSource.has_proc_cpuinfo():
  1435. g_trace.fail('Failed to find /proc/cpuinfo. Skipping ...')
  1436. return {}
  1437. returncode, output = DataSource.cat_proc_cpuinfo()
  1438. if returncode != 0:
  1439. g_trace.fail('Failed to run cat /proc/cpuinfo. Skipping ...')
  1440. return {}
  1441. # Various fields
  1442. vendor_id = _get_field(False, output, None, '', 'vendor_id', 'vendor id', 'vendor')
  1443. processor_brand = _get_field(True, output, None, None, 'model name', 'cpu', 'processor', 'uarch')
  1444. cache_size = _get_field(False, output, None, '', 'cache size')
  1445. stepping = _get_field(False, output, int, -1, 'stepping')
  1446. model = _get_field(False, output, int, -1, 'model')
  1447. family = _get_field(False, output, int, -1, 'cpu family')
  1448. hardware = _get_field(False, output, None, '', 'Hardware')
  1449. # Flags
  1450. flags = _get_field(False, output, None, None, 'flags', 'Features', 'ASEs implemented')
  1451. if flags:
  1452. flags = flags.split()
  1453. flags.sort()
  1454. # Check for other cache format
  1455. if not cache_size:
  1456. try:
  1457. for i in range(0, 10):
  1458. name = "cache{0}".format(i)
  1459. value = _get_field(False, output, None, None, name)
  1460. if value:
  1461. value = [entry.split('=') for entry in value.split(' ')]
  1462. value = dict(value)
  1463. if 'level' in value and value['level'] == '3' and 'size' in value:
  1464. cache_size = value['size']
  1465. break
  1466. except Exception:
  1467. pass
  1468. # Convert from MHz string to Hz
  1469. hz_actual = _get_field(False, output, None, '', 'cpu MHz', 'cpu speed', 'clock', 'cpu MHz dynamic', 'cpu MHz static')
  1470. hz_actual = hz_actual.lower().rstrip('mhz').strip()
  1471. hz_actual = _to_decimal_string(hz_actual)
  1472. # Convert from GHz/MHz string to Hz
  1473. hz_advertised, scale = (None, 0)
  1474. try:
  1475. hz_advertised, scale = _parse_cpu_brand_string(processor_brand)
  1476. except Exception:
  1477. pass
  1478. info = {
  1479. 'hardware_raw' : hardware,
  1480. 'brand_raw' : processor_brand,
  1481. 'l3_cache_size' : _friendly_bytes_to_int(cache_size),
  1482. 'flags' : flags,
  1483. 'vendor_id_raw' : vendor_id,
  1484. 'stepping' : stepping,
  1485. 'model' : model,
  1486. 'family' : family,
  1487. }
  1488. # Make the Hz the same for actual and advertised if missing any
  1489. if not hz_advertised or hz_advertised == '0.0':
  1490. hz_advertised = hz_actual
  1491. scale = 6
  1492. elif not hz_actual or hz_actual == '0.0':
  1493. hz_actual = hz_advertised
  1494. # Add the Hz if there is one
  1495. if _hz_short_to_full(hz_advertised, scale) > (0, 0):
  1496. info['hz_advertised_friendly'] = _hz_short_to_friendly(hz_advertised, scale)
  1497. info['hz_advertised'] = _hz_short_to_full(hz_advertised, scale)
  1498. if _hz_short_to_full(hz_actual, scale) > (0, 0):
  1499. info['hz_actual_friendly'] = _hz_short_to_friendly(hz_actual, 6)
  1500. info['hz_actual'] = _hz_short_to_full(hz_actual, 6)
  1501. info = _filter_dict_keys_with_empty_values(info, {'stepping':0, 'model':0, 'family':0})
  1502. g_trace.success()
  1503. return info
  1504. except Exception as err:
  1505. g_trace.fail(err)
  1506. #raise # NOTE: To have this throw on error, uncomment this line
  1507. return {}
  1508. def _get_cpu_info_from_cpufreq_info():
  1509. '''
  1510. Returns the CPU info gathered from cpufreq-info.
  1511. Returns {} if cpufreq-info is not found.
  1512. '''
  1513. g_trace.header('Tying to get info from cpufreq-info ...')
  1514. try:
  1515. hz_brand, scale = '0.0', 0
  1516. if not DataSource.has_cpufreq_info():
  1517. g_trace.fail('Failed to find cpufreq-info. Skipping ...')
  1518. return {}
  1519. returncode, output = DataSource.cpufreq_info()
  1520. if returncode != 0:
  1521. g_trace.fail('Failed to run cpufreq-info. Skipping ...')
  1522. return {}
  1523. hz_brand = output.split('current CPU frequency is')[1].split('\n')[0]
  1524. i = hz_brand.find('Hz')
  1525. assert(i != -1)
  1526. hz_brand = hz_brand[0 : i+2].strip().lower()
  1527. if hz_brand.endswith('mhz'):
  1528. scale = 6
  1529. elif hz_brand.endswith('ghz'):
  1530. scale = 9
  1531. hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip()
  1532. hz_brand = _to_decimal_string(hz_brand)
  1533. info = {
  1534. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_brand, scale),
  1535. 'hz_actual_friendly' : _hz_short_to_friendly(hz_brand, scale),
  1536. 'hz_advertised' : _hz_short_to_full(hz_brand, scale),
  1537. 'hz_actual' : _hz_short_to_full(hz_brand, scale),
  1538. }
  1539. info = _filter_dict_keys_with_empty_values(info)
  1540. g_trace.success()
  1541. return info
  1542. except Exception as err:
  1543. g_trace.fail(err)
  1544. #raise # NOTE: To have this throw on error, uncomment this line
  1545. return {}
  1546. def _get_cpu_info_from_lscpu():
  1547. '''
  1548. Returns the CPU info gathered from lscpu.
  1549. Returns {} if lscpu is not found.
  1550. '''
  1551. g_trace.header('Tying to get info from lscpu ...')
  1552. try:
  1553. if not DataSource.has_lscpu():
  1554. g_trace.fail('Failed to find lscpu. Skipping ...')
  1555. return {}
  1556. returncode, output = DataSource.lscpu()
  1557. if returncode != 0:
  1558. g_trace.fail('Failed to run lscpu. Skipping ...')
  1559. return {}
  1560. info = {}
  1561. new_hz = _get_field(False, output, None, None, 'CPU max MHz', 'CPU MHz')
  1562. if new_hz:
  1563. new_hz = _to_decimal_string(new_hz)
  1564. scale = 6
  1565. info['hz_advertised_friendly'] = _hz_short_to_friendly(new_hz, scale)
  1566. info['hz_actual_friendly'] = _hz_short_to_friendly(new_hz, scale)
  1567. info['hz_advertised'] = _hz_short_to_full(new_hz, scale)
  1568. info['hz_actual'] = _hz_short_to_full(new_hz, scale)
  1569. new_hz = _get_field(False, output, None, None, 'CPU dynamic MHz', 'CPU static MHz')
  1570. if new_hz:
  1571. new_hz = _to_decimal_string(new_hz)
  1572. scale = 6
  1573. info['hz_advertised_friendly'] = _hz_short_to_friendly(new_hz, scale)
  1574. info['hz_actual_friendly'] = _hz_short_to_friendly(new_hz, scale)
  1575. info['hz_advertised'] = _hz_short_to_full(new_hz, scale)
  1576. info['hz_actual'] = _hz_short_to_full(new_hz, scale)
  1577. vendor_id = _get_field(False, output, None, None, 'Vendor ID')
  1578. if vendor_id:
  1579. info['vendor_id_raw'] = vendor_id
  1580. brand = _get_field(False, output, None, None, 'Model name')
  1581. if brand:
  1582. info['brand_raw'] = brand
  1583. else:
  1584. brand = _get_field(False, output, None, None, 'Model')
  1585. if brand and not brand.isdigit():
  1586. info['brand_raw'] = brand
  1587. family = _get_field(False, output, None, None, 'CPU family')
  1588. if family and family.isdigit():
  1589. info['family'] = int(family)
  1590. stepping = _get_field(False, output, None, None, 'Stepping')
  1591. if stepping and stepping.isdigit():
  1592. info['stepping'] = int(stepping)
  1593. model = _get_field(False, output, None, None, 'Model')
  1594. if model and model.isdigit():
  1595. info['model'] = int(model)
  1596. l1_data_cache_size = _get_field(False, output, None, None, 'L1d cache')
  1597. if l1_data_cache_size:
  1598. l1_data_cache_size = l1_data_cache_size.split('(')[0].strip()
  1599. info['l1_data_cache_size'] = _friendly_bytes_to_int(l1_data_cache_size)
  1600. l1_instruction_cache_size = _get_field(False, output, None, None, 'L1i cache')
  1601. if l1_instruction_cache_size:
  1602. l1_instruction_cache_size = l1_instruction_cache_size.split('(')[0].strip()
  1603. info['l1_instruction_cache_size'] = _friendly_bytes_to_int(l1_instruction_cache_size)
  1604. l2_cache_size = _get_field(False, output, None, None, 'L2 cache', 'L2d cache')
  1605. if l2_cache_size:
  1606. l2_cache_size = l2_cache_size.split('(')[0].strip()
  1607. info['l2_cache_size'] = _friendly_bytes_to_int(l2_cache_size)
  1608. l3_cache_size = _get_field(False, output, None, None, 'L3 cache')
  1609. if l3_cache_size:
  1610. l3_cache_size = l3_cache_size.split('(')[0].strip()
  1611. info['l3_cache_size'] = _friendly_bytes_to_int(l3_cache_size)
  1612. # Flags
  1613. flags = _get_field(False, output, None, None, 'flags', 'Features', 'ASEs implemented')
  1614. if flags:
  1615. flags = flags.split()
  1616. flags.sort()
  1617. info['flags'] = flags
  1618. info = _filter_dict_keys_with_empty_values(info, {'stepping':0, 'model':0, 'family':0})
  1619. g_trace.success()
  1620. return info
  1621. except Exception as err:
  1622. g_trace.fail(err)
  1623. #raise # NOTE: To have this throw on error, uncomment this line
  1624. return {}
  1625. def _get_cpu_info_from_dmesg():
  1626. '''
  1627. Returns the CPU info gathered from dmesg.
  1628. Returns {} if dmesg is not found or does not have the desired info.
  1629. '''
  1630. g_trace.header('Tying to get info from the dmesg ...')
  1631. # Just return {} if this arch has an unreliable dmesg log
  1632. arch, bits = _parse_arch(DataSource.arch_string_raw)
  1633. if arch in ['S390X']:
  1634. g_trace.fail('Running on S390X. Skipping ...')
  1635. return {}
  1636. # Just return {} if there is no dmesg
  1637. if not DataSource.has_dmesg():
  1638. g_trace.fail('Failed to find dmesg. Skipping ...')
  1639. return {}
  1640. # If dmesg fails return {}
  1641. returncode, output = DataSource.dmesg_a()
  1642. if output is None or returncode != 0:
  1643. g_trace.fail('Failed to run \"dmesg -a\". Skipping ...')
  1644. return {}
  1645. info = _parse_dmesg_output(output)
  1646. g_trace.success()
  1647. return info
  1648. # https://openpowerfoundation.org/wp-content/uploads/2016/05/LoPAPR_DRAFT_v11_24March2016_cmt1.pdf
  1649. # page 767
  1650. def _get_cpu_info_from_ibm_pa_features():
  1651. '''
  1652. Returns the CPU info gathered from lsprop /proc/device-tree/cpus/*/ibm,pa-features
  1653. Returns {} if lsprop is not found or ibm,pa-features does not have the desired info.
  1654. '''
  1655. g_trace.header('Tying to get info from lsprop ...')
  1656. try:
  1657. # Just return {} if there is no lsprop
  1658. if not DataSource.has_ibm_pa_features():
  1659. g_trace.fail('Failed to find lsprop. Skipping ...')
  1660. return {}
  1661. # If ibm,pa-features fails return {}
  1662. returncode, output = DataSource.ibm_pa_features()
  1663. if output is None or returncode != 0:
  1664. g_trace.fail('Failed to glob /proc/device-tree/cpus/*/ibm,pa-features. Skipping ...')
  1665. return {}
  1666. # Filter out invalid characters from output
  1667. value = output.split("ibm,pa-features")[1].lower()
  1668. value = [s for s in value if s in list('0123456789abcfed')]
  1669. value = ''.join(value)
  1670. # Get data converted to Uint32 chunks
  1671. left = int(value[0 : 8], 16)
  1672. right = int(value[8 : 16], 16)
  1673. # Get the CPU flags
  1674. flags = {
  1675. # Byte 0
  1676. 'mmu' : _is_bit_set(left, 0),
  1677. 'fpu' : _is_bit_set(left, 1),
  1678. 'slb' : _is_bit_set(left, 2),
  1679. 'run' : _is_bit_set(left, 3),
  1680. #'reserved' : _is_bit_set(left, 4),
  1681. 'dabr' : _is_bit_set(left, 5),
  1682. 'ne' : _is_bit_set(left, 6),
  1683. 'wtr' : _is_bit_set(left, 7),
  1684. # Byte 1
  1685. 'mcr' : _is_bit_set(left, 8),
  1686. 'dsisr' : _is_bit_set(left, 9),
  1687. 'lp' : _is_bit_set(left, 10),
  1688. 'ri' : _is_bit_set(left, 11),
  1689. 'dabrx' : _is_bit_set(left, 12),
  1690. 'sprg3' : _is_bit_set(left, 13),
  1691. 'rislb' : _is_bit_set(left, 14),
  1692. 'pp' : _is_bit_set(left, 15),
  1693. # Byte 2
  1694. 'vpm' : _is_bit_set(left, 16),
  1695. 'dss_2.05' : _is_bit_set(left, 17),
  1696. #'reserved' : _is_bit_set(left, 18),
  1697. 'dar' : _is_bit_set(left, 19),
  1698. #'reserved' : _is_bit_set(left, 20),
  1699. 'ppr' : _is_bit_set(left, 21),
  1700. 'dss_2.02' : _is_bit_set(left, 22),
  1701. 'dss_2.06' : _is_bit_set(left, 23),
  1702. # Byte 3
  1703. 'lsd_in_dscr' : _is_bit_set(left, 24),
  1704. 'ugr_in_dscr' : _is_bit_set(left, 25),
  1705. #'reserved' : _is_bit_set(left, 26),
  1706. #'reserved' : _is_bit_set(left, 27),
  1707. #'reserved' : _is_bit_set(left, 28),
  1708. #'reserved' : _is_bit_set(left, 29),
  1709. #'reserved' : _is_bit_set(left, 30),
  1710. #'reserved' : _is_bit_set(left, 31),
  1711. # Byte 4
  1712. 'sso_2.06' : _is_bit_set(right, 0),
  1713. #'reserved' : _is_bit_set(right, 1),
  1714. #'reserved' : _is_bit_set(right, 2),
  1715. #'reserved' : _is_bit_set(right, 3),
  1716. #'reserved' : _is_bit_set(right, 4),
  1717. #'reserved' : _is_bit_set(right, 5),
  1718. #'reserved' : _is_bit_set(right, 6),
  1719. #'reserved' : _is_bit_set(right, 7),
  1720. # Byte 5
  1721. 'le' : _is_bit_set(right, 8),
  1722. 'cfar' : _is_bit_set(right, 9),
  1723. 'eb' : _is_bit_set(right, 10),
  1724. 'lsq_2.07' : _is_bit_set(right, 11),
  1725. #'reserved' : _is_bit_set(right, 12),
  1726. #'reserved' : _is_bit_set(right, 13),
  1727. #'reserved' : _is_bit_set(right, 14),
  1728. #'reserved' : _is_bit_set(right, 15),
  1729. # Byte 6
  1730. 'dss_2.07' : _is_bit_set(right, 16),
  1731. #'reserved' : _is_bit_set(right, 17),
  1732. #'reserved' : _is_bit_set(right, 18),
  1733. #'reserved' : _is_bit_set(right, 19),
  1734. #'reserved' : _is_bit_set(right, 20),
  1735. #'reserved' : _is_bit_set(right, 21),
  1736. #'reserved' : _is_bit_set(right, 22),
  1737. #'reserved' : _is_bit_set(right, 23),
  1738. # Byte 7
  1739. #'reserved' : _is_bit_set(right, 24),
  1740. #'reserved' : _is_bit_set(right, 25),
  1741. #'reserved' : _is_bit_set(right, 26),
  1742. #'reserved' : _is_bit_set(right, 27),
  1743. #'reserved' : _is_bit_set(right, 28),
  1744. #'reserved' : _is_bit_set(right, 29),
  1745. #'reserved' : _is_bit_set(right, 30),
  1746. #'reserved' : _is_bit_set(right, 31),
  1747. }
  1748. # Get a list of only the flags that are true
  1749. flags = [k for k, v in flags.items() if v]
  1750. flags.sort()
  1751. info = {
  1752. 'flags' : flags
  1753. }
  1754. info = _filter_dict_keys_with_empty_values(info)
  1755. g_trace.success()
  1756. return info
  1757. except Exception as err:
  1758. g_trace.fail(err)
  1759. return {}
  1760. def _get_cpu_info_from_cat_var_run_dmesg_boot():
  1761. '''
  1762. Returns the CPU info gathered from /var/run/dmesg.boot.
  1763. Returns {} if dmesg is not found or does not have the desired info.
  1764. '''
  1765. g_trace.header('Tying to get info from the /var/run/dmesg.boot log ...')
  1766. # Just return {} if there is no /var/run/dmesg.boot
  1767. if not DataSource.has_var_run_dmesg_boot():
  1768. g_trace.fail('Failed to find /var/run/dmesg.boot file. Skipping ...')
  1769. return {}
  1770. # If dmesg.boot fails return {}
  1771. returncode, output = DataSource.cat_var_run_dmesg_boot()
  1772. if output is None or returncode != 0:
  1773. g_trace.fail('Failed to run \"cat /var/run/dmesg.boot\". Skipping ...')
  1774. return {}
  1775. info = _parse_dmesg_output(output)
  1776. g_trace.success()
  1777. return info
  1778. def _get_cpu_info_from_sysctl():
  1779. '''
  1780. Returns the CPU info gathered from sysctl.
  1781. Returns {} if sysctl is not found.
  1782. '''
  1783. g_trace.header('Tying to get info from sysctl ...')
  1784. try:
  1785. # Just return {} if there is no sysctl
  1786. if not DataSource.has_sysctl():
  1787. g_trace.fail('Failed to find sysctl. Skipping ...')
  1788. return {}
  1789. # If sysctl fails return {}
  1790. returncode, output = DataSource.sysctl_machdep_cpu_hw_cpufrequency()
  1791. if output is None or returncode != 0:
  1792. g_trace.fail('Failed to run \"sysctl machdep.cpu hw.cpufrequency\". Skipping ...')
  1793. return {}
  1794. # Various fields
  1795. vendor_id = _get_field(False, output, None, None, 'machdep.cpu.vendor')
  1796. processor_brand = _get_field(True, output, None, None, 'machdep.cpu.brand_string')
  1797. cache_size = _get_field(False, output, int, 0, 'machdep.cpu.cache.size')
  1798. stepping = _get_field(False, output, int, 0, 'machdep.cpu.stepping')
  1799. model = _get_field(False, output, int, 0, 'machdep.cpu.model')
  1800. family = _get_field(False, output, int, 0, 'machdep.cpu.family')
  1801. # Flags
  1802. flags = _get_field(False, output, None, '', 'machdep.cpu.features').lower().split()
  1803. flags.extend(_get_field(False, output, None, '', 'machdep.cpu.leaf7_features').lower().split())
  1804. flags.extend(_get_field(False, output, None, '', 'machdep.cpu.extfeatures').lower().split())
  1805. flags.sort()
  1806. # Convert from GHz/MHz string to Hz
  1807. hz_advertised, scale = _parse_cpu_brand_string(processor_brand)
  1808. hz_actual = _get_field(False, output, None, None, 'hw.cpufrequency')
  1809. hz_actual = _to_decimal_string(hz_actual)
  1810. info = {
  1811. 'vendor_id_raw' : vendor_id,
  1812. 'brand_raw' : processor_brand,
  1813. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale),
  1814. 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 0),
  1815. 'hz_advertised' : _hz_short_to_full(hz_advertised, scale),
  1816. 'hz_actual' : _hz_short_to_full(hz_actual, 0),
  1817. 'l2_cache_size' : int(cache_size) * 1024,
  1818. 'stepping' : stepping,
  1819. 'model' : model,
  1820. 'family' : family,
  1821. 'flags' : flags
  1822. }
  1823. info = _filter_dict_keys_with_empty_values(info)
  1824. g_trace.success()
  1825. return info
  1826. except Exception as err:
  1827. g_trace.fail(err)
  1828. return {}
  1829. def _get_cpu_info_from_sysinfo():
  1830. '''
  1831. Returns the CPU info gathered from sysinfo.
  1832. Returns {} if sysinfo is not found.
  1833. '''
  1834. info = _get_cpu_info_from_sysinfo_v1()
  1835. info.update(_get_cpu_info_from_sysinfo_v2())
  1836. return info
  1837. def _get_cpu_info_from_sysinfo_v1():
  1838. '''
  1839. Returns the CPU info gathered from sysinfo.
  1840. Returns {} if sysinfo is not found.
  1841. '''
  1842. g_trace.header('Tying to get info from sysinfo version 1 ...')
  1843. try:
  1844. # Just return {} if there is no sysinfo
  1845. if not DataSource.has_sysinfo():
  1846. g_trace.fail('Failed to find sysinfo. Skipping ...')
  1847. return {}
  1848. # If sysinfo fails return {}
  1849. returncode, output = DataSource.sysinfo_cpu()
  1850. if output is None or returncode != 0:
  1851. g_trace.fail('Failed to run \"sysinfo -cpu\". Skipping ...')
  1852. return {}
  1853. # Various fields
  1854. vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ')
  1855. processor_brand = output.split('CPU #0: "')[1].split('"\n')[0].strip()
  1856. cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size')
  1857. stepping = int(output.split(', stepping ')[1].split(',')[0].strip())
  1858. model = int(output.split(', model ')[1].split(',')[0].strip())
  1859. family = int(output.split(', family ')[1].split(',')[0].strip())
  1860. # Flags
  1861. flags = []
  1862. for line in output.split('\n'):
  1863. if line.startswith('\t\t'):
  1864. for flag in line.strip().lower().split():
  1865. flags.append(flag)
  1866. flags.sort()
  1867. # Convert from GHz/MHz string to Hz
  1868. hz_advertised, scale = _parse_cpu_brand_string(processor_brand)
  1869. hz_actual = hz_advertised
  1870. info = {
  1871. 'vendor_id_raw' : vendor_id,
  1872. 'brand_raw' : processor_brand,
  1873. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale),
  1874. 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, scale),
  1875. 'hz_advertised' : _hz_short_to_full(hz_advertised, scale),
  1876. 'hz_actual' : _hz_short_to_full(hz_actual, scale),
  1877. 'l2_cache_size' : _to_friendly_bytes(cache_size),
  1878. 'stepping' : stepping,
  1879. 'model' : model,
  1880. 'family' : family,
  1881. 'flags' : flags
  1882. }
  1883. info = _filter_dict_keys_with_empty_values(info)
  1884. g_trace.success()
  1885. return info
  1886. except Exception as err:
  1887. g_trace.fail(err)
  1888. #raise # NOTE: To have this throw on error, uncomment this line
  1889. return {}
  1890. def _get_cpu_info_from_sysinfo_v2():
  1891. '''
  1892. Returns the CPU info gathered from sysinfo.
  1893. Returns {} if sysinfo is not found.
  1894. '''
  1895. g_trace.header('Tying to get info from sysinfo version 2 ...')
  1896. try:
  1897. # Just return {} if there is no sysinfo
  1898. if not DataSource.has_sysinfo():
  1899. g_trace.fail('Failed to find sysinfo. Skipping ...')
  1900. return {}
  1901. # If sysinfo fails return {}
  1902. returncode, output = DataSource.sysinfo_cpu()
  1903. if output is None or returncode != 0:
  1904. g_trace.fail('Failed to run \"sysinfo -cpu\". Skipping ...')
  1905. return {}
  1906. # Various fields
  1907. vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ')
  1908. processor_brand = output.split('CPU #0: "')[1].split('"\n')[0].strip()
  1909. cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size')
  1910. signature = output.split('Signature:')[1].split('\n')[0].strip()
  1911. #
  1912. stepping = int(signature.split('stepping ')[1].split(',')[0].strip())
  1913. model = int(signature.split('model ')[1].split(',')[0].strip())
  1914. family = int(signature.split('family ')[1].split(',')[0].strip())
  1915. # Flags
  1916. def get_subsection_flags(output):
  1917. retval = []
  1918. for line in output.split('\n')[1:]:
  1919. if not line.startswith(' ') and not line.startswith(' '): break
  1920. for entry in line.strip().lower().split(' '):
  1921. retval.append(entry)
  1922. return retval
  1923. flags = get_subsection_flags(output.split('Features: ')[1]) + \
  1924. get_subsection_flags(output.split('Extended Features (0x00000001): ')[1]) + \
  1925. get_subsection_flags(output.split('Extended Features (0x80000001): ')[1])
  1926. flags.sort()
  1927. # Convert from GHz/MHz string to Hz
  1928. lines = [n for n in output.split('\n') if n]
  1929. raw_hz = lines[0].split('running at ')[1].strip().lower()
  1930. hz_advertised = raw_hz.rstrip('mhz').rstrip('ghz').strip()
  1931. hz_advertised = _to_decimal_string(hz_advertised)
  1932. hz_actual = hz_advertised
  1933. scale = 0
  1934. if raw_hz.endswith('mhz'):
  1935. scale = 6
  1936. elif raw_hz.endswith('ghz'):
  1937. scale = 9
  1938. info = {
  1939. 'vendor_id_raw' : vendor_id,
  1940. 'brand_raw' : processor_brand,
  1941. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale),
  1942. 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, scale),
  1943. 'hz_advertised' : _hz_short_to_full(hz_advertised, scale),
  1944. 'hz_actual' : _hz_short_to_full(hz_actual, scale),
  1945. 'l2_cache_size' : _to_friendly_bytes(cache_size),
  1946. 'stepping' : stepping,
  1947. 'model' : model,
  1948. 'family' : family,
  1949. 'flags' : flags
  1950. }
  1951. info = _filter_dict_keys_with_empty_values(info)
  1952. g_trace.success()
  1953. return info
  1954. except Exception as err:
  1955. g_trace.fail(err)
  1956. #raise # NOTE: To have this throw on error, uncomment this line
  1957. return {}
  1958. def _get_cpu_info_from_wmic():
  1959. '''
  1960. Returns the CPU info gathered from WMI.
  1961. Returns {} if not on Windows, or wmic is not installed.
  1962. '''
  1963. g_trace.header('Tying to get info from wmic ...')
  1964. try:
  1965. # Just return {} if not Windows or there is no wmic
  1966. if not DataSource.is_windows or not DataSource.has_wmic():
  1967. g_trace.fail('Failed to find WMIC, or not on Windows. Skipping ...')
  1968. return {}
  1969. returncode, output = DataSource.wmic_cpu()
  1970. if output is None or returncode != 0:
  1971. g_trace.fail('Failed to run wmic. Skipping ...')
  1972. return {}
  1973. # Break the list into key values pairs
  1974. value = output.split("\n")
  1975. value = [s.rstrip().split('=') for s in value if '=' in s]
  1976. value = {k: v for k, v in value if v}
  1977. # Get the advertised MHz
  1978. processor_brand = value.get('Name')
  1979. hz_advertised, scale_advertised = _parse_cpu_brand_string(processor_brand)
  1980. # Get the actual MHz
  1981. hz_actual = value.get('CurrentClockSpeed')
  1982. scale_actual = 6
  1983. if hz_actual:
  1984. hz_actual = _to_decimal_string(hz_actual)
  1985. # Get cache sizes
  1986. l2_cache_size = value.get('L2CacheSize') # NOTE: L2CacheSize is in kilobytes
  1987. if l2_cache_size:
  1988. l2_cache_size = int(l2_cache_size) * 1024
  1989. l3_cache_size = value.get('L3CacheSize') # NOTE: L3CacheSize is in kilobytes
  1990. if l3_cache_size:
  1991. l3_cache_size = int(l3_cache_size) * 1024
  1992. # Get family, model, and stepping
  1993. family, model, stepping = '', '', ''
  1994. description = value.get('Description') or value.get('Caption')
  1995. entries = description.split(' ')
  1996. if 'Family' in entries and entries.index('Family') < len(entries)-1:
  1997. i = entries.index('Family')
  1998. family = int(entries[i + 1])
  1999. if 'Model' in entries and entries.index('Model') < len(entries)-1:
  2000. i = entries.index('Model')
  2001. model = int(entries[i + 1])
  2002. if 'Stepping' in entries and entries.index('Stepping') < len(entries)-1:
  2003. i = entries.index('Stepping')
  2004. stepping = int(entries[i + 1])
  2005. info = {
  2006. 'vendor_id_raw' : value.get('Manufacturer'),
  2007. 'brand_raw' : processor_brand,
  2008. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale_advertised),
  2009. 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, scale_actual),
  2010. 'hz_advertised' : _hz_short_to_full(hz_advertised, scale_advertised),
  2011. 'hz_actual' : _hz_short_to_full(hz_actual, scale_actual),
  2012. 'l2_cache_size' : l2_cache_size,
  2013. 'l3_cache_size' : l3_cache_size,
  2014. 'stepping' : stepping,
  2015. 'model' : model,
  2016. 'family' : family,
  2017. }
  2018. info = _filter_dict_keys_with_empty_values(info)
  2019. g_trace.success()
  2020. return info
  2021. except Exception as err:
  2022. g_trace.fail(err)
  2023. #raise # NOTE: To have this throw on error, uncomment this line
  2024. return {}
  2025. def _get_cpu_info_from_registry():
  2026. '''
  2027. Returns the CPU info gathered from the Windows Registry.
  2028. Returns {} if not on Windows.
  2029. '''
  2030. g_trace.header('Tying to get info from Windows registry ...')
  2031. try:
  2032. # Just return {} if not on Windows
  2033. if not DataSource.is_windows:
  2034. g_trace.fail('Not running on Windows. Skipping ...')
  2035. return {}
  2036. # Get the CPU name
  2037. processor_brand = DataSource.winreg_processor_brand().strip()
  2038. # Get the CPU vendor id
  2039. vendor_id = DataSource.winreg_vendor_id_raw()
  2040. # Get the CPU arch and bits
  2041. arch_string_raw = DataSource.winreg_arch_string_raw()
  2042. arch, bits = _parse_arch(arch_string_raw)
  2043. # Get the actual CPU Hz
  2044. hz_actual = DataSource.winreg_hz_actual()
  2045. hz_actual = _to_decimal_string(hz_actual)
  2046. # Get the advertised CPU Hz
  2047. hz_advertised, scale = _parse_cpu_brand_string(processor_brand)
  2048. # If advertised hz not found, use the actual hz
  2049. if hz_advertised == '0.0':
  2050. scale = 6
  2051. hz_advertised = _to_decimal_string(hz_actual)
  2052. # Get the CPU features
  2053. feature_bits = DataSource.winreg_feature_bits()
  2054. def is_set(bit):
  2055. mask = 0x80000000 >> bit
  2056. retval = mask & feature_bits > 0
  2057. return retval
  2058. # http://en.wikipedia.org/wiki/CPUID
  2059. # http://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean
  2060. # http://www.lohninger.com/helpcsuite/public_constants_cpuid.htm
  2061. flags = {
  2062. 'fpu' : is_set(0), # Floating Point Unit
  2063. 'vme' : is_set(1), # V86 Mode Extensions
  2064. 'de' : is_set(2), # Debug Extensions - I/O breakpoints supported
  2065. 'pse' : is_set(3), # Page Size Extensions (4 MB pages supported)
  2066. 'tsc' : is_set(4), # Time Stamp Counter and RDTSC instruction are available
  2067. 'msr' : is_set(5), # Model Specific Registers
  2068. 'pae' : is_set(6), # Physical Address Extensions (36 bit address, 2MB pages)
  2069. 'mce' : is_set(7), # Machine Check Exception supported
  2070. 'cx8' : is_set(8), # Compare Exchange Eight Byte instruction available
  2071. 'apic' : is_set(9), # Local APIC present (multiprocessor operation support)
  2072. 'sepamd' : is_set(10), # Fast system calls (AMD only)
  2073. 'sep' : is_set(11), # Fast system calls
  2074. 'mtrr' : is_set(12), # Memory Type Range Registers
  2075. 'pge' : is_set(13), # Page Global Enable
  2076. 'mca' : is_set(14), # Machine Check Architecture
  2077. 'cmov' : is_set(15), # Conditional MOVe instructions
  2078. 'pat' : is_set(16), # Page Attribute Table
  2079. 'pse36' : is_set(17), # 36 bit Page Size Extensions
  2080. 'serial' : is_set(18), # Processor Serial Number
  2081. 'clflush' : is_set(19), # Cache Flush
  2082. #'reserved1' : is_set(20), # reserved
  2083. 'dts' : is_set(21), # Debug Trace Store
  2084. 'acpi' : is_set(22), # ACPI support
  2085. 'mmx' : is_set(23), # MultiMedia Extensions
  2086. 'fxsr' : is_set(24), # FXSAVE and FXRSTOR instructions
  2087. 'sse' : is_set(25), # SSE instructions
  2088. 'sse2' : is_set(26), # SSE2 (WNI) instructions
  2089. 'ss' : is_set(27), # self snoop
  2090. #'reserved2' : is_set(28), # reserved
  2091. 'tm' : is_set(29), # Automatic clock control
  2092. 'ia64' : is_set(30), # IA64 instructions
  2093. '3dnow' : is_set(31) # 3DNow! instructions available
  2094. }
  2095. # Get a list of only the flags that are true
  2096. flags = [k for k, v in flags.items() if v]
  2097. flags.sort()
  2098. info = {
  2099. 'vendor_id_raw' : vendor_id,
  2100. 'brand_raw' : processor_brand,
  2101. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale),
  2102. 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 6),
  2103. 'hz_advertised' : _hz_short_to_full(hz_advertised, scale),
  2104. 'hz_actual' : _hz_short_to_full(hz_actual, 6),
  2105. 'flags' : flags
  2106. }
  2107. info = _filter_dict_keys_with_empty_values(info)
  2108. g_trace.success()
  2109. return info
  2110. except Exception as err:
  2111. g_trace.fail(err)
  2112. return {}
  2113. def _get_cpu_info_from_kstat():
  2114. '''
  2115. Returns the CPU info gathered from isainfo and kstat.
  2116. Returns {} if isainfo or kstat are not found.
  2117. '''
  2118. g_trace.header('Tying to get info from kstat ...')
  2119. try:
  2120. # Just return {} if there is no isainfo or kstat
  2121. if not DataSource.has_isainfo() or not DataSource.has_kstat():
  2122. g_trace.fail('Failed to find isinfo or kstat. Skipping ...')
  2123. return {}
  2124. # If isainfo fails return {}
  2125. returncode, flag_output = DataSource.isainfo_vb()
  2126. if flag_output is None or returncode != 0:
  2127. g_trace.fail('Failed to run \"isainfo -vb\". Skipping ...')
  2128. return {}
  2129. # If kstat fails return {}
  2130. returncode, kstat = DataSource.kstat_m_cpu_info()
  2131. if kstat is None or returncode != 0:
  2132. g_trace.fail('Failed to run \"kstat -m cpu_info\". Skipping ...')
  2133. return {}
  2134. # Various fields
  2135. vendor_id = kstat.split('\tvendor_id ')[1].split('\n')[0].strip()
  2136. processor_brand = kstat.split('\tbrand ')[1].split('\n')[0].strip()
  2137. stepping = int(kstat.split('\tstepping ')[1].split('\n')[0].strip())
  2138. model = int(kstat.split('\tmodel ')[1].split('\n')[0].strip())
  2139. family = int(kstat.split('\tfamily ')[1].split('\n')[0].strip())
  2140. # Flags
  2141. flags = flag_output.strip().split('\n')[-1].strip().lower().split()
  2142. flags.sort()
  2143. # Convert from GHz/MHz string to Hz
  2144. scale = 6
  2145. hz_advertised = kstat.split('\tclock_MHz ')[1].split('\n')[0].strip()
  2146. hz_advertised = _to_decimal_string(hz_advertised)
  2147. # Convert from GHz/MHz string to Hz
  2148. hz_actual = kstat.split('\tcurrent_clock_Hz ')[1].split('\n')[0].strip()
  2149. hz_actual = _to_decimal_string(hz_actual)
  2150. info = {
  2151. 'vendor_id_raw' : vendor_id,
  2152. 'brand_raw' : processor_brand,
  2153. 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale),
  2154. 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 0),
  2155. 'hz_advertised' : _hz_short_to_full(hz_advertised, scale),
  2156. 'hz_actual' : _hz_short_to_full(hz_actual, 0),
  2157. 'stepping' : stepping,
  2158. 'model' : model,
  2159. 'family' : family,
  2160. 'flags' : flags
  2161. }
  2162. info = _filter_dict_keys_with_empty_values(info)
  2163. g_trace.success()
  2164. return info
  2165. except Exception as err:
  2166. g_trace.fail(err)
  2167. return {}
  2168. def _get_cpu_info_from_platform_uname():
  2169. g_trace.header('Tying to get info from platform.uname ...')
  2170. try:
  2171. uname = DataSource.uname_string_raw.split(',')[0]
  2172. family, model, stepping = (None, None, None)
  2173. entries = uname.split(' ')
  2174. if 'Family' in entries and entries.index('Family') < len(entries)-1:
  2175. i = entries.index('Family')
  2176. family = int(entries[i + 1])
  2177. if 'Model' in entries and entries.index('Model') < len(entries)-1:
  2178. i = entries.index('Model')
  2179. model = int(entries[i + 1])
  2180. if 'Stepping' in entries and entries.index('Stepping') < len(entries)-1:
  2181. i = entries.index('Stepping')
  2182. stepping = int(entries[i + 1])
  2183. info = {
  2184. 'family' : family,
  2185. 'model' : model,
  2186. 'stepping' : stepping
  2187. }
  2188. info = _filter_dict_keys_with_empty_values(info)
  2189. g_trace.success()
  2190. return info
  2191. except Exception as err:
  2192. g_trace.fail(err)
  2193. return {}
  2194. def _get_cpu_info_internal():
  2195. '''
  2196. Returns the CPU info by using the best sources of information for your OS.
  2197. Returns {} if nothing is found.
  2198. '''
  2199. g_trace.write('!' * 80)
  2200. # Get the CPU arch and bits
  2201. arch, bits = _parse_arch(DataSource.arch_string_raw)
  2202. friendly_maxsize = { 2**31-1: '32 bit', 2**63-1: '64 bit' }.get(sys.maxsize) or 'unknown bits'
  2203. friendly_version = "{0}.{1}.{2}.{3}.{4}".format(*sys.version_info)
  2204. PYTHON_VERSION = "{0} ({1})".format(friendly_version, friendly_maxsize)
  2205. info = {
  2206. 'python_version' : PYTHON_VERSION,
  2207. 'cpuinfo_version' : CPUINFO_VERSION,
  2208. 'cpuinfo_version_string' : CPUINFO_VERSION_STRING,
  2209. 'arch' : arch,
  2210. 'bits' : bits,
  2211. 'count' : DataSource.cpu_count,
  2212. 'arch_string_raw' : DataSource.arch_string_raw,
  2213. }
  2214. g_trace.write("python_version: {0}".format(info['python_version']))
  2215. g_trace.write("cpuinfo_version: {0}".format(info['cpuinfo_version']))
  2216. g_trace.write("arch: {0}".format(info['arch']))
  2217. g_trace.write("bits: {0}".format(info['bits']))
  2218. g_trace.write("count: {0}".format(info['count']))
  2219. g_trace.write("arch_string_raw: {0}".format(info['arch_string_raw']))
  2220. # Try the Windows wmic
  2221. _copy_new_fields(info, _get_cpu_info_from_wmic())
  2222. # Try the Windows registry
  2223. _copy_new_fields(info, _get_cpu_info_from_registry())
  2224. # Try /proc/cpuinfo
  2225. _copy_new_fields(info, _get_cpu_info_from_proc_cpuinfo())
  2226. # Try cpufreq-info
  2227. _copy_new_fields(info, _get_cpu_info_from_cpufreq_info())
  2228. # Try LSCPU
  2229. _copy_new_fields(info, _get_cpu_info_from_lscpu())
  2230. # Try sysctl
  2231. _copy_new_fields(info, _get_cpu_info_from_sysctl())
  2232. # Try kstat
  2233. _copy_new_fields(info, _get_cpu_info_from_kstat())
  2234. # Try dmesg
  2235. _copy_new_fields(info, _get_cpu_info_from_dmesg())
  2236. # Try /var/run/dmesg.boot
  2237. _copy_new_fields(info, _get_cpu_info_from_cat_var_run_dmesg_boot())
  2238. # Try lsprop ibm,pa-features
  2239. _copy_new_fields(info, _get_cpu_info_from_ibm_pa_features())
  2240. # Try sysinfo
  2241. _copy_new_fields(info, _get_cpu_info_from_sysinfo())
  2242. # Try querying the CPU cpuid register
  2243. # FIXME: This should print stdout and stderr to trace log
  2244. _copy_new_fields(info, _get_cpu_info_from_cpuid())
  2245. # Try platform.uname
  2246. _copy_new_fields(info, _get_cpu_info_from_platform_uname())
  2247. g_trace.write('!' * 80)
  2248. return info
  2249. def get_cpu_info_json():
  2250. '''
  2251. Returns the CPU info by using the best sources of information for your OS.
  2252. Returns the result in a json string
  2253. '''
  2254. import json
  2255. output = None
  2256. # If running under pyinstaller, run normally
  2257. if getattr(sys, 'frozen', False):
  2258. info = _get_cpu_info_internal()
  2259. output = json.dumps(info)
  2260. output = "{0}".format(output)
  2261. # if not running under pyinstaller, run in another process.
  2262. # This is done because multiprocesing has a design flaw that
  2263. # causes non main programs to run multiple times on Windows.
  2264. else:
  2265. from subprocess import Popen, PIPE
  2266. command = [sys.executable, __file__, '--json']
  2267. p1 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
  2268. output = p1.communicate()[0]
  2269. if p1.returncode != 0:
  2270. return "{}"
  2271. output = output.decode(encoding='UTF-8')
  2272. return output
  2273. def get_cpu_info():
  2274. '''
  2275. Returns the CPU info by using the best sources of information for your OS.
  2276. Returns the result in a dict
  2277. '''
  2278. import json
  2279. output = get_cpu_info_json()
  2280. # Convert JSON to Python with non unicode strings
  2281. output = json.loads(output, object_hook = _utf_to_str)
  2282. return output
  2283. def main():
  2284. from argparse import ArgumentParser
  2285. import json
  2286. # Parse args
  2287. parser = ArgumentParser(description='Gets CPU info with pure Python')
  2288. parser.add_argument('--json', action='store_true', help='Return the info in JSON format')
  2289. parser.add_argument('--version', action='store_true', help='Return the version of py-cpuinfo')
  2290. parser.add_argument('--trace', action='store_true', help='Traces code paths used to find CPU info to file')
  2291. args = parser.parse_args()
  2292. global g_trace
  2293. g_trace = Trace(args.trace, False)
  2294. try:
  2295. _check_arch()
  2296. except Exception as err:
  2297. sys.stderr.write(str(err) + "\n")
  2298. sys.exit(1)
  2299. info = _get_cpu_info_internal()
  2300. if not info:
  2301. sys.stderr.write("Failed to find cpu info\n")
  2302. sys.exit(1)
  2303. if args.json:
  2304. print(json.dumps(info))
  2305. elif args.version:
  2306. print(CPUINFO_VERSION_STRING)
  2307. else:
  2308. print('Python Version: {0}'.format(info.get('python_version', '')))
  2309. print('Cpuinfo Version: {0}'.format(info.get('cpuinfo_version_string', '')))
  2310. print('Vendor ID Raw: {0}'.format(info.get('vendor_id_raw', '')))
  2311. print('Hardware Raw: {0}'.format(info.get('hardware_raw', '')))
  2312. print('Brand Raw: {0}'.format(info.get('brand_raw', '')))
  2313. print('Hz Advertised Friendly: {0}'.format(info.get('hz_advertised_friendly', '')))
  2314. print('Hz Actual Friendly: {0}'.format(info.get('hz_actual_friendly', '')))
  2315. print('Hz Advertised: {0}'.format(info.get('hz_advertised', '')))
  2316. print('Hz Actual: {0}'.format(info.get('hz_actual', '')))
  2317. print('Arch: {0}'.format(info.get('arch', '')))
  2318. print('Bits: {0}'.format(info.get('bits', '')))
  2319. print('Count: {0}'.format(info.get('count', '')))
  2320. print('Arch String Raw: {0}'.format(info.get('arch_string_raw', '')))
  2321. print('L1 Data Cache Size: {0}'.format(info.get('l1_data_cache_size', '')))
  2322. print('L1 Instruction Cache Size: {0}'.format(info.get('l1_instruction_cache_size', '')))
  2323. print('L2 Cache Size: {0}'.format(info.get('l2_cache_size', '')))
  2324. print('L2 Cache Line Size: {0}'.format(info.get('l2_cache_line_size', '')))
  2325. print('L2 Cache Associativity: {0}'.format(info.get('l2_cache_associativity', '')))
  2326. print('L3 Cache Size: {0}'.format(info.get('l3_cache_size', '')))
  2327. print('Stepping: {0}'.format(info.get('stepping', '')))
  2328. print('Model: {0}'.format(info.get('model', '')))
  2329. print('Family: {0}'.format(info.get('family', '')))
  2330. print('Processor Type: {0}'.format(info.get('processor_type', '')))
  2331. print('Flags: {0}'.format(', '.join(info.get('flags', ''))))
  2332. if __name__ == '__main__':
  2333. main()
  2334. else:
  2335. g_trace = Trace(False, False)
  2336. _check_arch()