Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cpuinfo/cpuinfo.py: 38%

1419 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-05-10 06:15 +0000

1#!/usr/bin/env python 

2# -*- coding: UTF-8 -*- 

3 

4# Copyright (c) 2014-2022 Matthew Brennan Jones <matthew.brennan.jones@gmail.com> 

5# Py-cpuinfo gets CPU info with pure Python 

6# It uses the MIT License 

7# It is hosted at: https://github.com/workhorsy/py-cpuinfo 

8# 

9# Permission is hereby granted, free of charge, to any person obtaining 

10# a copy of this software and associated documentation files (the 

11# "Software"), to deal in the Software without restriction, including 

12# without limitation the rights to use, copy, modify, merge, publish, 

13# distribute, sublicense, and/or sell copies of the Software, and to 

14# permit persons to whom the Software is furnished to do so, subject to 

15# the following conditions: 

16# 

17# The above copyright notice and this permission notice shall be included 

18# in all copies or substantial portions of the Software. 

19# 

20# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 

21# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 

22# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 

23# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 

24# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 

25# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 

26# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

27 

28CPUINFO_VERSION = (9, 0, 0) 

29CPUINFO_VERSION_STRING = '.'.join([str(n) for n in CPUINFO_VERSION]) 

30 

31import os, sys 

32import platform 

33import multiprocessing 

34import ctypes 

35 

36 

37CAN_CALL_CPUID_IN_SUBPROCESS = True 

38 

39g_trace = None 

40 

41 

42class Trace(object): 

43 def __init__(self, is_active, is_stored_in_string): 

44 self._is_active = is_active 

45 if not self._is_active: 

46 return 

47 

48 from datetime import datetime 

49 from io import StringIO 

50 

51 if is_stored_in_string: 

52 self._output = StringIO() 

53 else: 

54 date = datetime.now().strftime("%Y-%m-%d_%H-%M-%S-%f") 

55 self._output = open('cpuinfo_trace_{0}.trace'.format(date), 'w') 

56 

57 self._stdout = StringIO() 

58 self._stderr = StringIO() 

59 self._err = None 

60 

61 def header(self, msg): 

62 if not self._is_active: return 

63 

64 from inspect import stack 

65 frame = stack()[1] 

66 file = frame[1] 

67 line = frame[2] 

68 self._output.write("{0} ({1} {2})\n".format(msg, file, line)) 

69 self._output.flush() 

70 

71 def success(self): 

72 if not self._is_active: return 

73 

74 from inspect import stack 

75 frame = stack()[1] 

76 file = frame[1] 

77 line = frame[2] 

78 

79 self._output.write("Success ... ({0} {1})\n\n".format(file, line)) 

80 self._output.flush() 

81 

82 def fail(self, msg): 

83 if not self._is_active: return 

84 

85 from inspect import stack 

86 frame = stack()[1] 

87 file = frame[1] 

88 line = frame[2] 

89 

90 if isinstance(msg, str): 

91 msg = ''.join(['\t' + line for line in msg.split('\n')]) + '\n' 

92 

93 self._output.write(msg) 

94 self._output.write("Failed ... ({0} {1})\n\n".format(file, line)) 

95 self._output.flush() 

96 elif isinstance(msg, Exception): 

97 from traceback import format_exc 

98 err_string = format_exc() 

99 self._output.write("\tFailed ... ({0} {1})\n".format(file, line)) 

100 self._output.write(''.join(['\t\t{0}\n'.format(n) for n in err_string.split('\n')]) + '\n') 

101 self._output.flush() 

102 

103 def command_header(self, msg): 

104 if not self._is_active: return 

105 

106 from inspect import stack 

107 frame = stack()[3] 

108 file = frame[1] 

109 line = frame[2] 

110 self._output.write("\t{0} ({1} {2})\n".format(msg, file, line)) 

111 self._output.flush() 

112 

113 def command_output(self, msg, output): 

114 if not self._is_active: return 

115 

116 self._output.write("\t\t{0}\n".format(msg)) 

117 self._output.write(''.join(['\t\t\t{0}\n'.format(n) for n in output.split('\n')]) + '\n') 

118 self._output.flush() 

119 

120 def keys(self, keys, info, new_info): 

121 if not self._is_active: return 

122 

123 from inspect import stack 

124 frame = stack()[2] 

125 file = frame[1] 

126 line = frame[2] 

127 

128 # List updated keys 

129 self._output.write("\tChanged keys ({0} {1})\n".format(file, line)) 

130 changed_keys = [key for key in keys if key in info and key in new_info and info[key] != new_info[key]] 

131 if changed_keys: 

132 for key in changed_keys: 

133 self._output.write('\t\t{0}: {1} to {2}\n'.format(key, info[key], new_info[key])) 

134 else: 

135 self._output.write('\t\tNone\n') 

136 

137 # List new keys 

138 self._output.write("\tNew keys ({0} {1})\n".format(file, line)) 

139 new_keys = [key for key in keys if key in new_info and key not in info] 

140 if new_keys: 

141 for key in new_keys: 

142 self._output.write('\t\t{0}: {1}\n'.format(key, new_info[key])) 

143 else: 

144 self._output.write('\t\tNone\n') 

145 

146 self._output.write('\n') 

147 self._output.flush() 

148 

149 def write(self, msg): 

150 if not self._is_active: return 

151 

152 self._output.write(msg + '\n') 

153 self._output.flush() 

154 

155 def to_dict(self, info, is_fail): 

156 return { 

157 'output' : self._output.getvalue(), 

158 'stdout' : self._stdout.getvalue(), 

159 'stderr' : self._stderr.getvalue(), 

160 'info' : info, 

161 'err' : self._err, 

162 'is_fail' : is_fail 

163 } 

164 

165class DataSource(object): 

166 bits = platform.architecture()[0] 

167 cpu_count = multiprocessing.cpu_count() 

168 is_windows = platform.system().lower() == 'windows' 

169 arch_string_raw = platform.machine() 

170 uname_string_raw = platform.uname()[5] 

171 can_cpuid = True 

172 

173 @staticmethod 

174 def has_proc_cpuinfo(): 

175 return os.path.exists('/proc/cpuinfo') 

176 

177 @staticmethod 

178 def has_dmesg(): 

179 return len(_program_paths('dmesg')) > 0 

180 

181 @staticmethod 

182 def has_var_run_dmesg_boot(): 

183 uname = platform.system().strip().strip('"').strip("'").strip().lower() 

184 return 'linux' in uname and os.path.exists('/var/run/dmesg.boot') 

185 

186 @staticmethod 

187 def has_cpufreq_info(): 

188 return len(_program_paths('cpufreq-info')) > 0 

189 

190 @staticmethod 

191 def has_sestatus(): 

192 return len(_program_paths('sestatus')) > 0 

193 

194 @staticmethod 

195 def has_sysctl(): 

196 return len(_program_paths('sysctl')) > 0 

197 

198 @staticmethod 

199 def has_isainfo(): 

200 return len(_program_paths('isainfo')) > 0 

201 

202 @staticmethod 

203 def has_kstat(): 

204 return len(_program_paths('kstat')) > 0 

205 

206 @staticmethod 

207 def has_sysinfo(): 

208 uname = platform.system().strip().strip('"').strip("'").strip().lower() 

209 is_beos = 'beos' in uname or 'haiku' in uname 

210 return is_beos and len(_program_paths('sysinfo')) > 0 

211 

212 @staticmethod 

213 def has_lscpu(): 

214 return len(_program_paths('lscpu')) > 0 

215 

216 @staticmethod 

217 def has_ibm_pa_features(): 

218 return len(_program_paths('lsprop')) > 0 

219 

220 @staticmethod 

221 def has_wmic(): 

222 returncode, output = _run_and_get_stdout(['wmic', 'os', 'get', 'Version']) 

223 return returncode == 0 and len(output) > 0 

224 

225 @staticmethod 

226 def cat_proc_cpuinfo(): 

227 return _run_and_get_stdout(['cat', '/proc/cpuinfo']) 

228 

229 @staticmethod 

230 def cpufreq_info(): 

231 return _run_and_get_stdout(['cpufreq-info']) 

232 

233 @staticmethod 

234 def sestatus_b(): 

235 return _run_and_get_stdout(['sestatus', '-b']) 

236 

237 @staticmethod 

238 def dmesg_a(): 

239 return _run_and_get_stdout(['dmesg', '-a']) 

240 

241 @staticmethod 

242 def cat_var_run_dmesg_boot(): 

243 return _run_and_get_stdout(['cat', '/var/run/dmesg.boot']) 

244 

245 @staticmethod 

246 def sysctl_machdep_cpu_hw_cpufrequency(): 

247 return _run_and_get_stdout(['sysctl', 'machdep.cpu', 'hw.cpufrequency']) 

248 

249 @staticmethod 

250 def isainfo_vb(): 

251 return _run_and_get_stdout(['isainfo', '-vb']) 

252 

253 @staticmethod 

254 def kstat_m_cpu_info(): 

255 return _run_and_get_stdout(['kstat', '-m', 'cpu_info']) 

256 

257 @staticmethod 

258 def sysinfo_cpu(): 

259 return _run_and_get_stdout(['sysinfo', '-cpu']) 

260 

261 @staticmethod 

262 def lscpu(): 

263 return _run_and_get_stdout(['lscpu']) 

264 

265 @staticmethod 

266 def ibm_pa_features(): 

267 import glob 

268 

269 ibm_features = glob.glob('/proc/device-tree/cpus/*/ibm,pa-features') 

270 if ibm_features: 

271 return _run_and_get_stdout(['lsprop', ibm_features[0]]) 

272 

273 @staticmethod 

274 def wmic_cpu(): 

275 return _run_and_get_stdout(['wmic', 'cpu', 'get', 'Name,CurrentClockSpeed,L2CacheSize,L3CacheSize,Description,Caption,Manufacturer', '/format:list']) 

276 

277 @staticmethod 

278 def winreg_processor_brand(): 

279 processor_brand = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "ProcessorNameString") 

280 return processor_brand.strip() 

281 

282 @staticmethod 

283 def winreg_vendor_id_raw(): 

284 vendor_id_raw = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "VendorIdentifier") 

285 return vendor_id_raw 

286 

287 @staticmethod 

288 def winreg_arch_string_raw(): 

289 arch_string_raw = _read_windows_registry_key(r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", "PROCESSOR_ARCHITECTURE") 

290 return arch_string_raw 

291 

292 @staticmethod 

293 def winreg_hz_actual(): 

294 hz_actual = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "~Mhz") 

295 hz_actual = _to_decimal_string(hz_actual) 

296 return hz_actual 

297 

298 @staticmethod 

299 def winreg_feature_bits(): 

300 feature_bits = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "FeatureSet") 

301 return feature_bits 

302 

303 

304def _program_paths(program_name): 

305 paths = [] 

306 exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep)) 

307 for p in os.environ['PATH'].split(os.pathsep): 

308 p = os.path.join(p, program_name) 

309 if os.access(p, os.X_OK): 

310 paths.append(p) 

311 for e in exts: 

312 pext = p + e 

313 if os.access(pext, os.X_OK): 

314 paths.append(pext) 

315 return paths 

316 

317def _run_and_get_stdout(command, pipe_command=None): 

318 from subprocess import Popen, PIPE 

319 

320 g_trace.command_header('Running command "' + ' '.join(command) + '" ...') 

321 

322 # Run the command normally 

323 if not pipe_command: 

324 p1 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE) 

325 # Run the command and pipe it into another command 

326 else: 

327 p2 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE) 

328 p1 = Popen(pipe_command, stdin=p2.stdout, stdout=PIPE, stderr=PIPE) 

329 p2.stdout.close() 

330 

331 # Get the stdout and stderr 

332 stdout_output, stderr_output = p1.communicate() 

333 stdout_output = stdout_output.decode(encoding='UTF-8') 

334 stderr_output = stderr_output.decode(encoding='UTF-8') 

335 

336 # Send the result to the logger 

337 g_trace.command_output('return code:', str(p1.returncode)) 

338 g_trace.command_output('stdout:', stdout_output) 

339 

340 # Return the return code and stdout 

341 return p1.returncode, stdout_output 

342 

343def _read_windows_registry_key(key_name, field_name): 

344 g_trace.command_header('Reading Registry key "{0}" field "{1}" ...'.format(key_name, field_name)) 

345 

346 try: 

347 import _winreg as winreg 

348 except ImportError as err: 

349 try: 

350 import winreg 

351 except ImportError as err: 

352 pass 

353 

354 key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_name) 

355 value = winreg.QueryValueEx(key, field_name)[0] 

356 winreg.CloseKey(key) 

357 g_trace.command_output('value:', str(value)) 

358 return value 

359 

360# Make sure we are running on a supported system 

361def _check_arch(): 

362 arch, bits = _parse_arch(DataSource.arch_string_raw) 

363 if not arch in ['X86_32', 'X86_64', 'ARM_7', 'ARM_8', 

364 'PPC_64', 'S390X', 'MIPS_32', 'MIPS_64', 

365 "RISCV_32", "RISCV_64"]: 

366 raise Exception("py-cpuinfo currently only works on X86 " 

367 "and some ARM/PPC/S390X/MIPS/RISCV CPUs.") 

368 

369def _obj_to_b64(thing): 

370 import pickle 

371 import base64 

372 

373 a = thing 

374 b = pickle.dumps(a) 

375 c = base64.b64encode(b) 

376 d = c.decode('utf8') 

377 return d 

378 

379def _b64_to_obj(thing): 

380 import pickle 

381 import base64 

382 

383 try: 

384 a = base64.b64decode(thing) 

385 b = pickle.loads(a) 

386 return b 

387 except Exception: 

388 return {} 

389 

390def _utf_to_str(input): 

391 if isinstance(input, list): 

392 return [_utf_to_str(element) for element in input] 

393 elif isinstance(input, dict): 

394 return {_utf_to_str(key): _utf_to_str(value) 

395 for key, value in input.items()} 

396 else: 

397 return input 

398 

399def _copy_new_fields(info, new_info): 

400 keys = [ 

401 'vendor_id_raw', 'hardware_raw', 'brand_raw', 'hz_advertised_friendly', 'hz_actual_friendly', 

402 'hz_advertised', 'hz_actual', 'arch', 'bits', 'count', 

403 'arch_string_raw', 'uname_string_raw', 

404 'l2_cache_size', 'l2_cache_line_size', 'l2_cache_associativity', 

405 'stepping', 'model', 'family', 

406 'processor_type', 'flags', 

407 'l3_cache_size', 'l1_data_cache_size', 'l1_instruction_cache_size' 

408 ] 

409 

410 g_trace.keys(keys, info, new_info) 

411 

412 # Update the keys with new values 

413 for key in keys: 

414 if new_info.get(key, None) and not info.get(key, None): 

415 info[key] = new_info[key] 

416 elif key == 'flags' and new_info.get('flags'): 

417 for f in new_info['flags']: 

418 if f not in info['flags']: info['flags'].append(f) 

419 info['flags'].sort() 

420 

421def _get_field_actual(cant_be_number, raw_string, field_names): 

422 for line in raw_string.splitlines(): 

423 for field_name in field_names: 

424 field_name = field_name.lower() 

425 if ':' in line: 

426 left, right = line.split(':', 1) 

427 left = left.strip().lower() 

428 right = right.strip() 

429 if left == field_name and len(right) > 0: 

430 if cant_be_number: 

431 if not right.isdigit(): 

432 return right 

433 else: 

434 return right 

435 

436 return None 

437 

438def _get_field(cant_be_number, raw_string, convert_to, default_value, *field_names): 

439 retval = _get_field_actual(cant_be_number, raw_string, field_names) 

440 

441 # Convert the return value 

442 if retval and convert_to: 

443 try: 

444 retval = convert_to(retval) 

445 except Exception: 

446 retval = default_value 

447 

448 # Return the default if there is no return value 

449 if retval is None: 

450 retval = default_value 

451 

452 return retval 

453 

454def _to_decimal_string(ticks): 

455 try: 

456 # Convert to string 

457 ticks = '{0}'.format(ticks) 

458 # Sometimes ',' is used as a decimal separator 

459 ticks = ticks.replace(',', '.') 

460 

461 # Strip off non numbers and decimal places 

462 ticks = "".join(n for n in ticks if n.isdigit() or n=='.').strip() 

463 if ticks == '': 

464 ticks = '0' 

465 

466 # Add decimal if missing 

467 if '.' not in ticks: 

468 ticks = '{0}.0'.format(ticks) 

469 

470 # Remove trailing zeros 

471 ticks = ticks.rstrip('0') 

472 

473 # Add one trailing zero for empty right side 

474 if ticks.endswith('.'): 

475 ticks = '{0}0'.format(ticks) 

476 

477 # Make sure the number can be converted to a float 

478 ticks = float(ticks) 

479 ticks = '{0}'.format(ticks) 

480 return ticks 

481 except Exception: 

482 return '0.0' 

483 

484def _hz_short_to_full(ticks, scale): 

485 try: 

486 # Make sure the number can be converted to a float 

487 ticks = float(ticks) 

488 ticks = '{0}'.format(ticks) 

489 

490 # Scale the numbers 

491 hz = ticks.lstrip('0') 

492 old_index = hz.index('.') 

493 hz = hz.replace('.', '') 

494 hz = hz.ljust(scale + old_index+1, '0') 

495 new_index = old_index + scale 

496 hz = '{0}.{1}'.format(hz[:new_index], hz[new_index:]) 

497 left, right = hz.split('.') 

498 left, right = int(left), int(right) 

499 return (left, right) 

500 except Exception: 

501 return (0, 0) 

502 

503def _hz_friendly_to_full(hz_string): 

504 try: 

505 hz_string = hz_string.strip().lower() 

506 hz, scale = (None, None) 

507 

508 if hz_string.endswith('ghz'): 

509 scale = 9 

510 elif hz_string.endswith('mhz'): 

511 scale = 6 

512 elif hz_string.endswith('hz'): 

513 scale = 0 

514 

515 hz = "".join(n for n in hz_string if n.isdigit() or n=='.').strip() 

516 if not '.' in hz: 

517 hz += '.0' 

518 

519 hz, scale = _hz_short_to_full(hz, scale) 

520 

521 return (hz, scale) 

522 except Exception: 

523 return (0, 0) 

524 

525def _hz_short_to_friendly(ticks, scale): 

526 try: 

527 # Get the raw Hz as a string 

528 left, right = _hz_short_to_full(ticks, scale) 

529 result = '{0}.{1}'.format(left, right) 

530 

531 # Get the location of the dot, and remove said dot 

532 dot_index = result.index('.') 

533 result = result.replace('.', '') 

534 

535 # Get the Hz symbol and scale 

536 symbol = "Hz" 

537 scale = 0 

538 if dot_index > 9: 

539 symbol = "GHz" 

540 scale = 9 

541 elif dot_index > 6: 

542 symbol = "MHz" 

543 scale = 6 

544 elif dot_index > 3: 

545 symbol = "KHz" 

546 scale = 3 

547 

548 # Get the Hz with the dot at the new scaled point 

549 result = '{0}.{1}'.format(result[:-scale-1], result[-scale-1:]) 

550 

551 # Format the ticks to have 4 numbers after the decimal 

552 # and remove any superfluous zeroes. 

553 result = '{0:.4f} {1}'.format(float(result), symbol) 

554 result = result.rstrip('0') 

555 return result 

556 except Exception: 

557 return '0.0000 Hz' 

558 

559def _to_friendly_bytes(input): 

560 import re 

561 

562 if not input: 

563 return input 

564 input = "{0}".format(input) 

565 

566 formats = { 

567 r"^[0-9]+B$" : 'B', 

568 r"^[0-9]+K$" : 'KB', 

569 r"^[0-9]+M$" : 'MB', 

570 r"^[0-9]+G$" : 'GB' 

571 } 

572 

573 for pattern, friendly_size in formats.items(): 

574 if re.match(pattern, input): 

575 return "{0} {1}".format(input[ : -1].strip(), friendly_size) 

576 

577 return input 

578 

579def _friendly_bytes_to_int(friendly_bytes): 

580 input = friendly_bytes.lower() 

581 

582 formats = [ 

583 {'gib' : 1024 * 1024 * 1024}, 

584 {'mib' : 1024 * 1024}, 

585 {'kib' : 1024}, 

586 

587 {'gb' : 1024 * 1024 * 1024}, 

588 {'mb' : 1024 * 1024}, 

589 {'kb' : 1024}, 

590 

591 {'g' : 1024 * 1024 * 1024}, 

592 {'m' : 1024 * 1024}, 

593 {'k' : 1024}, 

594 {'b' : 1}, 

595 ] 

596 

597 try: 

598 for entry in formats: 

599 pattern = list(entry.keys())[0] 

600 multiplier = list(entry.values())[0] 

601 if input.endswith(pattern): 

602 return int(input.split(pattern)[0].strip()) * multiplier 

603 

604 except Exception as err: 

605 pass 

606 

607 return friendly_bytes 

608 

609def _parse_cpu_brand_string(cpu_string): 

610 # Just return 0 if the processor brand does not have the Hz 

611 if not 'hz' in cpu_string.lower(): 

612 return ('0.0', 0) 

613 

614 hz = cpu_string.lower() 

615 scale = 0 

616 

617 if hz.endswith('mhz'): 

618 scale = 6 

619 elif hz.endswith('ghz'): 

620 scale = 9 

621 if '@' in hz: 

622 hz = hz.split('@')[1] 

623 else: 

624 hz = hz.rsplit(None, 1)[1] 

625 

626 hz = hz.rstrip('mhz').rstrip('ghz').strip() 

627 hz = _to_decimal_string(hz) 

628 

629 return (hz, scale) 

630 

631def _parse_cpu_brand_string_dx(cpu_string): 

632 import re 

633 

634 # Find all the strings inside brackets () 

635 starts = [m.start() for m in re.finditer(r"\(", cpu_string)] 

636 ends = [m.start() for m in re.finditer(r"\)", cpu_string)] 

637 insides = {k: v for k, v in zip(starts, ends)} 

638 insides = [cpu_string[start+1 : end] for start, end in insides.items()] 

639 

640 # Find all the fields 

641 vendor_id, stepping, model, family = (None, None, None, None) 

642 for inside in insides: 

643 for pair in inside.split(','): 

644 pair = [n.strip() for n in pair.split(':')] 

645 if len(pair) > 1: 

646 name, value = pair[0], pair[1] 

647 if name == 'origin': 

648 vendor_id = value.strip('"') 

649 elif name == 'stepping': 

650 stepping = int(value.lstrip('0x'), 16) 

651 elif name == 'model': 

652 model = int(value.lstrip('0x'), 16) 

653 elif name in ['fam', 'family']: 

654 family = int(value.lstrip('0x'), 16) 

655 

656 # Find the Processor Brand 

657 # Strip off extra strings in brackets at end 

658 brand = cpu_string.strip() 

659 is_working = True 

660 while is_working: 

661 is_working = False 

662 for inside in insides: 

663 full = "({0})".format(inside) 

664 if brand.endswith(full): 

665 brand = brand[ :-len(full)].strip() 

666 is_working = True 

667 

668 # Find the Hz in the brand string 

669 hz_brand, scale = _parse_cpu_brand_string(brand) 

670 

671 # Find Hz inside brackets () after the brand string 

672 if hz_brand == '0.0': 

673 for inside in insides: 

674 hz = inside 

675 for entry in ['GHz', 'MHz', 'Hz']: 

676 if entry in hz: 

677 hz = "CPU @ " + hz[ : hz.find(entry) + len(entry)] 

678 hz_brand, scale = _parse_cpu_brand_string(hz) 

679 break 

680 

681 return (hz_brand, scale, brand, vendor_id, stepping, model, family) 

682 

683def _parse_dmesg_output(output): 

684 try: 

685 # Get all the dmesg lines that might contain a CPU string 

686 lines = output.split(' CPU0:')[1:] + \ 

687 output.split(' CPU1:')[1:] + \ 

688 output.split(' CPU:')[1:] + \ 

689 output.split('\nCPU0:')[1:] + \ 

690 output.split('\nCPU1:')[1:] + \ 

691 output.split('\nCPU:')[1:] 

692 lines = [l.split('\n')[0].strip() for l in lines] 

693 

694 # Convert the lines to CPU strings 

695 cpu_strings = [_parse_cpu_brand_string_dx(l) for l in lines] 

696 

697 # Find the CPU string that has the most fields 

698 best_string = None 

699 highest_count = 0 

700 for cpu_string in cpu_strings: 

701 count = sum([n is not None for n in cpu_string]) 

702 if count > highest_count: 

703 highest_count = count 

704 best_string = cpu_string 

705 

706 # If no CPU string was found, return {} 

707 if not best_string: 

708 return {} 

709 

710 hz_actual, scale, processor_brand, vendor_id, stepping, model, family = best_string 

711 

712 # Origin 

713 if ' Origin=' in output: 

714 fields = output[output.find(' Origin=') : ].split('\n')[0] 

715 fields = fields.strip().split() 

716 fields = [n.strip().split('=') for n in fields] 

717 fields = [{n[0].strip().lower() : n[1].strip()} for n in fields] 

718 

719 for field in fields: 

720 name = list(field.keys())[0] 

721 value = list(field.values())[0] 

722 

723 if name == 'origin': 

724 vendor_id = value.strip('"') 

725 elif name == 'stepping': 

726 stepping = int(value.lstrip('0x'), 16) 

727 elif name == 'model': 

728 model = int(value.lstrip('0x'), 16) 

729 elif name in ['fam', 'family']: 

730 family = int(value.lstrip('0x'), 16) 

731 

732 # Features 

733 flag_lines = [] 

734 for category in [' Features=', ' Features2=', ' AMD Features=', ' AMD Features2=']: 

735 if category in output: 

736 flag_lines.append(output.split(category)[1].split('\n')[0]) 

737 

738 flags = [] 

739 for line in flag_lines: 

740 line = line.split('<')[1].split('>')[0].lower() 

741 for flag in line.split(','): 

742 flags.append(flag) 

743 flags.sort() 

744 

745 # Convert from GHz/MHz string to Hz 

746 hz_advertised, scale = _parse_cpu_brand_string(processor_brand) 

747 

748 # If advertised hz not found, use the actual hz 

749 if hz_advertised == '0.0': 

750 scale = 6 

751 hz_advertised = _to_decimal_string(hz_actual) 

752 

753 info = { 

754 'vendor_id_raw' : vendor_id, 

755 'brand_raw' : processor_brand, 

756 

757 'stepping' : stepping, 

758 'model' : model, 

759 'family' : family, 

760 'flags' : flags 

761 } 

762 

763 if hz_advertised and hz_advertised != '0.0': 

764 info['hz_advertised_friendly'] = _hz_short_to_friendly(hz_advertised, scale) 

765 info['hz_actual_friendly'] = _hz_short_to_friendly(hz_actual, scale) 

766 

767 if hz_advertised and hz_advertised != '0.0': 

768 info['hz_advertised'] = _hz_short_to_full(hz_advertised, scale) 

769 info['hz_actual'] = _hz_short_to_full(hz_actual, scale) 

770 

771 return {k: v for k, v in info.items() if v} 

772 except Exception as err: 

773 g_trace.fail(err) 

774 #raise 

775 

776 return {} 

777 

778def _parse_arch(arch_string_raw): 

779 import re 

780 

781 arch, bits = None, None 

782 arch_string_raw = arch_string_raw.lower() 

783 

784 # X86 

785 if re.match(r'^i\d86$|^x86$|^x86_32$|^i86pc$|^ia32$|^ia-32$|^bepc$', arch_string_raw): 

786 arch = 'X86_32' 

787 bits = 32 

788 elif re.match(r'^x64$|^x86_64$|^x86_64t$|^i686-64$|^amd64$|^ia64$|^ia-64$', arch_string_raw): 

789 arch = 'X86_64' 

790 bits = 64 

791 # ARM 

792 elif re.match(r'^armv8-a|aarch64|arm64$', arch_string_raw): 

793 arch = 'ARM_8' 

794 bits = 64 

795 elif re.match(r'^armv7$|^armv7[a-z]$|^armv7-[a-z]$|^armv6[a-z]$', arch_string_raw): 

796 arch = 'ARM_7' 

797 bits = 32 

798 elif re.match(r'^armv8$|^armv8[a-z]$|^armv8-[a-z]$', arch_string_raw): 

799 arch = 'ARM_8' 

800 bits = 32 

801 # PPC 

802 elif re.match(r'^ppc32$|^prep$|^pmac$|^powermac$', arch_string_raw): 

803 arch = 'PPC_32' 

804 bits = 32 

805 elif re.match(r'^powerpc$|^ppc64$|^ppc64le$', arch_string_raw): 

806 arch = 'PPC_64' 

807 bits = 64 

808 # SPARC 

809 elif re.match(r'^sparc32$|^sparc$', arch_string_raw): 

810 arch = 'SPARC_32' 

811 bits = 32 

812 elif re.match(r'^sparc64$|^sun4u$|^sun4v$', arch_string_raw): 

813 arch = 'SPARC_64' 

814 bits = 64 

815 # S390X 

816 elif re.match(r'^s390x$', arch_string_raw): 

817 arch = 'S390X' 

818 bits = 64 

819 elif arch_string_raw == 'mips': 

820 arch = 'MIPS_32' 

821 bits = 32 

822 elif arch_string_raw == 'mips64': 

823 arch = 'MIPS_64' 

824 bits = 64 

825 # RISCV 

826 elif re.match(r'^riscv$|^riscv32$|^riscv32be$', arch_string_raw): 

827 arch = 'RISCV_32' 

828 bits = 32 

829 elif re.match(r'^riscv64$|^riscv64be$', arch_string_raw): 

830 arch = 'RISCV_64' 

831 bits = 64 

832 

833 return (arch, bits) 

834 

835def _is_bit_set(reg, bit): 

836 mask = 1 << bit 

837 is_set = reg & mask > 0 

838 return is_set 

839 

840 

841def _is_selinux_enforcing(trace): 

842 # Just return if the SE Linux Status Tool is not installed 

843 if not DataSource.has_sestatus(): 

844 trace.fail('Failed to find sestatus.') 

845 return False 

846 

847 # Run the sestatus, and just return if it failed to run 

848 returncode, output = DataSource.sestatus_b() 

849 if returncode != 0: 

850 trace.fail('Failed to run sestatus. Skipping ...') 

851 return False 

852 

853 # Figure out if explicitly in enforcing mode 

854 for line in output.splitlines(): 

855 line = line.strip().lower() 

856 if line.startswith("current mode:"): 

857 if line.endswith("enforcing"): 

858 return True 

859 else: 

860 return False 

861 

862 # Figure out if we can execute heap and execute memory 

863 can_selinux_exec_heap = False 

864 can_selinux_exec_memory = False 

865 for line in output.splitlines(): 

866 line = line.strip().lower() 

867 if line.startswith("allow_execheap") and line.endswith("on"): 

868 can_selinux_exec_heap = True 

869 elif line.startswith("allow_execmem") and line.endswith("on"): 

870 can_selinux_exec_memory = True 

871 

872 trace.command_output('can_selinux_exec_heap:', can_selinux_exec_heap) 

873 trace.command_output('can_selinux_exec_memory:', can_selinux_exec_memory) 

874 

875 return (not can_selinux_exec_heap or not can_selinux_exec_memory) 

876 

877def _filter_dict_keys_with_empty_values(info, acceptable_values = {}): 

878 filtered_info = {} 

879 for key in info: 

880 value = info[key] 

881 

882 # Keep if value is acceptable 

883 if key in acceptable_values: 

884 if acceptable_values[key] == value: 

885 filtered_info[key] = value 

886 continue 

887 

888 # Filter out None, 0, "", (), {}, [] 

889 if not value: 

890 continue 

891 

892 # Filter out (0, 0) 

893 if value == (0, 0): 

894 continue 

895 

896 # Filter out -1 

897 if value == -1: 

898 continue 

899 

900 # Filter out strings that start with "0.0" 

901 if type(value) == str and value.startswith('0.0'): 

902 continue 

903 

904 filtered_info[key] = value 

905 

906 return filtered_info 

907 

908class ASM(object): 

909 def __init__(self, restype=None, argtypes=(), machine_code=[]): 

910 self.restype = restype 

911 self.argtypes = argtypes 

912 self.machine_code = machine_code 

913 self.prochandle = None 

914 self.mm = None 

915 self.func = None 

916 self.address = None 

917 self.size = 0 

918 

919 def compile(self): 

920 machine_code = bytes.join(b'', self.machine_code) 

921 self.size = ctypes.c_size_t(len(machine_code)) 

922 

923 if DataSource.is_windows: 

924 # Allocate a memory segment the size of the machine code, and make it executable 

925 size = len(machine_code) 

926 # Alloc at least 1 page to ensure we own all pages that we want to change protection on 

927 if size < 0x1000: size = 0x1000 

928 MEM_COMMIT = ctypes.c_ulong(0x1000) 

929 PAGE_READWRITE = ctypes.c_ulong(0x4) 

930 pfnVirtualAlloc = ctypes.windll.kernel32.VirtualAlloc 

931 pfnVirtualAlloc.restype = ctypes.c_void_p 

932 self.address = pfnVirtualAlloc(None, ctypes.c_size_t(size), MEM_COMMIT, PAGE_READWRITE) 

933 if not self.address: 

934 raise Exception("Failed to VirtualAlloc") 

935 

936 # Copy the machine code into the memory segment 

937 memmove = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)(ctypes._memmove_addr) 

938 if memmove(self.address, machine_code, size) < 0: 

939 raise Exception("Failed to memmove") 

940 

941 # Enable execute permissions 

942 PAGE_EXECUTE = ctypes.c_ulong(0x10) 

943 old_protect = ctypes.c_ulong(0) 

944 pfnVirtualProtect = ctypes.windll.kernel32.VirtualProtect 

945 res = pfnVirtualProtect(ctypes.c_void_p(self.address), ctypes.c_size_t(size), PAGE_EXECUTE, ctypes.byref(old_protect)) 

946 if not res: 

947 raise Exception("Failed VirtualProtect") 

948 

949 # Flush Instruction Cache 

950 # First, get process Handle 

951 if not self.prochandle: 

952 pfnGetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess 

953 pfnGetCurrentProcess.restype = ctypes.c_void_p 

954 self.prochandle = ctypes.c_void_p(pfnGetCurrentProcess()) 

955 # Actually flush cache 

956 res = ctypes.windll.kernel32.FlushInstructionCache(self.prochandle, ctypes.c_void_p(self.address), ctypes.c_size_t(size)) 

957 if not res: 

958 raise Exception("Failed FlushInstructionCache") 

959 else: 

960 from mmap import mmap, MAP_PRIVATE, MAP_ANONYMOUS, PROT_WRITE, PROT_READ, PROT_EXEC 

961 

962 # Allocate a private and executable memory segment the size of the machine code 

963 machine_code = bytes.join(b'', self.machine_code) 

964 self.size = len(machine_code) 

965 self.mm = mmap(-1, self.size, flags=MAP_PRIVATE | MAP_ANONYMOUS, prot=PROT_WRITE | PROT_READ | PROT_EXEC) 

966 

967 # Copy the machine code into the memory segment 

968 self.mm.write(machine_code) 

969 self.address = ctypes.addressof(ctypes.c_int.from_buffer(self.mm)) 

970 

971 # Cast the memory segment into a function 

972 functype = ctypes.CFUNCTYPE(self.restype, *self.argtypes) 

973 self.func = functype(self.address) 

974 

975 def run(self): 

976 # Call the machine code like a function 

977 retval = self.func() 

978 

979 return retval 

980 

981 def free(self): 

982 # Free the function memory segment 

983 if DataSource.is_windows: 

984 MEM_RELEASE = ctypes.c_ulong(0x8000) 

985 ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(self.address), ctypes.c_size_t(0), MEM_RELEASE) 

986 else: 

987 self.mm.close() 

988 

989 self.prochandle = None 

990 self.mm = None 

991 self.func = None 

992 self.address = None 

993 self.size = 0 

994 

995 

996class CPUID(object): 

997 def __init__(self, trace=None): 

998 if trace is None: 

999 trace = Trace(False, False) 

1000 

1001 # Figure out if SE Linux is on and in enforcing mode 

1002 self.is_selinux_enforcing = _is_selinux_enforcing(trace) 

1003 

1004 def _asm_func(self, restype=None, argtypes=(), machine_code=[]): 

1005 asm = ASM(restype, argtypes, machine_code) 

1006 asm.compile() 

1007 return asm 

1008 

1009 def _run_asm(self, *machine_code): 

1010 asm = ASM(ctypes.c_uint32, (), machine_code) 

1011 asm.compile() 

1012 retval = asm.run() 

1013 asm.free() 

1014 return retval 

1015 

1016 # http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID 

1017 def get_vendor_id(self): 

1018 # EBX 

1019 ebx = self._run_asm( 

1020 b"\x31\xC0", # xor eax,eax 

1021 b"\x0F\xA2" # cpuid 

1022 b"\x89\xD8" # mov ax,bx 

1023 b"\xC3" # ret 

1024 ) 

1025 

1026 # ECX 

1027 ecx = self._run_asm( 

1028 b"\x31\xC0", # xor eax,eax 

1029 b"\x0f\xa2" # cpuid 

1030 b"\x89\xC8" # mov ax,cx 

1031 b"\xC3" # ret 

1032 ) 

1033 

1034 # EDX 

1035 edx = self._run_asm( 

1036 b"\x31\xC0", # xor eax,eax 

1037 b"\x0f\xa2" # cpuid 

1038 b"\x89\xD0" # mov ax,dx 

1039 b"\xC3" # ret 

1040 ) 

1041 

1042 # Each 4bits is a ascii letter in the name 

1043 vendor_id = [] 

1044 for reg in [ebx, edx, ecx]: 

1045 for n in [0, 8, 16, 24]: 

1046 vendor_id.append(chr((reg >> n) & 0xFF)) 

1047 vendor_id = ''.join(vendor_id) 

1048 

1049 return vendor_id 

1050 

1051 # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits 

1052 def get_info(self): 

1053 # EAX 

1054 eax = self._run_asm( 

1055 b"\xB8\x01\x00\x00\x00", # mov eax,0x1" 

1056 b"\x0f\xa2" # cpuid 

1057 b"\xC3" # ret 

1058 ) 

1059 

1060 # Get the CPU info 

1061 stepping_id = (eax >> 0) & 0xF # 4 bits 

1062 model = (eax >> 4) & 0xF # 4 bits 

1063 family_id = (eax >> 8) & 0xF # 4 bits 

1064 processor_type = (eax >> 12) & 0x3 # 2 bits 

1065 extended_model_id = (eax >> 16) & 0xF # 4 bits 

1066 extended_family_id = (eax >> 20) & 0xFF # 8 bits 

1067 family = 0 

1068 

1069 if family_id in [15]: 

1070 family = extended_family_id + family_id 

1071 else: 

1072 family = family_id 

1073 

1074 if family_id in [6, 15]: 

1075 model = (extended_model_id << 4) + model 

1076 

1077 return { 

1078 'stepping' : stepping_id, 

1079 'model' : model, 

1080 'family' : family, 

1081 'processor_type' : processor_type 

1082 } 

1083 

1084 # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000000h:_Get_Highest_Extended_Function_Supported 

1085 def get_max_extension_support(self): 

1086 # Check for extension support 

1087 max_extension_support = self._run_asm( 

1088 b"\xB8\x00\x00\x00\x80" # mov ax,0x80000000 

1089 b"\x0f\xa2" # cpuid 

1090 b"\xC3" # ret 

1091 ) 

1092 

1093 return max_extension_support 

1094 

1095 # http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits 

1096 def get_flags(self, max_extension_support): 

1097 # EDX 

1098 edx = self._run_asm( 

1099 b"\xB8\x01\x00\x00\x00", # mov eax,0x1" 

1100 b"\x0f\xa2" # cpuid 

1101 b"\x89\xD0" # mov ax,dx 

1102 b"\xC3" # ret 

1103 ) 

1104 

1105 # ECX 

1106 ecx = self._run_asm( 

1107 b"\xB8\x01\x00\x00\x00", # mov eax,0x1" 

1108 b"\x0f\xa2" # cpuid 

1109 b"\x89\xC8" # mov ax,cx 

1110 b"\xC3" # ret 

1111 ) 

1112 

1113 # Get the CPU flags 

1114 flags = { 

1115 'fpu' : _is_bit_set(edx, 0), 

1116 'vme' : _is_bit_set(edx, 1), 

1117 'de' : _is_bit_set(edx, 2), 

1118 'pse' : _is_bit_set(edx, 3), 

1119 'tsc' : _is_bit_set(edx, 4), 

1120 'msr' : _is_bit_set(edx, 5), 

1121 'pae' : _is_bit_set(edx, 6), 

1122 'mce' : _is_bit_set(edx, 7), 

1123 'cx8' : _is_bit_set(edx, 8), 

1124 'apic' : _is_bit_set(edx, 9), 

1125 #'reserved1' : _is_bit_set(edx, 10), 

1126 'sep' : _is_bit_set(edx, 11), 

1127 'mtrr' : _is_bit_set(edx, 12), 

1128 'pge' : _is_bit_set(edx, 13), 

1129 'mca' : _is_bit_set(edx, 14), 

1130 'cmov' : _is_bit_set(edx, 15), 

1131 'pat' : _is_bit_set(edx, 16), 

1132 'pse36' : _is_bit_set(edx, 17), 

1133 'pn' : _is_bit_set(edx, 18), 

1134 'clflush' : _is_bit_set(edx, 19), 

1135 #'reserved2' : _is_bit_set(edx, 20), 

1136 'dts' : _is_bit_set(edx, 21), 

1137 'acpi' : _is_bit_set(edx, 22), 

1138 'mmx' : _is_bit_set(edx, 23), 

1139 'fxsr' : _is_bit_set(edx, 24), 

1140 'sse' : _is_bit_set(edx, 25), 

1141 'sse2' : _is_bit_set(edx, 26), 

1142 'ss' : _is_bit_set(edx, 27), 

1143 'ht' : _is_bit_set(edx, 28), 

1144 'tm' : _is_bit_set(edx, 29), 

1145 'ia64' : _is_bit_set(edx, 30), 

1146 'pbe' : _is_bit_set(edx, 31), 

1147 

1148 'pni' : _is_bit_set(ecx, 0), 

1149 'pclmulqdq' : _is_bit_set(ecx, 1), 

1150 'dtes64' : _is_bit_set(ecx, 2), 

1151 'monitor' : _is_bit_set(ecx, 3), 

1152 'ds_cpl' : _is_bit_set(ecx, 4), 

1153 'vmx' : _is_bit_set(ecx, 5), 

1154 'smx' : _is_bit_set(ecx, 6), 

1155 'est' : _is_bit_set(ecx, 7), 

1156 'tm2' : _is_bit_set(ecx, 8), 

1157 'ssse3' : _is_bit_set(ecx, 9), 

1158 'cid' : _is_bit_set(ecx, 10), 

1159 #'reserved3' : _is_bit_set(ecx, 11), 

1160 'fma' : _is_bit_set(ecx, 12), 

1161 'cx16' : _is_bit_set(ecx, 13), 

1162 'xtpr' : _is_bit_set(ecx, 14), 

1163 'pdcm' : _is_bit_set(ecx, 15), 

1164 #'reserved4' : _is_bit_set(ecx, 16), 

1165 'pcid' : _is_bit_set(ecx, 17), 

1166 'dca' : _is_bit_set(ecx, 18), 

1167 'sse4_1' : _is_bit_set(ecx, 19), 

1168 'sse4_2' : _is_bit_set(ecx, 20), 

1169 'x2apic' : _is_bit_set(ecx, 21), 

1170 'movbe' : _is_bit_set(ecx, 22), 

1171 'popcnt' : _is_bit_set(ecx, 23), 

1172 'tscdeadline' : _is_bit_set(ecx, 24), 

1173 'aes' : _is_bit_set(ecx, 25), 

1174 'xsave' : _is_bit_set(ecx, 26), 

1175 'osxsave' : _is_bit_set(ecx, 27), 

1176 'avx' : _is_bit_set(ecx, 28), 

1177 'f16c' : _is_bit_set(ecx, 29), 

1178 'rdrnd' : _is_bit_set(ecx, 30), 

1179 'hypervisor' : _is_bit_set(ecx, 31) 

1180 } 

1181 

1182 # Get a list of only the flags that are true 

1183 flags = [k for k, v in flags.items() if v] 

1184 

1185 # http://en.wikipedia.org/wiki/CPUID#EAX.3D7.2C_ECX.3D0:_Extended_Features 

1186 if max_extension_support >= 7: 

1187 # EBX 

1188 ebx = self._run_asm( 

1189 b"\x31\xC9", # xor ecx,ecx 

1190 b"\xB8\x07\x00\x00\x00" # mov eax,7 

1191 b"\x0f\xa2" # cpuid 

1192 b"\x89\xD8" # mov ax,bx 

1193 b"\xC3" # ret 

1194 ) 

1195 

1196 # ECX 

1197 ecx = self._run_asm( 

1198 b"\x31\xC9", # xor ecx,ecx 

1199 b"\xB8\x07\x00\x00\x00" # mov eax,7 

1200 b"\x0f\xa2" # cpuid 

1201 b"\x89\xC8" # mov ax,cx 

1202 b"\xC3" # ret 

1203 ) 

1204 

1205 # Get the extended CPU flags 

1206 extended_flags = { 

1207 #'fsgsbase' : _is_bit_set(ebx, 0), 

1208 #'IA32_TSC_ADJUST' : _is_bit_set(ebx, 1), 

1209 'sgx' : _is_bit_set(ebx, 2), 

1210 'bmi1' : _is_bit_set(ebx, 3), 

1211 'hle' : _is_bit_set(ebx, 4), 

1212 'avx2' : _is_bit_set(ebx, 5), 

1213 #'reserved' : _is_bit_set(ebx, 6), 

1214 'smep' : _is_bit_set(ebx, 7), 

1215 'bmi2' : _is_bit_set(ebx, 8), 

1216 'erms' : _is_bit_set(ebx, 9), 

1217 'invpcid' : _is_bit_set(ebx, 10), 

1218 'rtm' : _is_bit_set(ebx, 11), 

1219 'pqm' : _is_bit_set(ebx, 12), 

1220 #'FPU CS and FPU DS deprecated' : _is_bit_set(ebx, 13), 

1221 'mpx' : _is_bit_set(ebx, 14), 

1222 'pqe' : _is_bit_set(ebx, 15), 

1223 'avx512f' : _is_bit_set(ebx, 16), 

1224 'avx512dq' : _is_bit_set(ebx, 17), 

1225 'rdseed' : _is_bit_set(ebx, 18), 

1226 'adx' : _is_bit_set(ebx, 19), 

1227 'smap' : _is_bit_set(ebx, 20), 

1228 'avx512ifma' : _is_bit_set(ebx, 21), 

1229 'pcommit' : _is_bit_set(ebx, 22), 

1230 'clflushopt' : _is_bit_set(ebx, 23), 

1231 'clwb' : _is_bit_set(ebx, 24), 

1232 'intel_pt' : _is_bit_set(ebx, 25), 

1233 'avx512pf' : _is_bit_set(ebx, 26), 

1234 'avx512er' : _is_bit_set(ebx, 27), 

1235 'avx512cd' : _is_bit_set(ebx, 28), 

1236 'sha' : _is_bit_set(ebx, 29), 

1237 'avx512bw' : _is_bit_set(ebx, 30), 

1238 'avx512vl' : _is_bit_set(ebx, 31), 

1239 

1240 'prefetchwt1' : _is_bit_set(ecx, 0), 

1241 'avx512vbmi' : _is_bit_set(ecx, 1), 

1242 'umip' : _is_bit_set(ecx, 2), 

1243 'pku' : _is_bit_set(ecx, 3), 

1244 'ospke' : _is_bit_set(ecx, 4), 

1245 #'reserved' : _is_bit_set(ecx, 5), 

1246 'avx512vbmi2' : _is_bit_set(ecx, 6), 

1247 #'reserved' : _is_bit_set(ecx, 7), 

1248 'gfni' : _is_bit_set(ecx, 8), 

1249 'vaes' : _is_bit_set(ecx, 9), 

1250 'vpclmulqdq' : _is_bit_set(ecx, 10), 

1251 'avx512vnni' : _is_bit_set(ecx, 11), 

1252 'avx512bitalg' : _is_bit_set(ecx, 12), 

1253 #'reserved' : _is_bit_set(ecx, 13), 

1254 'avx512vpopcntdq' : _is_bit_set(ecx, 14), 

1255 #'reserved' : _is_bit_set(ecx, 15), 

1256 #'reserved' : _is_bit_set(ecx, 16), 

1257 #'mpx0' : _is_bit_set(ecx, 17), 

1258 #'mpx1' : _is_bit_set(ecx, 18), 

1259 #'mpx2' : _is_bit_set(ecx, 19), 

1260 #'mpx3' : _is_bit_set(ecx, 20), 

1261 #'mpx4' : _is_bit_set(ecx, 21), 

1262 'rdpid' : _is_bit_set(ecx, 22), 

1263 #'reserved' : _is_bit_set(ecx, 23), 

1264 #'reserved' : _is_bit_set(ecx, 24), 

1265 #'reserved' : _is_bit_set(ecx, 25), 

1266 #'reserved' : _is_bit_set(ecx, 26), 

1267 #'reserved' : _is_bit_set(ecx, 27), 

1268 #'reserved' : _is_bit_set(ecx, 28), 

1269 #'reserved' : _is_bit_set(ecx, 29), 

1270 'sgx_lc' : _is_bit_set(ecx, 30), 

1271 #'reserved' : _is_bit_set(ecx, 31) 

1272 } 

1273 

1274 # Get a list of only the flags that are true 

1275 extended_flags = [k for k, v in extended_flags.items() if v] 

1276 flags += extended_flags 

1277 

1278 # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000001h:_Extended_Processor_Info_and_Feature_Bits 

1279 if max_extension_support >= 0x80000001: 

1280 # EBX 

1281 ebx = self._run_asm( 

1282 b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001 

1283 b"\x0f\xa2" # cpuid 

1284 b"\x89\xD8" # mov ax,bx 

1285 b"\xC3" # ret 

1286 ) 

1287 

1288 # ECX 

1289 ecx = self._run_asm( 

1290 b"\xB8\x01\x00\x00\x80" # mov ax,0x80000001 

1291 b"\x0f\xa2" # cpuid 

1292 b"\x89\xC8" # mov ax,cx 

1293 b"\xC3" # ret 

1294 ) 

1295 

1296 # Get the extended CPU flags 

1297 extended_flags = { 

1298 'fpu' : _is_bit_set(ebx, 0), 

1299 'vme' : _is_bit_set(ebx, 1), 

1300 'de' : _is_bit_set(ebx, 2), 

1301 'pse' : _is_bit_set(ebx, 3), 

1302 'tsc' : _is_bit_set(ebx, 4), 

1303 'msr' : _is_bit_set(ebx, 5), 

1304 'pae' : _is_bit_set(ebx, 6), 

1305 'mce' : _is_bit_set(ebx, 7), 

1306 'cx8' : _is_bit_set(ebx, 8), 

1307 'apic' : _is_bit_set(ebx, 9), 

1308 #'reserved' : _is_bit_set(ebx, 10), 

1309 'syscall' : _is_bit_set(ebx, 11), 

1310 'mtrr' : _is_bit_set(ebx, 12), 

1311 'pge' : _is_bit_set(ebx, 13), 

1312 'mca' : _is_bit_set(ebx, 14), 

1313 'cmov' : _is_bit_set(ebx, 15), 

1314 'pat' : _is_bit_set(ebx, 16), 

1315 'pse36' : _is_bit_set(ebx, 17), 

1316 #'reserved' : _is_bit_set(ebx, 18), 

1317 'mp' : _is_bit_set(ebx, 19), 

1318 'nx' : _is_bit_set(ebx, 20), 

1319 #'reserved' : _is_bit_set(ebx, 21), 

1320 'mmxext' : _is_bit_set(ebx, 22), 

1321 'mmx' : _is_bit_set(ebx, 23), 

1322 'fxsr' : _is_bit_set(ebx, 24), 

1323 'fxsr_opt' : _is_bit_set(ebx, 25), 

1324 'pdpe1gp' : _is_bit_set(ebx, 26), 

1325 'rdtscp' : _is_bit_set(ebx, 27), 

1326 #'reserved' : _is_bit_set(ebx, 28), 

1327 'lm' : _is_bit_set(ebx, 29), 

1328 '3dnowext' : _is_bit_set(ebx, 30), 

1329 '3dnow' : _is_bit_set(ebx, 31), 

1330 

1331 'lahf_lm' : _is_bit_set(ecx, 0), 

1332 'cmp_legacy' : _is_bit_set(ecx, 1), 

1333 'svm' : _is_bit_set(ecx, 2), 

1334 'extapic' : _is_bit_set(ecx, 3), 

1335 'cr8_legacy' : _is_bit_set(ecx, 4), 

1336 'abm' : _is_bit_set(ecx, 5), 

1337 'sse4a' : _is_bit_set(ecx, 6), 

1338 'misalignsse' : _is_bit_set(ecx, 7), 

1339 '3dnowprefetch' : _is_bit_set(ecx, 8), 

1340 'osvw' : _is_bit_set(ecx, 9), 

1341 'ibs' : _is_bit_set(ecx, 10), 

1342 'xop' : _is_bit_set(ecx, 11), 

1343 'skinit' : _is_bit_set(ecx, 12), 

1344 'wdt' : _is_bit_set(ecx, 13), 

1345 #'reserved' : _is_bit_set(ecx, 14), 

1346 'lwp' : _is_bit_set(ecx, 15), 

1347 'fma4' : _is_bit_set(ecx, 16), 

1348 'tce' : _is_bit_set(ecx, 17), 

1349 #'reserved' : _is_bit_set(ecx, 18), 

1350 'nodeid_msr' : _is_bit_set(ecx, 19), 

1351 #'reserved' : _is_bit_set(ecx, 20), 

1352 'tbm' : _is_bit_set(ecx, 21), 

1353 'topoext' : _is_bit_set(ecx, 22), 

1354 'perfctr_core' : _is_bit_set(ecx, 23), 

1355 'perfctr_nb' : _is_bit_set(ecx, 24), 

1356 #'reserved' : _is_bit_set(ecx, 25), 

1357 'dbx' : _is_bit_set(ecx, 26), 

1358 'perftsc' : _is_bit_set(ecx, 27), 

1359 'pci_l2i' : _is_bit_set(ecx, 28), 

1360 #'reserved' : _is_bit_set(ecx, 29), 

1361 #'reserved' : _is_bit_set(ecx, 30), 

1362 #'reserved' : _is_bit_set(ecx, 31) 

1363 } 

1364 

1365 # Get a list of only the flags that are true 

1366 extended_flags = [k for k, v in extended_flags.items() if v] 

1367 flags += extended_flags 

1368 

1369 flags.sort() 

1370 return flags 

1371 

1372 # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000002h.2C80000003h.2C80000004h:_Processor_Brand_String 

1373 def get_processor_brand(self, max_extension_support): 

1374 processor_brand = "" 

1375 

1376 # Processor brand string 

1377 if max_extension_support >= 0x80000004: 

1378 instructions = [ 

1379 b"\xB8\x02\x00\x00\x80", # mov ax,0x80000002 

1380 b"\xB8\x03\x00\x00\x80", # mov ax,0x80000003 

1381 b"\xB8\x04\x00\x00\x80" # mov ax,0x80000004 

1382 ] 

1383 for instruction in instructions: 

1384 # EAX 

1385 eax = self._run_asm( 

1386 instruction, # mov ax,0x8000000? 

1387 b"\x0f\xa2" # cpuid 

1388 b"\x89\xC0" # mov ax,ax 

1389 b"\xC3" # ret 

1390 ) 

1391 

1392 # EBX 

1393 ebx = self._run_asm( 

1394 instruction, # mov ax,0x8000000? 

1395 b"\x0f\xa2" # cpuid 

1396 b"\x89\xD8" # mov ax,bx 

1397 b"\xC3" # ret 

1398 ) 

1399 

1400 # ECX 

1401 ecx = self._run_asm( 

1402 instruction, # mov ax,0x8000000? 

1403 b"\x0f\xa2" # cpuid 

1404 b"\x89\xC8" # mov ax,cx 

1405 b"\xC3" # ret 

1406 ) 

1407 

1408 # EDX 

1409 edx = self._run_asm( 

1410 instruction, # mov ax,0x8000000? 

1411 b"\x0f\xa2" # cpuid 

1412 b"\x89\xD0" # mov ax,dx 

1413 b"\xC3" # ret 

1414 ) 

1415 

1416 # Combine each of the 4 bytes in each register into the string 

1417 for reg in [eax, ebx, ecx, edx]: 

1418 for n in [0, 8, 16, 24]: 

1419 processor_brand += chr((reg >> n) & 0xFF) 

1420 

1421 # Strip off any trailing NULL terminators and white space 

1422 processor_brand = processor_brand.strip("\0").strip() 

1423 

1424 return processor_brand 

1425 

1426 # http://en.wikipedia.org/wiki/CPUID#EAX.3D80000006h:_Extended_L2_Cache_Features 

1427 def get_cache(self, max_extension_support): 

1428 cache_info = {} 

1429 

1430 # Just return if the cache feature is not supported 

1431 if max_extension_support < 0x80000006: 

1432 return cache_info 

1433 

1434 # ECX 

1435 ecx = self._run_asm( 

1436 b"\xB8\x06\x00\x00\x80" # mov ax,0x80000006 

1437 b"\x0f\xa2" # cpuid 

1438 b"\x89\xC8" # mov ax,cx 

1439 b"\xC3" # ret 

1440 ) 

1441 

1442 cache_info = { 

1443 'size_b' : (ecx & 0xFF) * 1024, 

1444 'associativity' : (ecx >> 12) & 0xF, 

1445 'line_size_b' : (ecx >> 16) & 0xFFFF 

1446 } 

1447 

1448 return cache_info 

1449 

1450 def get_ticks_func(self): 

1451 retval = None 

1452 

1453 if DataSource.bits == '32bit': 

1454 # Works on x86_32 

1455 restype = None 

1456 argtypes = (ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint)) 

1457 get_ticks_x86_32 = self._asm_func(restype, argtypes, 

1458 [ 

1459 b"\x55", # push bp 

1460 b"\x89\xE5", # mov bp,sp 

1461 b"\x31\xC0", # xor ax,ax 

1462 b"\x0F\xA2", # cpuid 

1463 b"\x0F\x31", # rdtsc 

1464 b"\x8B\x5D\x08", # mov bx,[di+0x8] 

1465 b"\x8B\x4D\x0C", # mov cx,[di+0xc] 

1466 b"\x89\x13", # mov [bp+di],dx 

1467 b"\x89\x01", # mov [bx+di],ax 

1468 b"\x5D", # pop bp 

1469 b"\xC3" # ret 

1470 ] 

1471 ) 

1472 

1473 # Monkey patch func to combine high and low args into one return 

1474 old_func = get_ticks_x86_32.func 

1475 def new_func(): 

1476 # Pass two uint32s into function 

1477 high = ctypes.c_uint32(0) 

1478 low = ctypes.c_uint32(0) 

1479 old_func(ctypes.byref(high), ctypes.byref(low)) 

1480 

1481 # Shift the two uint32s into one uint64 

1482 retval = ((high.value << 32) & 0xFFFFFFFF00000000) | low.value 

1483 return retval 

1484 get_ticks_x86_32.func = new_func 

1485 

1486 retval = get_ticks_x86_32 

1487 elif DataSource.bits == '64bit': 

1488 # Works on x86_64 

1489 restype = ctypes.c_uint64 

1490 argtypes = () 

1491 get_ticks_x86_64 = self._asm_func(restype, argtypes, 

1492 [ 

1493 b"\x48", # dec ax 

1494 b"\x31\xC0", # xor ax,ax 

1495 b"\x0F\xA2", # cpuid 

1496 b"\x0F\x31", # rdtsc 

1497 b"\x48", # dec ax 

1498 b"\xC1\xE2\x20", # shl dx,byte 0x20 

1499 b"\x48", # dec ax 

1500 b"\x09\xD0", # or ax,dx 

1501 b"\xC3", # ret 

1502 ] 

1503 ) 

1504 

1505 retval = get_ticks_x86_64 

1506 return retval 

1507 

1508 def get_raw_hz(self): 

1509 from time import sleep 

1510 

1511 ticks_fn = self.get_ticks_func() 

1512 

1513 start = ticks_fn.func() 

1514 sleep(1) 

1515 end = ticks_fn.func() 

1516 

1517 ticks = (end - start) 

1518 ticks_fn.free() 

1519 

1520 return ticks 

1521 

1522def _get_cpu_info_from_cpuid_actual(): 

1523 ''' 

1524 Warning! This function has the potential to crash the Python runtime. 

1525 Do not call it directly. Use the _get_cpu_info_from_cpuid function instead. 

1526 It will safely call this function in another process. 

1527 ''' 

1528 

1529 from io import StringIO 

1530 

1531 trace = Trace(True, True) 

1532 info = {} 

1533 

1534 # Pipe stdout and stderr to strings 

1535 sys.stdout = trace._stdout 

1536 sys.stderr = trace._stderr 

1537 

1538 try: 

1539 # Get the CPU arch and bits 

1540 arch, bits = _parse_arch(DataSource.arch_string_raw) 

1541 

1542 # Return none if this is not an X86 CPU 

1543 if not arch in ['X86_32', 'X86_64']: 

1544 trace.fail('Not running on X86_32 or X86_64. Skipping ...') 

1545 return trace.to_dict(info, True) 

1546 

1547 # Return none if SE Linux is in enforcing mode 

1548 cpuid = CPUID(trace) 

1549 if cpuid.is_selinux_enforcing: 

1550 trace.fail('SELinux is enforcing. Skipping ...') 

1551 return trace.to_dict(info, True) 

1552 

1553 # Get the cpu info from the CPUID register 

1554 max_extension_support = cpuid.get_max_extension_support() 

1555 cache_info = cpuid.get_cache(max_extension_support) 

1556 info = cpuid.get_info() 

1557 

1558 processor_brand = cpuid.get_processor_brand(max_extension_support) 

1559 

1560 # Get the Hz and scale 

1561 hz_actual = cpuid.get_raw_hz() 

1562 hz_actual = _to_decimal_string(hz_actual) 

1563 

1564 # Get the Hz and scale 

1565 hz_advertised, scale = _parse_cpu_brand_string(processor_brand) 

1566 info = { 

1567 'vendor_id_raw' : cpuid.get_vendor_id(), 

1568 'hardware_raw' : '', 

1569 'brand_raw' : processor_brand, 

1570 

1571 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale), 

1572 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 0), 

1573 'hz_advertised' : _hz_short_to_full(hz_advertised, scale), 

1574 'hz_actual' : _hz_short_to_full(hz_actual, 0), 

1575 

1576 'l2_cache_size' : cache_info['size_b'], 

1577 'l2_cache_line_size' : cache_info['line_size_b'], 

1578 'l2_cache_associativity' : cache_info['associativity'], 

1579 

1580 'stepping' : info['stepping'], 

1581 'model' : info['model'], 

1582 'family' : info['family'], 

1583 'processor_type' : info['processor_type'], 

1584 'flags' : cpuid.get_flags(max_extension_support) 

1585 } 

1586 

1587 info = _filter_dict_keys_with_empty_values(info) 

1588 trace.success() 

1589 except Exception as err: 

1590 from traceback import format_exc 

1591 err_string = format_exc() 

1592 trace._err = ''.join(['\t\t{0}\n'.format(n) for n in err_string.split('\n')]) + '\n' 

1593 return trace.to_dict(info, True) 

1594 

1595 return trace.to_dict(info, False) 

1596 

1597def _get_cpu_info_from_cpuid_subprocess_wrapper(queue): 

1598 orig_stdout = sys.stdout 

1599 orig_stderr = sys.stderr 

1600 

1601 output = _get_cpu_info_from_cpuid_actual() 

1602 

1603 sys.stdout = orig_stdout 

1604 sys.stderr = orig_stderr 

1605 

1606 queue.put(_obj_to_b64(output)) 

1607 

1608def _get_cpu_info_from_cpuid(): 

1609 ''' 

1610 Returns the CPU info gathered by querying the X86 cpuid register in a new process. 

1611 Returns {} on non X86 cpus. 

1612 Returns {} if SELinux is in enforcing mode. 

1613 ''' 

1614 

1615 g_trace.header('Tying to get info from CPUID ...') 

1616 

1617 from multiprocessing import Process, Queue 

1618 

1619 # Return {} if can't cpuid 

1620 if not DataSource.can_cpuid: 

1621 g_trace.fail('Can\'t CPUID. Skipping ...') 

1622 return {} 

1623 

1624 # Get the CPU arch and bits 

1625 arch, bits = _parse_arch(DataSource.arch_string_raw) 

1626 

1627 # Return {} if this is not an X86 CPU 

1628 if not arch in ['X86_32', 'X86_64']: 

1629 g_trace.fail('Not running on X86_32 or X86_64. Skipping ...') 

1630 return {} 

1631 

1632 try: 

1633 if CAN_CALL_CPUID_IN_SUBPROCESS: 

1634 # Start running the function in a subprocess 

1635 queue = Queue() 

1636 p = Process(target=_get_cpu_info_from_cpuid_subprocess_wrapper, args=(queue,)) 

1637 p.start() 

1638 

1639 # Wait for the process to end, while it is still alive 

1640 while p.is_alive(): 

1641 p.join(0) 

1642 

1643 # Return {} if it failed 

1644 if p.exitcode != 0: 

1645 g_trace.fail('Failed to run CPUID in process. Skipping ...') 

1646 return {} 

1647 

1648 # Return {} if no results 

1649 if queue.empty(): 

1650 g_trace.fail('Failed to get anything from CPUID process. Skipping ...') 

1651 return {} 

1652 # Return the result, only if there is something to read 

1653 else: 

1654 output = _b64_to_obj(queue.get()) 

1655 import pprint 

1656 pp = pprint.PrettyPrinter(indent=4) 

1657 #pp.pprint(output) 

1658 

1659 if 'output' in output and output['output']: 

1660 g_trace.write(output['output']) 

1661 

1662 if 'stdout' in output and output['stdout']: 

1663 sys.stdout.write('{0}\n'.format(output['stdout'])) 

1664 sys.stdout.flush() 

1665 

1666 if 'stderr' in output and output['stderr']: 

1667 sys.stderr.write('{0}\n'.format(output['stderr'])) 

1668 sys.stderr.flush() 

1669 

1670 if 'is_fail' not in output: 

1671 g_trace.fail('Failed to get is_fail from CPUID process. Skipping ...') 

1672 return {} 

1673 

1674 # Fail if there was an exception 

1675 if 'err' in output and output['err']: 

1676 g_trace.fail('Failed to run CPUID in process. Skipping ...') 

1677 g_trace.write(output['err']) 

1678 g_trace.write('Failed ...') 

1679 return {} 

1680 

1681 if 'is_fail' in output and output['is_fail']: 

1682 g_trace.write('Failed ...') 

1683 return {} 

1684 

1685 if 'info' not in output or not output['info']: 

1686 g_trace.fail('Failed to get return info from CPUID process. Skipping ...') 

1687 return {} 

1688 

1689 return output['info'] 

1690 else: 

1691 # FIXME: This should write the values like in the above call to actual 

1692 orig_stdout = sys.stdout 

1693 orig_stderr = sys.stderr 

1694 

1695 output = _get_cpu_info_from_cpuid_actual() 

1696 

1697 sys.stdout = orig_stdout 

1698 sys.stderr = orig_stderr 

1699 

1700 g_trace.success() 

1701 return output['info'] 

1702 except Exception as err: 

1703 g_trace.fail(err) 

1704 

1705 # Return {} if everything failed 

1706 return {} 

1707 

1708def _get_cpu_info_from_proc_cpuinfo(): 

1709 ''' 

1710 Returns the CPU info gathered from /proc/cpuinfo. 

1711 Returns {} if /proc/cpuinfo is not found. 

1712 ''' 

1713 

1714 g_trace.header('Tying to get info from /proc/cpuinfo ...') 

1715 

1716 try: 

1717 # Just return {} if there is no cpuinfo 

1718 if not DataSource.has_proc_cpuinfo(): 

1719 g_trace.fail('Failed to find /proc/cpuinfo. Skipping ...') 

1720 return {} 

1721 

1722 returncode, output = DataSource.cat_proc_cpuinfo() 

1723 if returncode != 0: 

1724 g_trace.fail('Failed to run cat /proc/cpuinfo. Skipping ...') 

1725 return {} 

1726 

1727 # Various fields 

1728 vendor_id = _get_field(False, output, None, '', 'vendor_id', 'vendor id', 'vendor') 

1729 processor_brand = _get_field(True, output, None, None, 'model name', 'cpu', 'processor', 'uarch') 

1730 cache_size = _get_field(False, output, None, '', 'cache size') 

1731 stepping = _get_field(False, output, int, -1, 'stepping') 

1732 model = _get_field(False, output, int, -1, 'model') 

1733 family = _get_field(False, output, int, -1, 'cpu family') 

1734 hardware = _get_field(False, output, None, '', 'Hardware') 

1735 

1736 # Flags 

1737 flags = _get_field(False, output, None, None, 'flags', 'Features', 'ASEs implemented') 

1738 if flags: 

1739 flags = flags.split() 

1740 flags.sort() 

1741 

1742 # Check for other cache format 

1743 if not cache_size: 

1744 try: 

1745 for i in range(0, 10): 

1746 name = "cache{0}".format(i) 

1747 value = _get_field(False, output, None, None, name) 

1748 if value: 

1749 value = [entry.split('=') for entry in value.split(' ')] 

1750 value = dict(value) 

1751 if 'level' in value and value['level'] == '3' and 'size' in value: 

1752 cache_size = value['size'] 

1753 break 

1754 except Exception: 

1755 pass 

1756 

1757 # Convert from MHz string to Hz 

1758 hz_actual = _get_field(False, output, None, '', 'cpu MHz', 'cpu speed', 'clock', 'cpu MHz dynamic', 'cpu MHz static') 

1759 hz_actual = hz_actual.lower().rstrip('mhz').strip() 

1760 hz_actual = _to_decimal_string(hz_actual) 

1761 

1762 # Convert from GHz/MHz string to Hz 

1763 hz_advertised, scale = (None, 0) 

1764 try: 

1765 hz_advertised, scale = _parse_cpu_brand_string(processor_brand) 

1766 except Exception: 

1767 pass 

1768 

1769 info = { 

1770 'hardware_raw' : hardware, 

1771 'brand_raw' : processor_brand, 

1772 

1773 'l3_cache_size' : _friendly_bytes_to_int(cache_size), 

1774 'flags' : flags, 

1775 'vendor_id_raw' : vendor_id, 

1776 'stepping' : stepping, 

1777 'model' : model, 

1778 'family' : family, 

1779 } 

1780 

1781 # Make the Hz the same for actual and advertised if missing any 

1782 if not hz_advertised or hz_advertised == '0.0': 

1783 hz_advertised = hz_actual 

1784 scale = 6 

1785 elif not hz_actual or hz_actual == '0.0': 

1786 hz_actual = hz_advertised 

1787 

1788 # Add the Hz if there is one 

1789 if _hz_short_to_full(hz_advertised, scale) > (0, 0): 

1790 info['hz_advertised_friendly'] = _hz_short_to_friendly(hz_advertised, scale) 

1791 info['hz_advertised'] = _hz_short_to_full(hz_advertised, scale) 

1792 if _hz_short_to_full(hz_actual, scale) > (0, 0): 

1793 info['hz_actual_friendly'] = _hz_short_to_friendly(hz_actual, 6) 

1794 info['hz_actual'] = _hz_short_to_full(hz_actual, 6) 

1795 

1796 info = _filter_dict_keys_with_empty_values(info, {'stepping':0, 'model':0, 'family':0}) 

1797 g_trace.success() 

1798 return info 

1799 except Exception as err: 

1800 g_trace.fail(err) 

1801 #raise # NOTE: To have this throw on error, uncomment this line 

1802 return {} 

1803 

1804def _get_cpu_info_from_cpufreq_info(): 

1805 ''' 

1806 Returns the CPU info gathered from cpufreq-info. 

1807 Returns {} if cpufreq-info is not found. 

1808 ''' 

1809 

1810 g_trace.header('Tying to get info from cpufreq-info ...') 

1811 

1812 try: 

1813 hz_brand, scale = '0.0', 0 

1814 

1815 if not DataSource.has_cpufreq_info(): 

1816 g_trace.fail('Failed to find cpufreq-info. Skipping ...') 

1817 return {} 

1818 

1819 returncode, output = DataSource.cpufreq_info() 

1820 if returncode != 0: 

1821 g_trace.fail('Failed to run cpufreq-info. Skipping ...') 

1822 return {} 

1823 

1824 hz_brand = output.split('current CPU frequency is')[1].split('\n')[0] 

1825 i = hz_brand.find('Hz') 

1826 assert(i != -1) 

1827 hz_brand = hz_brand[0 : i+2].strip().lower() 

1828 

1829 if hz_brand.endswith('mhz'): 

1830 scale = 6 

1831 elif hz_brand.endswith('ghz'): 

1832 scale = 9 

1833 hz_brand = hz_brand.rstrip('mhz').rstrip('ghz').strip() 

1834 hz_brand = _to_decimal_string(hz_brand) 

1835 

1836 info = { 

1837 'hz_advertised_friendly' : _hz_short_to_friendly(hz_brand, scale), 

1838 'hz_actual_friendly' : _hz_short_to_friendly(hz_brand, scale), 

1839 'hz_advertised' : _hz_short_to_full(hz_brand, scale), 

1840 'hz_actual' : _hz_short_to_full(hz_brand, scale), 

1841 } 

1842 

1843 info = _filter_dict_keys_with_empty_values(info) 

1844 g_trace.success() 

1845 return info 

1846 except Exception as err: 

1847 g_trace.fail(err) 

1848 #raise # NOTE: To have this throw on error, uncomment this line 

1849 return {} 

1850 

1851def _get_cpu_info_from_lscpu(): 

1852 ''' 

1853 Returns the CPU info gathered from lscpu. 

1854 Returns {} if lscpu is not found. 

1855 ''' 

1856 

1857 g_trace.header('Tying to get info from lscpu ...') 

1858 

1859 try: 

1860 if not DataSource.has_lscpu(): 

1861 g_trace.fail('Failed to find lscpu. Skipping ...') 

1862 return {} 

1863 

1864 returncode, output = DataSource.lscpu() 

1865 if returncode != 0: 

1866 g_trace.fail('Failed to run lscpu. Skipping ...') 

1867 return {} 

1868 

1869 info = {} 

1870 

1871 new_hz = _get_field(False, output, None, None, 'CPU max MHz', 'CPU MHz') 

1872 if new_hz: 

1873 new_hz = _to_decimal_string(new_hz) 

1874 scale = 6 

1875 info['hz_advertised_friendly'] = _hz_short_to_friendly(new_hz, scale) 

1876 info['hz_actual_friendly'] = _hz_short_to_friendly(new_hz, scale) 

1877 info['hz_advertised'] = _hz_short_to_full(new_hz, scale) 

1878 info['hz_actual'] = _hz_short_to_full(new_hz, scale) 

1879 

1880 new_hz = _get_field(False, output, None, None, 'CPU dynamic MHz', 'CPU static MHz') 

1881 if new_hz: 

1882 new_hz = _to_decimal_string(new_hz) 

1883 scale = 6 

1884 info['hz_advertised_friendly'] = _hz_short_to_friendly(new_hz, scale) 

1885 info['hz_actual_friendly'] = _hz_short_to_friendly(new_hz, scale) 

1886 info['hz_advertised'] = _hz_short_to_full(new_hz, scale) 

1887 info['hz_actual'] = _hz_short_to_full(new_hz, scale) 

1888 

1889 vendor_id = _get_field(False, output, None, None, 'Vendor ID') 

1890 if vendor_id: 

1891 info['vendor_id_raw'] = vendor_id 

1892 

1893 brand = _get_field(False, output, None, None, 'Model name') 

1894 if brand: 

1895 info['brand_raw'] = brand 

1896 else: 

1897 brand = _get_field(False, output, None, None, 'Model') 

1898 if brand and not brand.isdigit(): 

1899 info['brand_raw'] = brand 

1900 

1901 family = _get_field(False, output, None, None, 'CPU family') 

1902 if family and family.isdigit(): 

1903 info['family'] = int(family) 

1904 

1905 stepping = _get_field(False, output, None, None, 'Stepping') 

1906 if stepping and stepping.isdigit(): 

1907 info['stepping'] = int(stepping) 

1908 

1909 model = _get_field(False, output, None, None, 'Model') 

1910 if model and model.isdigit(): 

1911 info['model'] = int(model) 

1912 

1913 l1_data_cache_size = _get_field(False, output, None, None, 'L1d cache') 

1914 if l1_data_cache_size: 

1915 l1_data_cache_size = l1_data_cache_size.split('(')[0].strip() 

1916 info['l1_data_cache_size'] = _friendly_bytes_to_int(l1_data_cache_size) 

1917 

1918 l1_instruction_cache_size = _get_field(False, output, None, None, 'L1i cache') 

1919 if l1_instruction_cache_size: 

1920 l1_instruction_cache_size = l1_instruction_cache_size.split('(')[0].strip() 

1921 info['l1_instruction_cache_size'] = _friendly_bytes_to_int(l1_instruction_cache_size) 

1922 

1923 l2_cache_size = _get_field(False, output, None, None, 'L2 cache', 'L2d cache') 

1924 if l2_cache_size: 

1925 l2_cache_size = l2_cache_size.split('(')[0].strip() 

1926 info['l2_cache_size'] = _friendly_bytes_to_int(l2_cache_size) 

1927 

1928 l3_cache_size = _get_field(False, output, None, None, 'L3 cache') 

1929 if l3_cache_size: 

1930 l3_cache_size = l3_cache_size.split('(')[0].strip() 

1931 info['l3_cache_size'] = _friendly_bytes_to_int(l3_cache_size) 

1932 

1933 # Flags 

1934 flags = _get_field(False, output, None, None, 'flags', 'Features', 'ASEs implemented') 

1935 if flags: 

1936 flags = flags.split() 

1937 flags.sort() 

1938 info['flags'] = flags 

1939 

1940 info = _filter_dict_keys_with_empty_values(info, {'stepping':0, 'model':0, 'family':0}) 

1941 g_trace.success() 

1942 return info 

1943 except Exception as err: 

1944 g_trace.fail(err) 

1945 #raise # NOTE: To have this throw on error, uncomment this line 

1946 return {} 

1947 

1948def _get_cpu_info_from_dmesg(): 

1949 ''' 

1950 Returns the CPU info gathered from dmesg. 

1951 Returns {} if dmesg is not found or does not have the desired info. 

1952 ''' 

1953 

1954 g_trace.header('Tying to get info from the dmesg ...') 

1955 

1956 # Just return {} if this arch has an unreliable dmesg log 

1957 arch, bits = _parse_arch(DataSource.arch_string_raw) 

1958 if arch in ['S390X']: 

1959 g_trace.fail('Running on S390X. Skipping ...') 

1960 return {} 

1961 

1962 # Just return {} if there is no dmesg 

1963 if not DataSource.has_dmesg(): 

1964 g_trace.fail('Failed to find dmesg. Skipping ...') 

1965 return {} 

1966 

1967 # If dmesg fails return {} 

1968 returncode, output = DataSource.dmesg_a() 

1969 if output is None or returncode != 0: 

1970 g_trace.fail('Failed to run \"dmesg -a\". Skipping ...') 

1971 return {} 

1972 

1973 info = _parse_dmesg_output(output) 

1974 g_trace.success() 

1975 return info 

1976 

1977 

1978# https://openpowerfoundation.org/wp-content/uploads/2016/05/LoPAPR_DRAFT_v11_24March2016_cmt1.pdf 

1979# page 767 

1980def _get_cpu_info_from_ibm_pa_features(): 

1981 ''' 

1982 Returns the CPU info gathered from lsprop /proc/device-tree/cpus/*/ibm,pa-features 

1983 Returns {} if lsprop is not found or ibm,pa-features does not have the desired info. 

1984 ''' 

1985 

1986 g_trace.header('Tying to get info from lsprop ...') 

1987 

1988 try: 

1989 # Just return {} if there is no lsprop 

1990 if not DataSource.has_ibm_pa_features(): 

1991 g_trace.fail('Failed to find lsprop. Skipping ...') 

1992 return {} 

1993 

1994 # If ibm,pa-features fails return {} 

1995 returncode, output = DataSource.ibm_pa_features() 

1996 if output is None or returncode != 0: 

1997 g_trace.fail('Failed to glob /proc/device-tree/cpus/*/ibm,pa-features. Skipping ...') 

1998 return {} 

1999 

2000 # Filter out invalid characters from output 

2001 value = output.split("ibm,pa-features")[1].lower() 

2002 value = [s for s in value if s in list('0123456789abcfed')] 

2003 value = ''.join(value) 

2004 

2005 # Get data converted to Uint32 chunks 

2006 left = int(value[0 : 8], 16) 

2007 right = int(value[8 : 16], 16) 

2008 

2009 # Get the CPU flags 

2010 flags = { 

2011 # Byte 0 

2012 'mmu' : _is_bit_set(left, 0), 

2013 'fpu' : _is_bit_set(left, 1), 

2014 'slb' : _is_bit_set(left, 2), 

2015 'run' : _is_bit_set(left, 3), 

2016 #'reserved' : _is_bit_set(left, 4), 

2017 'dabr' : _is_bit_set(left, 5), 

2018 'ne' : _is_bit_set(left, 6), 

2019 'wtr' : _is_bit_set(left, 7), 

2020 

2021 # Byte 1 

2022 'mcr' : _is_bit_set(left, 8), 

2023 'dsisr' : _is_bit_set(left, 9), 

2024 'lp' : _is_bit_set(left, 10), 

2025 'ri' : _is_bit_set(left, 11), 

2026 'dabrx' : _is_bit_set(left, 12), 

2027 'sprg3' : _is_bit_set(left, 13), 

2028 'rislb' : _is_bit_set(left, 14), 

2029 'pp' : _is_bit_set(left, 15), 

2030 

2031 # Byte 2 

2032 'vpm' : _is_bit_set(left, 16), 

2033 'dss_2.05' : _is_bit_set(left, 17), 

2034 #'reserved' : _is_bit_set(left, 18), 

2035 'dar' : _is_bit_set(left, 19), 

2036 #'reserved' : _is_bit_set(left, 20), 

2037 'ppr' : _is_bit_set(left, 21), 

2038 'dss_2.02' : _is_bit_set(left, 22), 

2039 'dss_2.06' : _is_bit_set(left, 23), 

2040 

2041 # Byte 3 

2042 'lsd_in_dscr' : _is_bit_set(left, 24), 

2043 'ugr_in_dscr' : _is_bit_set(left, 25), 

2044 #'reserved' : _is_bit_set(left, 26), 

2045 #'reserved' : _is_bit_set(left, 27), 

2046 #'reserved' : _is_bit_set(left, 28), 

2047 #'reserved' : _is_bit_set(left, 29), 

2048 #'reserved' : _is_bit_set(left, 30), 

2049 #'reserved' : _is_bit_set(left, 31), 

2050 

2051 # Byte 4 

2052 'sso_2.06' : _is_bit_set(right, 0), 

2053 #'reserved' : _is_bit_set(right, 1), 

2054 #'reserved' : _is_bit_set(right, 2), 

2055 #'reserved' : _is_bit_set(right, 3), 

2056 #'reserved' : _is_bit_set(right, 4), 

2057 #'reserved' : _is_bit_set(right, 5), 

2058 #'reserved' : _is_bit_set(right, 6), 

2059 #'reserved' : _is_bit_set(right, 7), 

2060 

2061 # Byte 5 

2062 'le' : _is_bit_set(right, 8), 

2063 'cfar' : _is_bit_set(right, 9), 

2064 'eb' : _is_bit_set(right, 10), 

2065 'lsq_2.07' : _is_bit_set(right, 11), 

2066 #'reserved' : _is_bit_set(right, 12), 

2067 #'reserved' : _is_bit_set(right, 13), 

2068 #'reserved' : _is_bit_set(right, 14), 

2069 #'reserved' : _is_bit_set(right, 15), 

2070 

2071 # Byte 6 

2072 'dss_2.07' : _is_bit_set(right, 16), 

2073 #'reserved' : _is_bit_set(right, 17), 

2074 #'reserved' : _is_bit_set(right, 18), 

2075 #'reserved' : _is_bit_set(right, 19), 

2076 #'reserved' : _is_bit_set(right, 20), 

2077 #'reserved' : _is_bit_set(right, 21), 

2078 #'reserved' : _is_bit_set(right, 22), 

2079 #'reserved' : _is_bit_set(right, 23), 

2080 

2081 # Byte 7 

2082 #'reserved' : _is_bit_set(right, 24), 

2083 #'reserved' : _is_bit_set(right, 25), 

2084 #'reserved' : _is_bit_set(right, 26), 

2085 #'reserved' : _is_bit_set(right, 27), 

2086 #'reserved' : _is_bit_set(right, 28), 

2087 #'reserved' : _is_bit_set(right, 29), 

2088 #'reserved' : _is_bit_set(right, 30), 

2089 #'reserved' : _is_bit_set(right, 31), 

2090 } 

2091 

2092 # Get a list of only the flags that are true 

2093 flags = [k for k, v in flags.items() if v] 

2094 flags.sort() 

2095 

2096 info = { 

2097 'flags' : flags 

2098 } 

2099 info = _filter_dict_keys_with_empty_values(info) 

2100 g_trace.success() 

2101 return info 

2102 except Exception as err: 

2103 g_trace.fail(err) 

2104 return {} 

2105 

2106 

2107def _get_cpu_info_from_cat_var_run_dmesg_boot(): 

2108 ''' 

2109 Returns the CPU info gathered from /var/run/dmesg.boot. 

2110 Returns {} if dmesg is not found or does not have the desired info. 

2111 ''' 

2112 

2113 g_trace.header('Tying to get info from the /var/run/dmesg.boot log ...') 

2114 

2115 # Just return {} if there is no /var/run/dmesg.boot 

2116 if not DataSource.has_var_run_dmesg_boot(): 

2117 g_trace.fail('Failed to find /var/run/dmesg.boot file. Skipping ...') 

2118 return {} 

2119 

2120 # If dmesg.boot fails return {} 

2121 returncode, output = DataSource.cat_var_run_dmesg_boot() 

2122 if output is None or returncode != 0: 

2123 g_trace.fail('Failed to run \"cat /var/run/dmesg.boot\". Skipping ...') 

2124 return {} 

2125 

2126 info = _parse_dmesg_output(output) 

2127 g_trace.success() 

2128 return info 

2129 

2130 

2131def _get_cpu_info_from_sysctl(): 

2132 ''' 

2133 Returns the CPU info gathered from sysctl. 

2134 Returns {} if sysctl is not found. 

2135 ''' 

2136 

2137 g_trace.header('Tying to get info from sysctl ...') 

2138 

2139 try: 

2140 # Just return {} if there is no sysctl 

2141 if not DataSource.has_sysctl(): 

2142 g_trace.fail('Failed to find sysctl. Skipping ...') 

2143 return {} 

2144 

2145 # If sysctl fails return {} 

2146 returncode, output = DataSource.sysctl_machdep_cpu_hw_cpufrequency() 

2147 if output is None or returncode != 0: 

2148 g_trace.fail('Failed to run \"sysctl machdep.cpu hw.cpufrequency\". Skipping ...') 

2149 return {} 

2150 

2151 # Various fields 

2152 vendor_id = _get_field(False, output, None, None, 'machdep.cpu.vendor') 

2153 processor_brand = _get_field(True, output, None, None, 'machdep.cpu.brand_string') 

2154 cache_size = _get_field(False, output, int, 0, 'machdep.cpu.cache.size') 

2155 stepping = _get_field(False, output, int, 0, 'machdep.cpu.stepping') 

2156 model = _get_field(False, output, int, 0, 'machdep.cpu.model') 

2157 family = _get_field(False, output, int, 0, 'machdep.cpu.family') 

2158 

2159 # Flags 

2160 flags = _get_field(False, output, None, '', 'machdep.cpu.features').lower().split() 

2161 flags.extend(_get_field(False, output, None, '', 'machdep.cpu.leaf7_features').lower().split()) 

2162 flags.extend(_get_field(False, output, None, '', 'machdep.cpu.extfeatures').lower().split()) 

2163 flags.sort() 

2164 

2165 # Convert from GHz/MHz string to Hz 

2166 hz_advertised, scale = _parse_cpu_brand_string(processor_brand) 

2167 hz_actual = _get_field(False, output, None, None, 'hw.cpufrequency') 

2168 hz_actual = _to_decimal_string(hz_actual) 

2169 

2170 info = { 

2171 'vendor_id_raw' : vendor_id, 

2172 'brand_raw' : processor_brand, 

2173 

2174 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale), 

2175 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 0), 

2176 'hz_advertised' : _hz_short_to_full(hz_advertised, scale), 

2177 'hz_actual' : _hz_short_to_full(hz_actual, 0), 

2178 

2179 'l2_cache_size' : int(cache_size) * 1024, 

2180 

2181 'stepping' : stepping, 

2182 'model' : model, 

2183 'family' : family, 

2184 'flags' : flags 

2185 } 

2186 

2187 info = _filter_dict_keys_with_empty_values(info) 

2188 g_trace.success() 

2189 return info 

2190 except Exception as err: 

2191 g_trace.fail(err) 

2192 return {} 

2193 

2194 

2195def _get_cpu_info_from_sysinfo(): 

2196 ''' 

2197 Returns the CPU info gathered from sysinfo. 

2198 Returns {} if sysinfo is not found. 

2199 ''' 

2200 

2201 info = _get_cpu_info_from_sysinfo_v1() 

2202 info.update(_get_cpu_info_from_sysinfo_v2()) 

2203 return info 

2204 

2205def _get_cpu_info_from_sysinfo_v1(): 

2206 ''' 

2207 Returns the CPU info gathered from sysinfo. 

2208 Returns {} if sysinfo is not found. 

2209 ''' 

2210 

2211 g_trace.header('Tying to get info from sysinfo version 1 ...') 

2212 

2213 try: 

2214 # Just return {} if there is no sysinfo 

2215 if not DataSource.has_sysinfo(): 

2216 g_trace.fail('Failed to find sysinfo. Skipping ...') 

2217 return {} 

2218 

2219 # If sysinfo fails return {} 

2220 returncode, output = DataSource.sysinfo_cpu() 

2221 if output is None or returncode != 0: 

2222 g_trace.fail('Failed to run \"sysinfo -cpu\". Skipping ...') 

2223 return {} 

2224 

2225 # Various fields 

2226 vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ') 

2227 processor_brand = output.split('CPU #0: "')[1].split('"\n')[0].strip() 

2228 cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size') 

2229 stepping = int(output.split(', stepping ')[1].split(',')[0].strip()) 

2230 model = int(output.split(', model ')[1].split(',')[0].strip()) 

2231 family = int(output.split(', family ')[1].split(',')[0].strip()) 

2232 

2233 # Flags 

2234 flags = [] 

2235 for line in output.split('\n'): 

2236 if line.startswith('\t\t'): 

2237 for flag in line.strip().lower().split(): 

2238 flags.append(flag) 

2239 flags.sort() 

2240 

2241 # Convert from GHz/MHz string to Hz 

2242 hz_advertised, scale = _parse_cpu_brand_string(processor_brand) 

2243 hz_actual = hz_advertised 

2244 

2245 info = { 

2246 'vendor_id_raw' : vendor_id, 

2247 'brand_raw' : processor_brand, 

2248 

2249 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale), 

2250 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, scale), 

2251 'hz_advertised' : _hz_short_to_full(hz_advertised, scale), 

2252 'hz_actual' : _hz_short_to_full(hz_actual, scale), 

2253 

2254 'l2_cache_size' : _to_friendly_bytes(cache_size), 

2255 

2256 'stepping' : stepping, 

2257 'model' : model, 

2258 'family' : family, 

2259 'flags' : flags 

2260 } 

2261 

2262 info = _filter_dict_keys_with_empty_values(info) 

2263 g_trace.success() 

2264 return info 

2265 except Exception as err: 

2266 g_trace.fail(err) 

2267 #raise # NOTE: To have this throw on error, uncomment this line 

2268 return {} 

2269 

2270def _get_cpu_info_from_sysinfo_v2(): 

2271 ''' 

2272 Returns the CPU info gathered from sysinfo. 

2273 Returns {} if sysinfo is not found. 

2274 ''' 

2275 

2276 g_trace.header('Tying to get info from sysinfo version 2 ...') 

2277 

2278 try: 

2279 # Just return {} if there is no sysinfo 

2280 if not DataSource.has_sysinfo(): 

2281 g_trace.fail('Failed to find sysinfo. Skipping ...') 

2282 return {} 

2283 

2284 # If sysinfo fails return {} 

2285 returncode, output = DataSource.sysinfo_cpu() 

2286 if output is None or returncode != 0: 

2287 g_trace.fail('Failed to run \"sysinfo -cpu\". Skipping ...') 

2288 return {} 

2289 

2290 # Various fields 

2291 vendor_id = '' #_get_field(False, output, None, None, 'CPU #0: ') 

2292 processor_brand = output.split('CPU #0: "')[1].split('"\n')[0].strip() 

2293 cache_size = '' #_get_field(False, output, None, None, 'machdep.cpu.cache.size') 

2294 signature = output.split('Signature:')[1].split('\n')[0].strip() 

2295 # 

2296 stepping = int(signature.split('stepping ')[1].split(',')[0].strip()) 

2297 model = int(signature.split('model ')[1].split(',')[0].strip()) 

2298 family = int(signature.split('family ')[1].split(',')[0].strip()) 

2299 

2300 # Flags 

2301 def get_subsection_flags(output): 

2302 retval = [] 

2303 for line in output.split('\n')[1:]: 

2304 if not line.startswith(' ') and not line.startswith(' '): break 

2305 for entry in line.strip().lower().split(' '): 

2306 retval.append(entry) 

2307 return retval 

2308 

2309 flags = get_subsection_flags(output.split('Features: ')[1]) + \ 

2310 get_subsection_flags(output.split('Extended Features (0x00000001): ')[1]) + \ 

2311 get_subsection_flags(output.split('Extended Features (0x80000001): ')[1]) 

2312 flags.sort() 

2313 

2314 # Convert from GHz/MHz string to Hz 

2315 lines = [n for n in output.split('\n') if n] 

2316 raw_hz = lines[0].split('running at ')[1].strip().lower() 

2317 hz_advertised = raw_hz.rstrip('mhz').rstrip('ghz').strip() 

2318 hz_advertised = _to_decimal_string(hz_advertised) 

2319 hz_actual = hz_advertised 

2320 

2321 scale = 0 

2322 if raw_hz.endswith('mhz'): 

2323 scale = 6 

2324 elif raw_hz.endswith('ghz'): 

2325 scale = 9 

2326 

2327 info = { 

2328 'vendor_id_raw' : vendor_id, 

2329 'brand_raw' : processor_brand, 

2330 

2331 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale), 

2332 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, scale), 

2333 'hz_advertised' : _hz_short_to_full(hz_advertised, scale), 

2334 'hz_actual' : _hz_short_to_full(hz_actual, scale), 

2335 

2336 'l2_cache_size' : _to_friendly_bytes(cache_size), 

2337 

2338 'stepping' : stepping, 

2339 'model' : model, 

2340 'family' : family, 

2341 'flags' : flags 

2342 } 

2343 

2344 info = _filter_dict_keys_with_empty_values(info) 

2345 g_trace.success() 

2346 return info 

2347 except Exception as err: 

2348 g_trace.fail(err) 

2349 #raise # NOTE: To have this throw on error, uncomment this line 

2350 return {} 

2351 

2352def _get_cpu_info_from_wmic(): 

2353 ''' 

2354 Returns the CPU info gathered from WMI. 

2355 Returns {} if not on Windows, or wmic is not installed. 

2356 ''' 

2357 g_trace.header('Tying to get info from wmic ...') 

2358 

2359 try: 

2360 # Just return {} if not Windows or there is no wmic 

2361 if not DataSource.is_windows or not DataSource.has_wmic(): 

2362 g_trace.fail('Failed to find WMIC, or not on Windows. Skipping ...') 

2363 return {} 

2364 

2365 returncode, output = DataSource.wmic_cpu() 

2366 if output is None or returncode != 0: 

2367 g_trace.fail('Failed to run wmic. Skipping ...') 

2368 return {} 

2369 

2370 # Break the list into key values pairs 

2371 value = output.split("\n") 

2372 value = [s.rstrip().split('=') for s in value if '=' in s] 

2373 value = {k: v for k, v in value if v} 

2374 

2375 # Get the advertised MHz 

2376 processor_brand = value.get('Name') 

2377 hz_advertised, scale_advertised = _parse_cpu_brand_string(processor_brand) 

2378 

2379 # Get the actual MHz 

2380 hz_actual = value.get('CurrentClockSpeed') 

2381 scale_actual = 6 

2382 if hz_actual: 

2383 hz_actual = _to_decimal_string(hz_actual) 

2384 

2385 # Get cache sizes 

2386 l2_cache_size = value.get('L2CacheSize') # NOTE: L2CacheSize is in kilobytes 

2387 if l2_cache_size: 

2388 l2_cache_size = int(l2_cache_size) * 1024 

2389 

2390 l3_cache_size = value.get('L3CacheSize') # NOTE: L3CacheSize is in kilobytes 

2391 if l3_cache_size: 

2392 l3_cache_size = int(l3_cache_size) * 1024 

2393 

2394 # Get family, model, and stepping 

2395 family, model, stepping = '', '', '' 

2396 description = value.get('Description') or value.get('Caption') 

2397 entries = description.split(' ') 

2398 

2399 if 'Family' in entries and entries.index('Family') < len(entries)-1: 

2400 i = entries.index('Family') 

2401 family = int(entries[i + 1]) 

2402 

2403 if 'Model' in entries and entries.index('Model') < len(entries)-1: 

2404 i = entries.index('Model') 

2405 model = int(entries[i + 1]) 

2406 

2407 if 'Stepping' in entries and entries.index('Stepping') < len(entries)-1: 

2408 i = entries.index('Stepping') 

2409 stepping = int(entries[i + 1]) 

2410 

2411 info = { 

2412 'vendor_id_raw' : value.get('Manufacturer'), 

2413 'brand_raw' : processor_brand, 

2414 

2415 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale_advertised), 

2416 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, scale_actual), 

2417 'hz_advertised' : _hz_short_to_full(hz_advertised, scale_advertised), 

2418 'hz_actual' : _hz_short_to_full(hz_actual, scale_actual), 

2419 

2420 'l2_cache_size' : l2_cache_size, 

2421 'l3_cache_size' : l3_cache_size, 

2422 

2423 'stepping' : stepping, 

2424 'model' : model, 

2425 'family' : family, 

2426 } 

2427 

2428 info = _filter_dict_keys_with_empty_values(info) 

2429 g_trace.success() 

2430 return info 

2431 except Exception as err: 

2432 g_trace.fail(err) 

2433 #raise # NOTE: To have this throw on error, uncomment this line 

2434 return {} 

2435 

2436def _get_cpu_info_from_registry(): 

2437 ''' 

2438 Returns the CPU info gathered from the Windows Registry. 

2439 Returns {} if not on Windows. 

2440 ''' 

2441 

2442 g_trace.header('Tying to get info from Windows registry ...') 

2443 

2444 try: 

2445 # Just return {} if not on Windows 

2446 if not DataSource.is_windows: 

2447 g_trace.fail('Not running on Windows. Skipping ...') 

2448 return {} 

2449 

2450 # Get the CPU name 

2451 processor_brand = DataSource.winreg_processor_brand().strip() 

2452 

2453 # Get the CPU vendor id 

2454 vendor_id = DataSource.winreg_vendor_id_raw() 

2455 

2456 # Get the CPU arch and bits 

2457 arch_string_raw = DataSource.winreg_arch_string_raw() 

2458 arch, bits = _parse_arch(arch_string_raw) 

2459 

2460 # Get the actual CPU Hz 

2461 hz_actual = DataSource.winreg_hz_actual() 

2462 hz_actual = _to_decimal_string(hz_actual) 

2463 

2464 # Get the advertised CPU Hz 

2465 hz_advertised, scale = _parse_cpu_brand_string(processor_brand) 

2466 

2467 # If advertised hz not found, use the actual hz 

2468 if hz_advertised == '0.0': 

2469 scale = 6 

2470 hz_advertised = _to_decimal_string(hz_actual) 

2471 

2472 # Get the CPU features 

2473 feature_bits = DataSource.winreg_feature_bits() 

2474 

2475 def is_set(bit): 

2476 mask = 0x80000000 >> bit 

2477 retval = mask & feature_bits > 0 

2478 return retval 

2479 

2480 # http://en.wikipedia.org/wiki/CPUID 

2481 # http://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean 

2482 # http://www.lohninger.com/helpcsuite/public_constants_cpuid.htm 

2483 flags = { 

2484 'fpu' : is_set(0), # Floating Point Unit 

2485 'vme' : is_set(1), # V86 Mode Extensions 

2486 'de' : is_set(2), # Debug Extensions - I/O breakpoints supported 

2487 'pse' : is_set(3), # Page Size Extensions (4 MB pages supported) 

2488 'tsc' : is_set(4), # Time Stamp Counter and RDTSC instruction are available 

2489 'msr' : is_set(5), # Model Specific Registers 

2490 'pae' : is_set(6), # Physical Address Extensions (36 bit address, 2MB pages) 

2491 'mce' : is_set(7), # Machine Check Exception supported 

2492 'cx8' : is_set(8), # Compare Exchange Eight Byte instruction available 

2493 'apic' : is_set(9), # Local APIC present (multiprocessor operation support) 

2494 'sepamd' : is_set(10), # Fast system calls (AMD only) 

2495 'sep' : is_set(11), # Fast system calls 

2496 'mtrr' : is_set(12), # Memory Type Range Registers 

2497 'pge' : is_set(13), # Page Global Enable 

2498 'mca' : is_set(14), # Machine Check Architecture 

2499 'cmov' : is_set(15), # Conditional MOVe instructions 

2500 'pat' : is_set(16), # Page Attribute Table 

2501 'pse36' : is_set(17), # 36 bit Page Size Extensions 

2502 'serial' : is_set(18), # Processor Serial Number 

2503 'clflush' : is_set(19), # Cache Flush 

2504 #'reserved1' : is_set(20), # reserved 

2505 'dts' : is_set(21), # Debug Trace Store 

2506 'acpi' : is_set(22), # ACPI support 

2507 'mmx' : is_set(23), # MultiMedia Extensions 

2508 'fxsr' : is_set(24), # FXSAVE and FXRSTOR instructions 

2509 'sse' : is_set(25), # SSE instructions 

2510 'sse2' : is_set(26), # SSE2 (WNI) instructions 

2511 'ss' : is_set(27), # self snoop 

2512 #'reserved2' : is_set(28), # reserved 

2513 'tm' : is_set(29), # Automatic clock control 

2514 'ia64' : is_set(30), # IA64 instructions 

2515 '3dnow' : is_set(31) # 3DNow! instructions available 

2516 } 

2517 

2518 # Get a list of only the flags that are true 

2519 flags = [k for k, v in flags.items() if v] 

2520 flags.sort() 

2521 

2522 info = { 

2523 'vendor_id_raw' : vendor_id, 

2524 'brand_raw' : processor_brand, 

2525 

2526 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale), 

2527 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 6), 

2528 'hz_advertised' : _hz_short_to_full(hz_advertised, scale), 

2529 'hz_actual' : _hz_short_to_full(hz_actual, 6), 

2530 

2531 'flags' : flags 

2532 } 

2533 

2534 info = _filter_dict_keys_with_empty_values(info) 

2535 g_trace.success() 

2536 return info 

2537 except Exception as err: 

2538 g_trace.fail(err) 

2539 return {} 

2540 

2541def _get_cpu_info_from_kstat(): 

2542 ''' 

2543 Returns the CPU info gathered from isainfo and kstat. 

2544 Returns {} if isainfo or kstat are not found. 

2545 ''' 

2546 

2547 g_trace.header('Tying to get info from kstat ...') 

2548 

2549 try: 

2550 # Just return {} if there is no isainfo or kstat 

2551 if not DataSource.has_isainfo() or not DataSource.has_kstat(): 

2552 g_trace.fail('Failed to find isinfo or kstat. Skipping ...') 

2553 return {} 

2554 

2555 # If isainfo fails return {} 

2556 returncode, flag_output = DataSource.isainfo_vb() 

2557 if flag_output is None or returncode != 0: 

2558 g_trace.fail('Failed to run \"isainfo -vb\". Skipping ...') 

2559 return {} 

2560 

2561 # If kstat fails return {} 

2562 returncode, kstat = DataSource.kstat_m_cpu_info() 

2563 if kstat is None or returncode != 0: 

2564 g_trace.fail('Failed to run \"kstat -m cpu_info\". Skipping ...') 

2565 return {} 

2566 

2567 # Various fields 

2568 vendor_id = kstat.split('\tvendor_id ')[1].split('\n')[0].strip() 

2569 processor_brand = kstat.split('\tbrand ')[1].split('\n')[0].strip() 

2570 stepping = int(kstat.split('\tstepping ')[1].split('\n')[0].strip()) 

2571 model = int(kstat.split('\tmodel ')[1].split('\n')[0].strip()) 

2572 family = int(kstat.split('\tfamily ')[1].split('\n')[0].strip()) 

2573 

2574 # Flags 

2575 flags = flag_output.strip().split('\n')[-1].strip().lower().split() 

2576 flags.sort() 

2577 

2578 # Convert from GHz/MHz string to Hz 

2579 scale = 6 

2580 hz_advertised = kstat.split('\tclock_MHz ')[1].split('\n')[0].strip() 

2581 hz_advertised = _to_decimal_string(hz_advertised) 

2582 

2583 # Convert from GHz/MHz string to Hz 

2584 hz_actual = kstat.split('\tcurrent_clock_Hz ')[1].split('\n')[0].strip() 

2585 hz_actual = _to_decimal_string(hz_actual) 

2586 

2587 info = { 

2588 'vendor_id_raw' : vendor_id, 

2589 'brand_raw' : processor_brand, 

2590 

2591 'hz_advertised_friendly' : _hz_short_to_friendly(hz_advertised, scale), 

2592 'hz_actual_friendly' : _hz_short_to_friendly(hz_actual, 0), 

2593 'hz_advertised' : _hz_short_to_full(hz_advertised, scale), 

2594 'hz_actual' : _hz_short_to_full(hz_actual, 0), 

2595 

2596 'stepping' : stepping, 

2597 'model' : model, 

2598 'family' : family, 

2599 'flags' : flags 

2600 } 

2601 

2602 info = _filter_dict_keys_with_empty_values(info) 

2603 g_trace.success() 

2604 return info 

2605 except Exception as err: 

2606 g_trace.fail(err) 

2607 return {} 

2608 

2609def _get_cpu_info_from_platform_uname(): 

2610 

2611 g_trace.header('Tying to get info from platform.uname ...') 

2612 

2613 try: 

2614 uname = DataSource.uname_string_raw.split(',')[0] 

2615 

2616 family, model, stepping = (None, None, None) 

2617 entries = uname.split(' ') 

2618 

2619 if 'Family' in entries and entries.index('Family') < len(entries)-1: 

2620 i = entries.index('Family') 

2621 family = int(entries[i + 1]) 

2622 

2623 if 'Model' in entries and entries.index('Model') < len(entries)-1: 

2624 i = entries.index('Model') 

2625 model = int(entries[i + 1]) 

2626 

2627 if 'Stepping' in entries and entries.index('Stepping') < len(entries)-1: 

2628 i = entries.index('Stepping') 

2629 stepping = int(entries[i + 1]) 

2630 

2631 info = { 

2632 'family' : family, 

2633 'model' : model, 

2634 'stepping' : stepping 

2635 } 

2636 info = _filter_dict_keys_with_empty_values(info) 

2637 g_trace.success() 

2638 return info 

2639 except Exception as err: 

2640 g_trace.fail(err) 

2641 return {} 

2642 

2643def _get_cpu_info_internal(): 

2644 ''' 

2645 Returns the CPU info by using the best sources of information for your OS. 

2646 Returns {} if nothing is found. 

2647 ''' 

2648 

2649 g_trace.write('!' * 80) 

2650 

2651 # Get the CPU arch and bits 

2652 arch, bits = _parse_arch(DataSource.arch_string_raw) 

2653 

2654 friendly_maxsize = { 2**31-1: '32 bit', 2**63-1: '64 bit' }.get(sys.maxsize) or 'unknown bits' 

2655 friendly_version = "{0}.{1}.{2}.{3}.{4}".format(*sys.version_info) 

2656 PYTHON_VERSION = "{0} ({1})".format(friendly_version, friendly_maxsize) 

2657 

2658 info = { 

2659 'python_version' : PYTHON_VERSION, 

2660 'cpuinfo_version' : CPUINFO_VERSION, 

2661 'cpuinfo_version_string' : CPUINFO_VERSION_STRING, 

2662 'arch' : arch, 

2663 'bits' : bits, 

2664 'count' : DataSource.cpu_count, 

2665 'arch_string_raw' : DataSource.arch_string_raw, 

2666 } 

2667 

2668 g_trace.write("python_version: {0}".format(info['python_version'])) 

2669 g_trace.write("cpuinfo_version: {0}".format(info['cpuinfo_version'])) 

2670 g_trace.write("arch: {0}".format(info['arch'])) 

2671 g_trace.write("bits: {0}".format(info['bits'])) 

2672 g_trace.write("count: {0}".format(info['count'])) 

2673 g_trace.write("arch_string_raw: {0}".format(info['arch_string_raw'])) 

2674 

2675 # Try the Windows wmic 

2676 _copy_new_fields(info, _get_cpu_info_from_wmic()) 

2677 

2678 # Try the Windows registry 

2679 _copy_new_fields(info, _get_cpu_info_from_registry()) 

2680 

2681 # Try /proc/cpuinfo 

2682 _copy_new_fields(info, _get_cpu_info_from_proc_cpuinfo()) 

2683 

2684 # Try cpufreq-info 

2685 _copy_new_fields(info, _get_cpu_info_from_cpufreq_info()) 

2686 

2687 # Try LSCPU 

2688 _copy_new_fields(info, _get_cpu_info_from_lscpu()) 

2689 

2690 # Try sysctl 

2691 _copy_new_fields(info, _get_cpu_info_from_sysctl()) 

2692 

2693 # Try kstat 

2694 _copy_new_fields(info, _get_cpu_info_from_kstat()) 

2695 

2696 # Try dmesg 

2697 _copy_new_fields(info, _get_cpu_info_from_dmesg()) 

2698 

2699 # Try /var/run/dmesg.boot 

2700 _copy_new_fields(info, _get_cpu_info_from_cat_var_run_dmesg_boot()) 

2701 

2702 # Try lsprop ibm,pa-features 

2703 _copy_new_fields(info, _get_cpu_info_from_ibm_pa_features()) 

2704 

2705 # Try sysinfo 

2706 _copy_new_fields(info, _get_cpu_info_from_sysinfo()) 

2707 

2708 # Try querying the CPU cpuid register 

2709 # FIXME: This should print stdout and stderr to trace log 

2710 _copy_new_fields(info, _get_cpu_info_from_cpuid()) 

2711 

2712 # Try platform.uname 

2713 _copy_new_fields(info, _get_cpu_info_from_platform_uname()) 

2714 

2715 g_trace.write('!' * 80) 

2716 

2717 return info 

2718 

2719def get_cpu_info_json(): 

2720 ''' 

2721 Returns the CPU info by using the best sources of information for your OS. 

2722 Returns the result in a json string 

2723 ''' 

2724 

2725 import json 

2726 

2727 output = None 

2728 

2729 # If running under pyinstaller, run normally 

2730 if getattr(sys, 'frozen', False): 

2731 info = _get_cpu_info_internal() 

2732 output = json.dumps(info) 

2733 output = "{0}".format(output) 

2734 # if not running under pyinstaller, run in another process. 

2735 # This is done because multiprocesing has a design flaw that 

2736 # causes non main programs to run multiple times on Windows. 

2737 else: 

2738 from subprocess import Popen, PIPE 

2739 

2740 command = [sys.executable, __file__, '--json'] 

2741 p1 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE) 

2742 output = p1.communicate()[0] 

2743 

2744 if p1.returncode != 0: 

2745 return "{}" 

2746 

2747 output = output.decode(encoding='UTF-8') 

2748 

2749 return output 

2750 

2751def get_cpu_info(): 

2752 ''' 

2753 Returns the CPU info by using the best sources of information for your OS. 

2754 Returns the result in a dict 

2755 ''' 

2756 

2757 import json 

2758 

2759 output = get_cpu_info_json() 

2760 

2761 # Convert JSON to Python with non unicode strings 

2762 output = json.loads(output, object_hook = _utf_to_str) 

2763 

2764 return output 

2765 

2766def main(): 

2767 from argparse import ArgumentParser 

2768 import json 

2769 

2770 # Parse args 

2771 parser = ArgumentParser(description='Gets CPU info with pure Python') 

2772 parser.add_argument('--json', action='store_true', help='Return the info in JSON format') 

2773 parser.add_argument('--version', action='store_true', help='Return the version of py-cpuinfo') 

2774 parser.add_argument('--trace', action='store_true', help='Traces code paths used to find CPU info to file') 

2775 args = parser.parse_args() 

2776 

2777 global g_trace 

2778 g_trace = Trace(args.trace, False) 

2779 

2780 try: 

2781 _check_arch() 

2782 except Exception as err: 

2783 sys.stderr.write(str(err) + "\n") 

2784 sys.exit(1) 

2785 

2786 info = _get_cpu_info_internal() 

2787 

2788 if not info: 

2789 sys.stderr.write("Failed to find cpu info\n") 

2790 sys.exit(1) 

2791 

2792 if args.json: 

2793 print(json.dumps(info)) 

2794 elif args.version: 

2795 print(CPUINFO_VERSION_STRING) 

2796 else: 

2797 print('Python Version: {0}'.format(info.get('python_version', ''))) 

2798 print('Cpuinfo Version: {0}'.format(info.get('cpuinfo_version_string', ''))) 

2799 print('Vendor ID Raw: {0}'.format(info.get('vendor_id_raw', ''))) 

2800 print('Hardware Raw: {0}'.format(info.get('hardware_raw', ''))) 

2801 print('Brand Raw: {0}'.format(info.get('brand_raw', ''))) 

2802 print('Hz Advertised Friendly: {0}'.format(info.get('hz_advertised_friendly', ''))) 

2803 print('Hz Actual Friendly: {0}'.format(info.get('hz_actual_friendly', ''))) 

2804 print('Hz Advertised: {0}'.format(info.get('hz_advertised', ''))) 

2805 print('Hz Actual: {0}'.format(info.get('hz_actual', ''))) 

2806 print('Arch: {0}'.format(info.get('arch', ''))) 

2807 print('Bits: {0}'.format(info.get('bits', ''))) 

2808 print('Count: {0}'.format(info.get('count', ''))) 

2809 print('Arch String Raw: {0}'.format(info.get('arch_string_raw', ''))) 

2810 print('L1 Data Cache Size: {0}'.format(info.get('l1_data_cache_size', ''))) 

2811 print('L1 Instruction Cache Size: {0}'.format(info.get('l1_instruction_cache_size', ''))) 

2812 print('L2 Cache Size: {0}'.format(info.get('l2_cache_size', ''))) 

2813 print('L2 Cache Line Size: {0}'.format(info.get('l2_cache_line_size', ''))) 

2814 print('L2 Cache Associativity: {0}'.format(info.get('l2_cache_associativity', ''))) 

2815 print('L3 Cache Size: {0}'.format(info.get('l3_cache_size', ''))) 

2816 print('Stepping: {0}'.format(info.get('stepping', ''))) 

2817 print('Model: {0}'.format(info.get('model', ''))) 

2818 print('Family: {0}'.format(info.get('family', ''))) 

2819 print('Processor Type: {0}'.format(info.get('processor_type', ''))) 

2820 print('Flags: {0}'.format(', '.join(info.get('flags', '')))) 

2821 

2822 

2823if __name__ == '__main__': 

2824 main() 

2825else: 

2826 g_trace = Trace(False, False) 

2827 _check_arch()