This patch adds RISC-V support that was merged upstream after 8.0.0. It includes changes from the following commits: * 220d5b0 Fixed issue with byte format list out of order in python 2 [matthew.brennan.jones@gmail.com] * 4b98eb2 Made new riscv tests run with test suite [matthew.brennan.jones@gmail.com] * 25c0ed9 Merge pull request #167 from felixonmars/riscv [matthew.brennan.jones@gmail.com] * 657b367 Add support for RISC-V [felixonmars@archlinux.org] diff --git a/README.md b/README.md index 264203c..e3d34af 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Fields | "hz_actual_friendly" | "1.7330 GHz" | string | | "hz_advertised" | (2930000000, 0) | (int, int) | | "hz_actual" | (1733000000, 0) | (int, int) | -| "arch" | "X86_64" | "X86_32", "X86_64", "ARM_8", "ARM_7", "PPC_32", "PPC_64", "SPARC_32", "SPARC_64", "S390X", "MIPS_32", "MIPS_64" | +| "arch" | "X86_64" | "X86_32", "X86_64", "ARM_8", "ARM_7", "PPC_32", "PPC_64", "SPARC_32", "SPARC_64", "S390X", "MIPS_32", "MIPS_64", "RISCV_32", "RISCV_64" | | "bits" | 64 | int | | "count" | 4 | int | | "l1_data_cache_size" | 32768 | int | @@ -152,7 +152,7 @@ OS Support CPU Support ----- * X86 32bit and 64bit -* Some ARM, PPC, S390X and MIPS CPUs +* Some ARM, PPC, S390X, MIPS and RISCV CPUs These approaches are used for getting info: diff --git a/cpuinfo/cpuinfo.py b/cpuinfo/cpuinfo.py index 3a2752d..3757d6e 100644 --- a/cpuinfo/cpuinfo.py +++ b/cpuinfo/cpuinfo.py @@ -370,9 +370,10 @@ def _read_windows_registry_key(key_name, field_name): def _check_arch(): arch, bits = _parse_arch(DataSource.arch_string_raw) if not arch in ['X86_32', 'X86_64', 'ARM_7', 'ARM_8', - 'PPC_64', 'S390X', 'MIPS_32', 'MIPS_64']: + 'PPC_64', 'S390X', 'MIPS_32', 'MIPS_64', + "RISCV_32", "RISCV_64"]: raise Exception("py-cpuinfo currently only works on X86 " - "and some ARM/PPC/S390X/MIPS CPUs.") + "and some ARM/PPC/S390X/MIPS/RISCV CPUs.") def _obj_to_b64(thing): import pickle @@ -589,19 +590,25 @@ def _to_friendly_bytes(input): def _friendly_bytes_to_int(friendly_bytes): input = friendly_bytes.lower() - formats = { - 'gb' : 1024 * 1024 * 1024, - 'mb' : 1024 * 1024, - 'kb' : 1024, - - 'g' : 1024 * 1024 * 1024, - 'm' : 1024 * 1024, - 'k' : 1024, - 'b' : 1, - } + formats = [ + {'gib' : 1024 * 1024 * 1024}, + {'mib' : 1024 * 1024}, + {'kib' : 1024}, + + {'gb' : 1024 * 1024 * 1024}, + {'mb' : 1024 * 1024}, + {'kb' : 1024}, + + {'g' : 1024 * 1024 * 1024}, + {'m' : 1024 * 1024}, + {'k' : 1024}, + {'b' : 1}, + ] try: - for pattern, multiplier in formats.items(): + for entry in formats: + pattern = list(entry.keys())[0] + multiplier = list(entry.values())[0] if input.endswith(pattern): return int(input.split(pattern)[0].strip()) * multiplier @@ -827,6 +834,13 @@ def _parse_arch(arch_string_raw): elif arch_string_raw == 'mips64': arch = 'MIPS_64' bits = 64 + # RISCV + elif re.match(r'^riscv$|^riscv32$|^riscv32be$', arch_string_raw): + arch = 'RISCV_32' + bits = 32 + elif re.match(r'^riscv64$|^riscv64be$', arch_string_raw): + arch = 'RISCV_64' + bits = 64 return (arch, bits) @@ -1710,7 +1724,7 @@ def _get_cpu_info_from_proc_cpuinfo(): # Various fields vendor_id = _get_field(False, output, None, '', 'vendor_id', 'vendor id', 'vendor') - processor_brand = _get_field(True, output, None, None, 'model name','cpu', 'processor') + 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') diff --git a/test_suite.py b/test_suite.py index 4c61ae2..6ba1f56 100644 --- a/test_suite.py +++ b/test_suite.py @@ -58,6 +58,7 @@ from test_linux_odroid_c2_aarch64 import TestLinux_Odroid_C2_Aarch_64 from test_linux_odroid_xu3_arm_32 import TestLinux_Odroid_XU3_arm_32 from test_linux_alt_p9_mipsel_bfk3 import TestLinuxAlt_p9_mipsel_bfk3 from test_linux_mips64el_loongson3A3000 import TestLinux_mips64el_Loongson3A3000 +from test_linux_ubuntu_21_04_riscv64 import TestLinuxUbuntu_21_04_riscv64 from test_pcbsd_10_x86_64 import TestPCBSD from test_free_bsd_11_x86_64 import TestFreeBSD_11_X86_64 from test_osx_10_9_x86_64 import TestOSX_10_9 @@ -106,6 +107,7 @@ if __name__ == '__main__': TestLinux_RaspberryPiModelB, TestLinux_Odroid_C2_Aarch_64, TestLinux_Odroid_XU3_arm_32, + TestLinuxUbuntu_21_04_riscv64, TestFreeBSD_11_X86_64, TestPCBSD, TestOSX_10_9, diff --git a/tests/test_invalid_cpu.py b/tests/test_invalid_cpu.py index 1931ecf..d4e75a0 100644 --- a/tests/test_invalid_cpu.py +++ b/tests/test_invalid_cpu.py @@ -33,4 +33,4 @@ class TestInvalidCPU(unittest.TestCase): cpuinfo._check_arch() self.fail('Failed to raise Exception') except Exception as err: - self.assertEqual('py-cpuinfo currently only works on X86 and some ARM/PPC/S390X/MIPS CPUs.', err.args[0]) + self.assertEqual('py-cpuinfo currently only works on X86 and some ARM/PPC/S390X/MIPS/RISCV CPUs.', err.args[0]) diff --git a/tests/test_linux_ubuntu_21_04_riscv64.py b/tests/test_linux_ubuntu_21_04_riscv64.py new file mode 100644 index 0000000..d58cc4a --- /dev/null +++ b/tests/test_linux_ubuntu_21_04_riscv64.py @@ -0,0 +1,139 @@ + + +import unittest +from cpuinfo import * +import helpers + + +class MockDataSource(object): + bits = '64bit' + cpu_count = 4 + is_windows = False + arch_string_raw = 'riscv64' + uname_string_raw = 'riscv64' + can_cpuid = False + + @staticmethod + def has_proc_cpuinfo(): + return True + + @staticmethod + def has_dmesg(): + return True + + @staticmethod + def has_lscpu(): + return True + + @staticmethod + def has_ibm_pa_features(): + return False + + @staticmethod + def cat_proc_cpuinfo(): + returncode = 0 + output = r''' +processor : 0 +hart : 2 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,u74-mc + +processor : 1 +hart : 1 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,u74-mc + +processor : 2 +hart : 3 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,u74-mc + +processor : 3 +hart : 4 +isa : rv64imafdc +mmu : sv39 +uarch : sifive,u74-mc + +''' + return returncode, output + + @staticmethod + def dmesg_a(): + returncode = 1 + output = r''' +dmesg: read kernel buffer failed: Operation not permitted + +''' + return returncode, output + + @staticmethod + def lscpu(): + returncode = 0 + output = r''' +Architecture: riscv64 +Byte Order: Little Endian +CPU(s): 4 +On-line CPU(s) list: 0-3 +Thread(s) per core: 4 +Core(s) per socket: 1 +Socket(s): 1 +L1d cache: 32 KiB +L1i cache: 32 KiB +L2 cache: 2 MiB + + +''' + return returncode, output + + +class TestLinuxUbuntu_21_04_riscv64(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) + + ''' + Make sure calls return the expected number of fields. + ''' + def test_returns(self): + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_registry())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_cpufreq_info())) + self.assertEqual(3, len(cpuinfo._get_cpu_info_from_lscpu())) + self.assertEqual(1, len(cpuinfo._get_cpu_info_from_proc_cpuinfo())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_sysctl())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_kstat())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_dmesg())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_cat_var_run_dmesg_boot())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_ibm_pa_features())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_sysinfo())) + self.assertEqual(0, len(cpuinfo._get_cpu_info_from_cpuid())) + self.assertEqual(11, len(cpuinfo._get_cpu_info_internal())) + + def test_get_cpu_info_from_lscpu(self): + info = cpuinfo._get_cpu_info_from_lscpu() + self.assertEqual(32 * 1024, info['l1_instruction_cache_size']) + self.assertEqual(32 * 1024, info['l1_data_cache_size']) + self.assertEqual(2 * 1024 * 1024, info['l2_cache_size']) + self.assertEqual(3, len(info)) + + def test_get_cpu_info_from_proc_cpuinfo(self): + info = cpuinfo._get_cpu_info_from_proc_cpuinfo() + self.assertEqual('sifive,u74-mc', info['brand_raw']) + self.assertEqual(1, len(info)) + + def test_all(self): + info = cpuinfo._get_cpu_info_internal() + + self.assertEqual('sifive,u74-mc', info['brand_raw']) + self.assertEqual('RISCV_64', info['arch']) + self.assertEqual(64, info['bits']) + self.assertEqual(4, info['count']) + self.assertEqual(32 * 1024, info['l1_instruction_cache_size']) + self.assertEqual(32 * 1024, info['l1_data_cache_size']) + self.assertEqual(2 * 1024 * 1024, info['l2_cache_size']) + self.assertEqual('riscv64', info['arch_string_raw']) diff --git a/tools/get_system_info.py b/tools/get_system_info.py index f508f68..9110616 100644 --- a/tools/get_system_info.py +++ b/tools/get_system_info.py @@ -157,6 +157,13 @@ def parse_arch(arch_string_raw): elif re.match(r'^s390x$', arch_string_raw): arch = 'S390X' bits = 64 + # RISCV + elif re.match(r'^riscv$|^riscv32$|^riscv32be$', arch_string_raw): + arch = 'RISCV_32' + bits = 32 + elif re.match(r'^riscv64$|^riscv64be$', arch_string_raw): + arch = 'RISCV_64' + bits = 64 return (arch, bits)