Skip to content

Commit

Permalink
Fixed Bug #152: CPU stepping, model, and family values are blank if 0
Browse files Browse the repository at this point in the history
  • Loading branch information
workhorsy committed Sep 6, 2022
1 parent 635811d commit 21e4f3b
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 14 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
* Release 8.1.0
* Fixed Bug #152: CPU stepping, model, and family values are blank if 0
* Fixed Bug #177: Officially drop support for Python 2
* Fixed Bug #171: Replace Python 3.11 deprecated unittest.makeSuite
* Fixed Bug #173: Fix lgtm.com alerts
Expand Down
44 changes: 31 additions & 13 deletions cpuinfo/cpuinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,18 +874,36 @@ def _is_selinux_enforcing(trace):

return (not can_selinux_exec_heap or not can_selinux_exec_memory)

def _filter_dict_keys_with_empty_values(info):
# Filter out None, 0, "", (), {}, []
info = {k: v for k, v in info.items() if v}
def _filter_dict_keys_with_empty_values(info, acceptable_values = {}):
filtered_info = {}
for key in info:
value = info[key]

# Filter out (0, 0)
info = {k: v for k, v in info.items() if v != (0, 0)}
# Keep if value is acceptable
if key in acceptable_values:
if acceptable_values[key] == value:
filtered_info[key] = value
continue

# Filter out strings that start with "0.0"
info = {k: v for k, v in info.items() if not (type(v) == str and v.startswith('0.0'))}
# Filter out None, 0, "", (), {}, []
if not value:
continue

return info
# Filter out (0, 0)
if value == (0, 0):
continue

# Filter out -1
if value == -1:
continue

# Filter out strings that start with "0.0"
if type(value) == str and value.startswith('0.0'):
continue

filtered_info[key] = value

return filtered_info

class ASM(object):
def __init__(self, restype=None, argtypes=(), machine_code=[]):
Expand Down Expand Up @@ -1710,9 +1728,9 @@ def _get_cpu_info_from_proc_cpuinfo():
vendor_id = _get_field(False, output, None, '', 'vendor_id', 'vendor id', 'vendor')
processor_brand = _get_field(True, output, None, None, 'model name', 'cpu', 'processor', 'uarch')
cache_size = _get_field(False, output, None, '', 'cache size')
stepping = _get_field(False, output, int, 0, 'stepping')
model = _get_field(False, output, int, 0, 'model')
family = _get_field(False, output, int, 0, 'cpu family')
stepping = _get_field(False, output, int, -1, 'stepping')
model = _get_field(False, output, int, -1, 'model')
family = _get_field(False, output, int, -1, 'cpu family')
hardware = _get_field(False, output, None, '', 'Hardware')

# Flags
Expand Down Expand Up @@ -1775,7 +1793,7 @@ def _get_cpu_info_from_proc_cpuinfo():
info['hz_actual_friendly'] = _hz_short_to_friendly(hz_actual, 6)
info['hz_actual'] = _hz_short_to_full(hz_actual, 6)

info = _filter_dict_keys_with_empty_values(info)
info = _filter_dict_keys_with_empty_values(info, {'stepping':0, 'model':0, 'family':0})
g_trace.success()
return info
except Exception as err:
Expand Down Expand Up @@ -1915,7 +1933,7 @@ def _get_cpu_info_from_lscpu():
flags.sort()
info['flags'] = flags

info = _filter_dict_keys_with_empty_values(info)
info = _filter_dict_keys_with_empty_values(info, {'stepping':0, 'model':0, 'family':0})
g_trace.success()
return info
except Exception as err:
Expand Down
6 changes: 5 additions & 1 deletion test_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
from test_cpuid import TestCPUID
from test_actual import TestActual
from test_cli import TestCLI
from test_bug_152_cpu_zero import TestBug152
from test_filter import TestFilter

if __name__ == '__main__':
def logger(msg):
Expand Down Expand Up @@ -123,7 +125,9 @@ def logger(msg):
TestWindows_10_X86_64_Ryzen7,
TestCPUID,
TestActual,
TestCLI
TestCLI,
TestBug152,
TestFilter,
]

# Add the tests to the suite
Expand Down
126 changes: 126 additions & 0 deletions tests/test_bug_152_cpu_zero.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@


import unittest
from cpuinfo import *
import helpers


class MockDataSource(object):
bits = '64bit'
cpu_count = 1
is_windows = False
arch_string_raw = 'x86_64'
uname_string_raw = 'x86_64'
can_cpuid = False

@staticmethod
def has_proc_cpuinfo():
return True

@staticmethod
def has_lscpu():
return True

@staticmethod
def cat_proc_cpuinfo():
returncode = 0
output = r'''
processor : 0
vendor_id : GenuineIntel
cpu family : 0
model : 0
model name : Intel(R) Pentium(R) CPU G640 @ 2.80GHz
stepping : 0
microcode : 0x29
cpu MHz : 1901.375
cache size : 3072 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 popcnt tsc_deadline_timer xsave lahf_lm epb tpr_shadow vnmi flexpriority ept vpid xsaveopt dtherm arat pln pts
bugs :
bogomips : 5587.32
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
'''
return returncode, output

@staticmethod
def lscpu():
returncode = 0
output = r'''
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 2
On-line CPU(s) list: 0,1
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 0
Model: 0
Model name: Intel(R) Pentium(R) CPU G640 @ 2.80GHz
Stepping: 0
CPU MHz: 2070.796
CPU max MHz: 2800.0000
CPU min MHz: 1600.0000
BogoMIPS: 5587.32
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 3072K
NUMA node0 CPU(s): 0,1
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 popcnt tsc_deadline_timer xsave lahf_lm epb tpr_shadow vnmi flexpriority ept vpid xsaveopt dtherm arat pln pts
'''
return returncode, output

# Confirms fix for: https://github.com/workhorsy/py-cpuinfo/issues/152
# CPU stepping, model, and family values are blank if 0
class TestBug152(unittest.TestCase):
def setUp(self):
helpers.backup_data_source(cpuinfo)
helpers.monkey_patch_data_source(cpuinfo, MockDataSource)

def tearDown(self):
helpers.restore_data_source(cpuinfo)

def test_get_cpu_info_from_lscpu(self):
info = cpuinfo._get_cpu_info_from_lscpu()

# Make sure fields with 0 are not filtered out
self.assertIn('stepping', info.keys())
self.assertIn('model', info.keys())
self.assertIn('family', info.keys())

self.assertEqual(0, info['stepping'])
self.assertEqual(0, info['model'])
self.assertEqual(0, info['family'])

def test_get_cpu_info_from_proc_cpuinfo(self):
info = cpuinfo._get_cpu_info_from_proc_cpuinfo()

# Make sure fields with 0 are not filtered out
self.assertIn('stepping', info.keys())
self.assertIn('model', info.keys())
self.assertIn('family', info.keys())

self.assertEqual(0, info['stepping'])
self.assertEqual(0, info['model'])
self.assertEqual(0, info['family'])

30 changes: 30 additions & 0 deletions tests/test_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@


import unittest
from cpuinfo import *
import helpers


class TestFilter(unittest.TestCase):
def test_filter(self):
# Make sure NON empty values DON'T get filtered out
for x in [2, "abc", ("one"), {"key" : "val"}, [9, 8, 7]]:
info = { 'example' : x }
info = cpuinfo._filter_dict_keys_with_empty_values(info)
self.assertEqual(info, { 'example' : x })

# Make sure empty values get filtered out
for x in [None, 0, -1, "", (), {}, [], (0, 0), "0.0"]:
info = { 'example' : x }
info = cpuinfo._filter_dict_keys_with_empty_values(info)
self.assertEqual(info, {})

# Make sure 0 values get filtered out
info = { 'aaa':1, 'bbb':0, 'ccc':2 }
info = cpuinfo._filter_dict_keys_with_empty_values(info)
self.assertEqual(info, { 'aaa':1, 'ccc':2 })

# Make sure 0 values dont get filtered out with 0 as acceptable value
info = { 'aaa':1, 'bbb':0, 'ccc':2 }
info = cpuinfo._filter_dict_keys_with_empty_values(info, { 'bbb' : 0 })
self.assertEqual(info, { 'aaa':1, 'bbb':0, 'ccc':2 })

0 comments on commit 21e4f3b

Please sign in to comment.