Compare commits

...

236 Commits
v1.00 ... i277

Author SHA1 Message Date
Dr-Noob
11e186e65b [v1.06][X86] Add Zen5 uarch 2024-09-05 08:33:02 +01:00
Dr-Noob
eb8fad2843 [v1.06][ARM] Simplify is_ARMv8_or_newer 2024-09-02 08:27:58 +01:00
Dr-Noob
bd38951439 [v1.06][ARM] Update get_vpus_width to match SVE detection 2024-09-02 08:26:58 +01:00
Dr-Noob
057a36efd5 [v1.06][ARM] Add new microarchitectures 2024-09-02 08:20:40 +01:00
Dr-Noob
56901d70ab [v1.06][ARM] Add more NXP SoCs 2024-08-31 18:40:35 +01:00
Dr-Noob
5bd507e4b6 [v1.06][ARM] Add support for Amlogic A311D (#268) 2024-08-31 09:37:50 +01:00
Dr-Noob
9192ba3eb8 [v1.06][ARM] Add (another) cpufamily for M3 and set the ARM version, fixing peak performance wrong result (#230) 2024-08-29 08:13:05 +01:00
Dr-Noob
807a13d29e [v1.06] Fix manpage file extension (fixes #269) 2024-08-28 21:33:48 +01:00
Dr-Noob
15a803dae5 [v1.06][ARM] Check if HWCAP2_SVE2 is defined before using it (fixes #270) 2024-08-28 21:26:27 +01:00
Dr-Noob
0507355372 [v1.06][X86] Bugfix: set affinity in --accurate-pp
There are cases where measure_frequency is called after binding the
process to a specific core via bind_to_cpu (e.g., when iterating over
modules in hybrid architectures). Thus, in measure_frequency we must
set the affinity of the newly created threads, ensuring they are
binded to the right core.
2024-08-26 12:31:18 +01:00
Dr-Noob
9f66a137c5 [v1.06][ARM] Add support for NXP i.MX 8M Plus (#261) 2024-08-25 17:44:29 +01:00
Dr-Noob
324d0fbe94 [v1.06][PPC] Add support for Espresso (#231) 2024-08-25 16:50:58 +01:00
Dr-Noob
af8bb16302 [v1.06][ARM] Fix for commit 025e28c 2024-08-24 15:44:06 +01:00
Dr-Noob
40374121b8 [v1.06] Replace emalloc+memset with ecalloc when possible. Refactor some memory allocation code 2024-08-24 15:32:33 +01:00
Dr-Noob
025e28c516 [v1.06][ARM] Set Android properties as defines 2024-08-24 14:47:34 +01:00
Dr-Noob
7ad19d113c [v1.06] Remove soc_ prefix from field names in system_on_chip struct 2024-08-24 12:44:24 +01:00
Dr-Noob
13605ed0ce [v1.06][ARM] Remove BCM prefix from Broadcom vendor string 2024-08-24 12:34:57 +01:00
Dr-Noob
7689355a72 [v1.06][ARM] Add support for Apple SoCs in Asahi Linux (#263) 2024-08-23 08:37:13 +01:00
Timothy Warren
321a1ec375 [v1.06][X86] Add old Intel and AMD CPUs (#260)
* Add Intel and AMD 486, Intel Pentium Pro, and AMD K5 chips
* Update infer_cpu_name_from_uarch to support added CPU uarches
* Add sources for more of the legacy chip data
* Add the more specific codename for Intel Pentium MMX Mobile chips
* Document source of AMD 486/K5 variants
* Add link to documentation for Intel 486

---------

Co-authored-by: Timothy Warren <tim@timshomepage.net>
2024-08-20 09:25:01 +02:00
Dr-Noob
48c598cf3b [v1.06][ARM] Add support for Ampere Altra (#262) 2024-08-19 08:46:07 +01:00
Dr-Noob
aa94389bbe [v1.06][ARM] Fix two off-by-one bugs (#264) 2024-08-19 08:39:52 +01:00
Er2
8d10a03adc [v1.06][FreeBSD][Apple] Implement fallback frequency calculation (#251) 2024-08-19 09:21:41 +02:00
Dr-Noob
2410fd16d3 [v1.06] Bump version 2024-08-18 15:12:27 +01:00
Dr-Noob
f63178b41c [v1.05][ARM] Fix compile warning in SVE cntb 2024-08-10 11:23:13 +01:00
Dr-Noob
2788e6831e [v1.05][ARM] Fix SVE cntb datatype 2024-08-10 11:16:22 +01:00
Dr-Noob
146f2a13aa [v1.05][ARM] Show SVE cntb in debug 2024-08-10 11:11:46 +01:00
Dr-Noob
90624b9aaa [v1.05][ARM] Preeliminary support for SVE detection (#259) 2024-08-10 11:08:39 +01:00
Dr-Noob
e42f04cca8 [v1.05][ARM] Add support for Kirin 9000S and TSV120 (#259) 2024-08-10 11:03:22 +01:00
Dr-Noob
3aacaf5f9e [v1.05] Add RISC-V picture to README (thanks #241!) 2024-08-03 16:31:56 +01:00
Dr-Noob
50f66ec571 [v1.05][X86] Fix compilation issue in clang and fallback to get_topology_from_udev also in AMD 2024-08-03 15:45:10 +01:00
Dr-Noob
cb186a2f97 [v1.05][X86] Do not show empty SSE if not supported (#260) 2024-08-02 10:09:51 +01:00
Dr-Noob
6164884415 [v1.05][ARM] Add latest Snapdragon SoCs (closes #256) 2024-08-02 08:07:47 +01:00
Dr-Noob
260f9ec3b8 [v1.05] Add new contributor to acknowledgements 2024-07-25 08:29:05 +01:00
Dr-Noob
79013d0ec9 [v1.05][X86] Improve robustness in case of old CPUs (verified by #220)
- Use udev to get topo when apic failed or is not available.
- Assume single core in udev when total cores is 1.
- Print core/cores accordingly to the number of cores.
2024-07-25 08:23:56 +01:00
Dr-Noob
e4227388b9 [v1.05][ARM] Add new SnapD SoCs and use ro.soc.mode in Android to improve SoC detection (#253) 2024-07-19 08:21:11 +01:00
Dr-Noob
8fca4cb250 [v1.05][X86] Fix frequency fetching from udev and measurement in hybrid architectures 2024-07-11 22:27:42 +01:00
Dr-Noob
7c947bdf64 [v1.05] Use UNKNOWN_DATA instead of -1 in frequency measurement 2024-07-11 22:10:00 +01:00
Dr-Noob
1ed3a0f2bf [v1.05] Adapt frequency measurement iterations depending on CPU speed
This is achieved by running a first measurement which gets a taste of
CPU speed, then estimate a reasonable value for the iterations of the
real measurement and then running the actual measurement. This is very
helpful to reduce the runtime of the measurement, especially for slow
CPUs
2024-07-11 21:55:01 +01:00
Dr-Noob
0fe6fc3f4d [v1.05][ARM] Fix mistake in Makefile 2024-07-11 08:17:26 +01:00
Dr-Noob
96c784026b [v1.05] Fix formatting issues in Makefile 2024-07-09 08:47:34 +01:00
Dr-Noob
59cd2dd128 [v1.05][X86] Add support for Hygon CPUs (#244) 2024-07-09 08:34:44 +01:00
Dr-Noob
da1981b97c [v1.05] Check read return value in frequency measurement 2024-07-09 08:32:24 +01:00
Dr-Noob
8506c91e00 [v1.05] Add --measure-max-freq (available on x86 and ARM) 2024-07-08 09:07:57 +01:00
Dr-Noob
ece28cbdee [v1.05] Small fix in help message 2024-07-08 08:31:00 +01:00
Dr-Noob
7b46c78249 [v1.05] Replace printf with proper printErr 2024-07-08 08:28:48 +01:00
Dr-Noob
e0095c303d [v1.05] Print a tilde in case the freq was measured (indicating that this value is an approximation) 2024-07-08 08:23:56 +01:00
Dr-Noob
65378aaed9 [v1.05] Move sysctl from ARM-specific to common (#251) 2024-07-07 12:43:03 +01:00
Dr-Noob
946729dd06 [v1.05] Compile measure freq only in Linux (avoids compiler warning in non-linux builds) 2024-07-06 11:28:46 +01:00
Dr-Noob
9212f19de1 [v1.05] Add support for frequency measurement (both x86 and ARM) (branch measure-freq #220) 2024-07-05 08:44:34 +01:00
Dr-Noob
b019256515 [v1.05] Continue merging measure-freq #220
- [v1.05][X86] Show SSE if AVX/FMA is not supported
- [v1.05][X86] Do not stop if cach is NULL and check for non-NULL cache in get_topology_info functions
- [v1.05][X86] Fix bug where the number of cpus were not set if NULL was returned inside the loop. Ensure topo is not NULL in get_peak_performance. Fallback to UNKNOWN_DATA when we have no information about topology
2024-07-05 08:37:54 +01:00
Dr-Noob
d4cadbd807 [v1.05] Move bind_to_cpu from x86-specific to global (merging measure-freq #220) 2024-07-05 08:32:11 +01:00
Dr-Noob
4f081ef1a2 [v1.05] Add newline to fix dummy warning with clang 2024-07-03 09:09:37 +02:00
Dr-Noob
1b746bc67d [v1.05][ARM] Add support to detect SoC from PCI (#245) with initial support for NVIDIA Tegra 2024-07-03 08:01:53 +01:00
Dr-Noob
dfa2b773d1 [v1.05][X86] Add new Zen4 uarch (#237) 2024-05-18 22:36:23 +01:00
Dr-Noob
59efbf4e08 [v1.05] Add VirtualBox hypervisor (noted in #235) 2024-05-18 22:27:17 +01:00
Dr-Noob
29768e841d [v1.05][ARM] Update TaiShan vector units 2024-02-20 09:35:30 +01:00
Dr-Noob
cc16bc56ef [v1.05][X86] Improve support for old x86 CPUs (#220) by improving Pentium uarch detection and adding support to infer the CPU name from uarch when the corresponding CPUID level is not available 2024-02-13 21:29:08 +00:00
Dr-Noob
1504c5d0ef [v1.05][X86] Report x86 / x86_64 in ARCH_X86 builds 2024-02-13 21:26:24 +00:00
Dr-Noob
08919916dc [v1.05] Always print manufacturing process in nanometers (this indirectly fixes a bug of processes in micrometers being incorrectly reported by 10x 2024-02-13 21:24:16 +00:00
Dr-Noob
4a8a7567f0 [v1.05] Add support for NO_COLOR (#227) 2024-02-13 08:41:54 +00:00
Dr-Noob
c01f60fa6c [v1.05] Implement new approach to infer SoC from the uarch. Add support for Kunpeng SoCs 2024-02-08 09:04:51 +00:00
Dr-Noob
b610dc8c7d [v1.05] Bump version 2024-02-05 18:33:15 +00:00
Dr-Noob
0967e3597b [v1.04] Fix error in previous commit 2024-02-05 09:48:46 +01:00
Dr-Noob
14df701707 [v1.04] Check release when printing error also in Apple chip failures 2024-02-05 08:46:17 +00:00
Dr-Noob
cbcce9c2ed [v1.04] Improve error reporting in the case of unkown microarchitectures. As pointed out in #224 this was already solved, but this commit tries to be an improvement over the previous implementation 2024-02-05 08:37:59 +00:00
Dr-Noob
b072e5c331 [v1.04] Update acknowledgements 2024-02-01 22:40:58 +00:00
Dr-Noob
4b42d2c89d [v1.04][ARM] Extend Allwinner SoC list (#207) 2024-02-01 23:26:23 +01:00
Dr-Noob
d221f578b7 [v1.04][ARM] Use sysctl to fetch topology in Apple SoCs 2024-01-25 09:33:22 +01:00
Dr-Noob
7b4b94bb93 [v1.04] Fix typo in Rockchip SoC detection 2024-01-22 07:18:15 +00:00
Dr-Noob
5e00d554aa [v1.04][ARM] Fix number of cores per cluster in M2 and M3 SoCs (#183) 2024-01-17 08:48:58 +00:00
Dr-Noob
5ffac60622 [v1.04][ARM] Support for reverse ordering in Rockchip SoCs 2024-01-17 09:37:15 +01:00
Dr-Noob
6566ac3ccf [v1.04] Add Apple VZ hypervisor (#218) 2024-01-15 08:43:28 +00:00
Dr-Noob
0a048717bf [v1.04][X86] Fix bug in AMD CPUs (#212) 2023-12-24 23:03:20 +00:00
Dr-Noob
ce6e6f9cd8 [v1.04][ARM] Preeliminary M3 support 2023-12-24 22:42:01 +00:00
Dr-Noob
2feee25659 [v1.04] Clarify how the unknown microarchitectures should be reported 2023-12-03 20:23:15 +00:00
Dr-Noob
8335bd004d [v1.04][X86] Add AMD uarchs 2023-12-02 18:18:43 +00:00
Dr-Noob
a172b4b281 [v1.04][ARM] Add more Mediatek SoCs 2023-11-18 20:25:57 +01:00
Dr-Noob
d88a6bf763 [v1.04][X86] Fixed bhyve matcher (#193) 2023-11-11 09:36:12 +00:00
Dr-Noob
8870a0ca0c [v1.04][RISCV] Add Sipeed ASCII logo 2023-11-01 20:50:05 +00:00
Dr-Noob
a43b700540 [v1.04][RISCV] Add Lichee PI 4a SoC (#200) 2023-11-01 20:48:25 +00:00
Dr-Noob
9a578d3670 [v1.04][RISCV] Make single-letter extension detection more robust. s and u are invalid but might appear (#200), so just skip them 2023-10-29 17:14:47 +00:00
Dr-Noob
bf890965a3 [v1.04] Add colors to Google logo 2023-10-17 09:19:05 +02:00
Dr-Noob
530207aee0 [v1.04] Added Google ascii logo 2023-10-17 08:56:20 +02:00
Dr-Noob
f64ff0d4cf [v1.04] Added Google Tensor SoCs 2023-10-17 08:55:38 +02:00
Dr-Noob
4b7600d49e [v1.04][ARM] Add Cortex-A715/X3 uarchs 2023-10-16 09:04:59 +02:00
Dr-Noob
d8ce2de287 [v1.04] Testing bhyve matcher 2023-10-03 21:00:43 +01:00
Dr-Noob
bc9b9c1e99 [1.04][ARM] Add support for Raspberry Pi 5 2023-10-01 11:56:36 +02:00
Dr-Noob
b17df01958 [1.04][ARM] Improve robustness in Raspberry Pi detection 2023-10-01 11:49:20 +02:00
Dr-Noob
44e5e1b6dc [v1.04][RISCV] Add support for multi-letter extensions 2023-09-25 07:27:13 +01:00
Dr-Noob
fe4bcde898 [v1.04][X86] Added new uarchs 2023-09-24 12:58:56 +01:00
Dr-Noob
45854a00d6 [v1.04] Add bhyve hypervisor 2023-09-24 12:10:39 +01:00
Dr-Noob
6c69ab0a00 [v1.04][RISCV] Extend extension mask to 64 bit. Fix SET_ISA_EXT_MAP else condition. Fix print_ascii_riscv iters computation 2023-09-24 11:59:43 +01:00
Dr-Noob
bd3c66395d [v1.04][RISCV] Add multi-letter extensions to list 2023-09-22 21:39:17 +01:00
Dr-Noob
a12defaf4b [v1.04][RISCV] Define to enum 2023-09-19 08:18:13 +01:00
Dr-Noob
4fa3dc2076 [v1.04][RISCV] First support for parsing multi-letter extensions 2023-09-18 08:20:32 +01:00
Dr-Noob
bcf8b8171d [v1.04][RISCV] Temporary fix to parse multi-letter extensions 2023-09-17 23:14:49 +01:00
Dr-Noob
7d81d895b0 [v1.04][ARM] Add support for M2 Max/Ultra 2023-09-02 21:08:43 +01:00
Dr-Noob
6a5b4c3da4 [v1.04][ARM] Fix bug in socs.h for Apple M2 2023-09-02 20:53:53 +01:00
Dr-Noob
5f5561f177 [v1.04][ARM] Add Rockchip 3588S SoC (thanks #188!) 2023-09-02 19:02:00 +01:00
Dr-Noob
9a46e310e4 [v1.04][X86] Add additional Zen4 cpuid 2023-09-02 18:48:22 +01:00
Dr-Noob
36071b8eb8 [v1.04][ARM] Add support for M2 Pro 2023-06-09 17:47:05 +02:00
Dr-Noob
6349f4435e [v1.04][X86] Add mobile rocket lake chip 2023-06-06 21:44:27 +02:00
Dr-Noob
bddf6cfe31 [v1.04][PPC] Small fix for jump or move depends on uninitialised value (noted in #178) 2023-05-09 10:58:16 +02:00
Dr-Noob
53e5dd19f7 [v1.04][ARM] Experimental new backend for computing peak performance, considering the number of VPUs and width (previously this was highly simplified) 2023-05-06 15:36:00 +02:00
Dr-Noob
b3719dc216 [v1.04] Bump version 2023-05-06 11:37:32 +02:00
Dr-Noob
7a3fd539c3 [v1.03][X86] Fix compilation warning under Windows 2023-05-06 11:30:14 +02:00
Dr-Noob
f6bf00e33d [v1.03][X86] Refactor --raw. Add support for printing HV level 2023-05-06 11:14:46 +02:00
Dr-Noob
985bd6f25f [v1.03][X86] Do not consider an empty HV as a bug 2023-05-06 11:02:37 +02:00
Dr-Noob
f599613f5e [v1.03] Reuse same _PATH_CPUINFO definition 2023-05-06 10:19:39 +02:00
Dr-Noob
8a8b1dffa8 [v1.03] Apply refactoring in src/common/udev.c 2023-05-06 10:06:16 +02:00
Dr-Noob
8e95828fb1 [v1.03][PPC] Read frequency from cpuinfo if the default method fails 2023-05-04 19:01:55 +02:00
Dr-Noob
93f733cb12 [v1.03][PPC] Small update in PowerPC uarch table 2023-05-04 18:59:03 +02:00
Dr-Noob
0397db2fd8 [v1.03][PPC] Implement hypervisor detection in PowerPC 2023-05-04 18:56:31 +02:00
Dr-Noob
ebe7312c9d [v1.03][PPC] Fix bug where /sys/devices/system/cpu/cpu*/topology/physical_package_id contains -1 by adding a new way of finding the number of sockets. This happened in #178 and most probably in #153 too 2023-05-03 17:51:44 +02:00
Dr-Noob
8c72295f47 [v1.03] Add PPC integrity check 2023-04-27 22:35:56 +02:00
Dr-Noob
bec47a44a7 [v1.03] Update README (PPC/macOS support was proved in #167) 2023-04-24 17:58:58 +02:00
Dr-Noob
de638aba50 [v1.03][x86] Fix Zen4 peak performance calculation 2023-04-24 17:47:42 +02:00
Dr-Noob
5be6f8bba0 [v1.03][x86] Add AMD 9004 Series CPUID 2023-04-22 08:20:35 +02:00
Dr-Noob
10d4f67cdb [v1.03] Fixing commit 99fd108 2023-04-13 17:50:49 +02:00
Dr-Noob
5dd6ab60cb [v1.03] Lets follow the function prototype rules 2023-04-13 17:45:32 +02:00
Dr-Noob
99fd108d0f [v1.03] Try detecting SoC with nvmem in last place (avoids usless work in Android) 2023-04-13 17:41:32 +02:00
Dr-Noob
f28f3ef70d [v1.03] Avoid segmentation fault when a Rockchip SoC is not found in socs.h 2023-04-13 17:37:14 +02:00
Dr-Noob
89aadeead8 [v1.03] Add common soc.c/.h for both ARM and RISC-V 2023-04-13 17:15:32 +02:00
Dr-Noob
f58d76ccac [v1.03] Update help option and perform some formatting adjustments 2023-04-13 16:24:47 +02:00
Dr-Noob
889fbf2d67 [v1.03][RISCV] Fix bug in Makefile and implement --debug option 2023-04-13 15:49:06 +02:00
Dr-Noob
91cc04c653 [v1.03][RISCV] Merge RISC-V branch into main 2023-04-13 15:28:42 +02:00
Dr-Noob
05744f4e40 [v1.03][RISCV] Add support for RISCV extensions 2023-04-12 18:55:56 +02:00
Dr-Noob
4405a262ca [v1.03][RISCV] Add some more uarchs 2023-04-12 16:23:23 +02:00
Dr-Noob
9e9828d210 [v1.03][RISCV] Improve SiFive logo and add SiFive color scheme 2023-04-08 12:41:44 +02:00
Dr-Noob
65bad8721e [v1.03][RISCV] Add short/long variants for SiFive and StarFive ascii arts and fix StarFive long logo 2023-04-08 11:51:20 +02:00
Dr-Noob
13e86d7f14 [v1.03][RISCV] Add preeliminary uarch detection 2023-04-07 16:19:43 +02:00
Dr-Noob
69dd47bab0 [v1.03][RISCV] Search backwards in device-tree string 2023-04-07 15:24:33 +02:00
Dr-Noob
0ef08ef53e [v1.03][RISCV] Add basic Allwinner support 2023-04-07 10:37:59 +02:00
Dr-Noob
2b4e675800 [v1.03][ARM] Add more Rockchip SoCs (fix) 2023-04-03 15:10:58 +02:00
Dr-Noob
30a2493ad9 [v1.03][RISCV] Add basic StarFive support 2023-04-03 14:08:58 +02:00
Dr-Noob
a496f694a6 [v1.03][RISCV] Add SiFive ascii art 2023-04-03 13:25:51 +02:00
Dr-Noob
14819c350e [v1.03][RISCV] Add basic SoC detection backend 2023-04-03 12:41:59 +02:00
Dr-Noob
9a69a7f58d [v1.03][RISCV] Implementing basic skeleton for RISC-V backend 2023-04-01 16:46:54 +02:00
Dr-Noob
1f450b23a1 [v1.03][RISCV] Add support for compiling to RISC-V 2023-03-31 17:57:01 +02:00
Dr-Noob
cf77360d1b [v1.03][ARM] Add more Rockchip SoCs 2023-03-25 13:11:31 +01:00
Dr-Noob
dfa321d4f4 [v1.03][ARM] Reworking Rockchip logo and colors 2023-03-25 12:56:36 +01:00
Dr-Noob
522a1c6ddd [v1.03][ARM] Add Rockchip logo and colors 2023-03-25 12:44:10 +01:00
Dr-Noob
994dc0334d [v1.03][ARM] Implement new Rockchip detection based on efuse0 2023-03-25 12:02:31 +01:00
Dr-Noob
ec9b88cc7c [v1.03] Acknowledge Allwinner contributors support 2023-03-25 11:12:42 +01:00
Dr-Noob
c3b5dd0eb0 [v1.03][ARM] Experimental feature: Show vendor logo even when the exact SoC model cannot be determined 2023-03-25 11:00:43 +01:00
Dr-Noob
eaee997945 [v1.03][ARM] Show Unknown SoC if no exact model is found instead of showing the raw name 2023-03-25 10:47:17 +01:00
Dr-Noob
5dced25745 [v1.03][ARM] Added more Allwinner SIDs 2023-03-12 12:29:37 +01:00
Dr-Noob
dc69a9f8a6 [v1.03][ARM] Fix Allwinner H2+/H3 confusion 2023-03-11 16:26:02 +01:00
Dr-Noob
3b54f62d62 [v1.03][ARM] Use SID to improve Allwinner SoC detection. Should help with #173 2023-03-11 12:02:16 +01:00
Dr-Noob
3296dc960e [v1.03][ARM] Add Snapd 730G detection as reported by #174 2023-02-11 19:06:58 +01:00
Dr-Noob
be600728d7 [v1.03][X86] Fix freq functions argument to comply with what pthread expects 2023-01-29 09:30:30 +01:00
Dr-Noob
6eb2357485 [v1.03] Add void to function declarations with no args. C99 Standard says in 6.7.5.3 that empty arguments are actually obsolescent - this commit fixes a warning in some compilers 2023-01-29 09:25:07 +01:00
Dr-Noob
b0354e28ff [v1.03] Fix compilation error due to FILE identifier not being found 2023-01-29 09:17:54 +01:00
Dr-Noob
687459961d [v1.03][X86] Fix ambiguity in Kaby/Coffee Lake classification as noted by #149 2023-01-28 09:06:24 +01:00
Dr-Noob
07e920896b [v1.03] Print version when reporting an error or bug (implements #172) 2023-01-18 22:30:05 +01:00
Dr-Noob
57f11f3eab [v1.03] Print git hash and tag when printing version 2023-01-18 20:31:49 +01:00
Dr-Noob
2b8a942a98 [v1.03] Merge bugfix branch to include Snapd patch 2023-01-17 18:41:12 +01:00
Dr-Noob
f960a97477 [v1.02][ARM] Fix bug in previous commit 2023-01-17 18:06:11 +01:00
Dr-Noob
ba8bbdd252 [v1.03][X86] Add support for new Intel chips in uarch 2023-01-12 18:46:09 +01:00
Dr-Noob
2fc4896429 [v1.03] Remove useless comparaison 2023-01-06 15:17:39 +01:00
Dr-Noob
095bbfb784 [v1.03] Fix build in macOS 2023-01-06 12:19:06 +01:00
Dr-Noob
874f89051a [v1.03] Fix build in PPC 2023-01-06 11:05:19 +01:00
Dr-Noob
22a80d817d [v1.03] Fix compilation errors in Windows 2023-01-05 11:43:14 +01:00
Dr-Noob
49941b1717 [v1.03] Bump version 2023-01-05 11:17:49 +01:00
Dr-Noob
a4c0bb1aae [v1.02] Merge Alder Lake into master branch 2023-01-05 11:17:16 +01:00
Dr-Noob
ea29507b62 [v1.02] Added basic support for Zen4 2022-12-03 16:29:53 +00:00
Dr-Noob
b2aa8194c6 [v1.02][x86] Detect and print core type in ADL 2022-12-02 21:25:30 +00:00
Dr-Noob
d879b06d08 [v1.02][x86] Fix printer for non hybrid architectures 2022-12-02 20:53:40 +00:00
Dr-Noob
6cc18027db [v1.02][x86] ADL has a shared L3, not one L3 per core type 2022-12-02 20:39:49 +00:00
Dr-Noob
77510c260a [v1.02][x86] Small fixes to hybrid core detection 2022-11-05 18:28:10 +00:00
Dr-Noob
1eb1a5246e [v1.02][x86] Extending peakperf computation to hybid cores 2022-11-05 18:17:38 +00:00
Dr-Noob
cec91a1e4d [v1.02][x86] Adding support printing Intel hybrid CPUs 2022-11-05 17:49:43 +00:00
Dr-Noob
ff5166ea2e [v1.02][x86] Adding support for topology detection of hybrid cores 2022-11-05 17:48:20 +00:00
Dr-Noob
051d48b7d1 [v1.02][x86] Suport for detecting hybrid_flag 2022-10-20 20:49:10 +00:00
Dr-Noob
e91eef3e65 [v1.02][x86] Split feature detection into a separate function 2022-10-20 20:48:22 +00:00
Dr-Noob
195866aae3 [v1.02][ARM] Add new ARMv9 uarchs and new Snapd SoC 2022-10-09 17:36:23 +02:00
Dr-Noob
de24d86cd6 [v1.02] Extended get_num_caches_from_files to support maps with commas, should fix #152 2022-09-30 19:44:14 +02:00
Dr-Noob
4b1a087b64 [v1.02][ARM] Kirin SoCs seem to start with hi, not Hi, as reported in #157 2022-09-23 19:36:05 +02:00
Dr-Noob
7eb856ae84 [v1.02] Merge fixes from bugfix 2022-09-23 19:20:30 +02:00
Dr-Noob
65366abe04 [v1.02][ARM] Fixed wrong check for Apple CPU 2022-09-19 11:33:14 +02:00
Dr-Noob
190e5daace [v1.02] Merge master and bugfix2 branches 2022-09-19 11:27:03 +02:00
Dr-Noob
9f7204d43d [v1.02][ARM] Updating M1/M2 peak performance calculations according to the discussion in #155 2022-09-14 11:08:36 +02:00
Dr-Noob
87961144d2 [v1.02][X86] Add Zen3+ uarch 2022-09-09 09:02:26 +02:00
Dr-Noob
f4565cb937 [v1.02] Ignore extension warnings in ppc 2022-09-07 08:18:16 +02:00
Dr-Noob
61a1ad8a2b [v1.02] Merge support for Apple M2 2022-09-06 08:12:44 +02:00
Dr-Noob
ecce0354e5 [v1.02][ARM] Fixed M2 bug, support for M2 should now be complete 2022-09-05 18:17:15 +02:00
Dr-Noob
a955451937 [v1.02][X86] Add Steam Deck CPU as requested in #147 2022-09-05 10:39:06 +02:00
Dr-Noob
db21931118 [v1.02][X86] Fix Coffee Lake spelling 2022-09-05 10:28:07 +02:00
Dr-Noob
71a9308bed [v1.02][X86] Fixed uarch misclassification as noted by #149 2022-09-05 10:19:48 +02:00
Dr-Noob
dfec2a65d2 [v1.02][ARM] Experimental support for M2 2022-09-05 10:02:26 +02:00
Dr-Noob
b319b52952 [v1.02] Use a different name for ifdef; the other might be already defined! 2022-09-05 08:41:19 +02:00
Dr-Noob
758be60967 [v1.02] Remove wrong check in udev 2022-09-05 08:24:22 +02:00
Dr-Noob
52ba038527 [v1.02][ARM] Add support for M1 Ultra 2022-05-25 22:11:48 +01:00
Dr-Noob
0f1c2881d9 [v1.02] Bump version 2022-04-24 11:42:32 +01:00
Dr-Noob
3a628e22ba [v1.01] Merge bugfix2 branch 2022-04-24 11:42:06 +01:00
Dr-Noob
07d1e565e1 [v1.01] Merge bugfix branch 2022-04-24 11:41:46 +01:00
Dr-Noob
0ea0754727 [v1.01] Experimental M1 chip detection using hw.cpusubfamily 2022-03-06 10:40:05 +01:00
Dr-Noob
316c2dec40 [v1.01] Improve read_file implementation as suggested in #137 2022-02-10 22:27:51 +01:00
Dr-Noob
c4b2f31320 [v1.01] Read file in udev by dynamically reallocating a buffer, instead of allocating a fixed size. Should fix issue #137 2022-02-09 22:16:13 +01:00
Dr-Noob
fed0dce706 [v1.01] Add Alder Lake uarch detection 2022-01-25 20:15:07 +01:00
Dr-Noob
3046e84b4b [v1.01] Fix dummy compilation issue 2021-12-28 16:03:16 +01:00
Dr-Noob
874a856e34 [v1.01] Run multiple independent instructions in the pipeline for AVX freq too. Fixes incorrect frequency measures under certain CPUs 2021-12-27 12:42:36 +01:00
Dr-Noob
a4e1a837a3 [v1.01] New license 2021-12-25 11:16:18 +01:00
Dr-Noob
40b13bc60c [v1.01] Refactoring in printer to make code clearer. Remove usless check in PPC 2021-12-08 10:35:38 +01:00
Dr-Noob
84ee3107c6 [v1.01][X86] Merge bugfix2 branch 2021-12-08 10:22:02 +01:00
Dr-Noob
33bf081c0a [v1.01][ARM] Merge changes from feat2 (added Allwinner CPUs) 2021-12-07 13:29:26 +01:00
Dr-Noob
0db9f1f5c2 [v1.01] Add more x86 archs to Makefile 2021-12-06 22:36:12 +01:00
Dr-Noob
4d8f108222 [v1.01] Change apple text color (as suggested by #129) 2021-12-04 09:08:02 +01:00
Dr-Noob
4229e2c63b [v1.01][X86] Do not assume that cach and topo structures are non-NULL, which may easily happen in VMs. Add protection against NULL fields in cpu structure 2021-12-03 23:15:23 +01:00
Dr-Noob
a53fc41041 [v1.01] Added Allwinner SoCs (thanks #130!). Changed the match_soc algorithm; it should be more general now 2021-12-03 16:14:42 +01:00
Dr-Noob
4a9bbef086 [v1.01] Fix compiler warning 2021-11-20 10:27:34 +01:00
Dr-Noob
fe3bc6163c [v1.01] Do not use FMA for frequency measurement. It is sufficient to run any other AVX instructions, and some CPUs support AVX but not FMA. 2021-11-20 10:25:36 +01:00
Dr-Noob
4b50740516 [v1.01] Remove useless frequency measurement (SSE and novector should report the same frequency!). Increase iterations to improve precision 2021-11-20 10:13:35 +01:00
Dr-Noob
2fce2c9f52 [v1.00] Fix freq measurement for AVX512 2021-11-20 10:11:22 +01:00
Dr-Noob
617fd2a520 [v1.00] Implemented all backends for --accurate-pp 2021-11-19 22:01:29 +01:00
Dr-Noob
7226adb04d [v1.00] Skeleton for future support for other vector instructions in --accurate-pp 2021-11-19 21:36:55 +01:00
Dr-Noob
a5b321a966 [v1.00][X86] Retrieve topology from udev when APIC fails (like #119) 2021-11-01 13:55:49 +01:00
Dr-Noob
6981d61eaf [v1.00][X86] Show unknown string when the number of cores cannot be retrieved (like #119) 2021-11-01 13:07:48 +01:00
Dr-Noob
a426f231c6 [v1.00] Add preeliminary support for Phytium chip 2021-10-31 20:19:37 +01:00
Dr-Noob
7692a3cd49 [v1.00] Merge latest commits from master branch 2021-10-31 20:19:21 +01:00
Dr-Noob
bb12a2c276 [v1.00] Fix ambiguity in uarch detection with 0x806E9; it may be Amber/Kaby Lake (thanks to #122 for pointing this out!). We can differentiate by CPU name (hacky, but is there a better way?) 2021-10-07 22:37:29 +02:00
Dr-Noob
432b2d7c56 [v1.00] Temporary rename new Intel CPU uarch names 2021-09-25 22:42:26 +02:00
Dr-Noob
3928a9e3b6 [v1.00] Ice Lake is NOT a uarch; Sunny Cove is. But we need to check for codename in these cases since with the uarch is not enough to determine the number of VPUs 2021-09-25 22:03:22 +02:00
Dr-Noob
9f29023362 [v1.00][ARM] Fix typo in soc.c 2021-09-18 15:32:08 +02:00
Dr-Noob
40380a2f50 [v1.00][ARM] Add board.platform property detection. Try to match the SoC name until it founds a valid one in SoC detection, instead of checking only the first property found 2021-09-18 15:28:33 +02:00
Dr-Noob
b97b43cec7 [v1.00][ARM] Add new Dimensity 1100/1200 SoCs. Allow for non-upercase mtk SoC detection 2021-09-18 13:45:32 +02:00
Dr-Noob
b9988622f2 [v1.00][ARM] Always consider two cores equals using the same criteria: if MIDR and freq are the same 2021-09-18 13:13:24 +02:00
Dr-Noob
2cdc31392a [v1.00] Add --accurate-pp option (Linux x86_64) only. Needs more work to make it stable (add support for non-AVX, AVX512, etc) 2021-09-16 15:13:26 +02:00
Dr-Noob
3b7a122956 [v1.00] Reset affinity in Linux after querying topology 2021-09-16 13:01:50 +02:00
Dr-Noob
c2b0213b9f [v1.00] Update and slightly improve man page as suggested by #118 2021-09-13 22:49:10 +02:00
Dr-Noob
3641391bd8 [v1.00] Clarify what should be posted when a bug occurs 2021-08-31 10:06:09 +02:00
Dr-Noob
0350d116bd [v1.00] Add missing uarchs from instlatx64 2021-08-31 10:02:39 +02:00
Dr-Noob
23055483c4 [v1.00] Fix broken links in README as noted by #114 2021-08-30 23:11:18 +02:00
Dr-Noob
bf75716054 [v1.00][ARM] Add Cortex X1 and Snapd 888+ in ARM detection 2021-08-29 09:53:16 +02:00
Dr-Noob
dd324537ee [v1.00] Significantly improve README 2021-08-23 20:48:41 +02:00
Dr-Noob
a6714dabc7 [0.97] Do not count "L4" cache when computing the max cache level 2021-04-30 22:57:15 +02:00
76 changed files with 5766 additions and 1183 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
cpufetch cpufetch
*.o

352
LICENSE
View File

@@ -1,21 +1,339 @@
MIT License GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (c) 2018 Dr-Noob Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Permission is hereby granted, free of charge, to any person obtaining a copy Preamble
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The licenses for most software are designed to take away your
copies or substantial portions of the Software. freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR When we speak of free software, we are referring to freedom, not
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, price. Our General Public Licenses are designed to make sure that you
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE have the freedom to distribute copies of free software (and charge for
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER this service if you wish), that you receive source code or can get it
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, if you want it, that you can change the software or use pieces of it
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE in new free programs; and that you know you can do these things.
SOFTWARE.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1,7 +1,7 @@
CC ?= gcc CC ?= gcc
CFLAGS+=-Wall -Wextra -pedantic CFLAGS+=-Wall -Wextra -pedantic
SANITY_FLAGS=-Wfloat-equal -Wshadow -Wpointer-arith SANITY_FLAGS=-Wfloat-equal -Wshadow -Wpointer-arith -Wstrict-prototypes
PREFIX ?= /usr PREFIX ?= /usr
@@ -11,28 +11,56 @@ COMMON_SRC = $(SRC_COMMON)main.c $(SRC_COMMON)cpu.c $(SRC_COMMON)udev.c $(SRC_CO
COMMON_HDR = $(SRC_COMMON)ascii.h $(SRC_COMMON)cpu.h $(SRC_COMMON)udev.h $(SRC_COMMON)printer.h $(SRC_COMMON)args.h $(SRC_COMMON)global.h COMMON_HDR = $(SRC_COMMON)ascii.h $(SRC_COMMON)cpu.h $(SRC_COMMON)udev.h $(SRC_COMMON)printer.h $(SRC_COMMON)args.h $(SRC_COMMON)global.h
ifneq ($(OS),Windows_NT) ifneq ($(OS),Windows_NT)
GIT_VERSION := "$(shell git describe --abbrev=4 --dirty --always --tags)"
arch := $(shell uname -m) arch := $(shell uname -m)
ifeq ($(arch), $(filter $(arch), x86_64 amd64 i686)) os := $(shell uname -s)
ifeq ($(os), Linux)
COMMON_SRC += $(SRC_COMMON)freq.c
COMMON_HDR += $(SRC_COMMON)freq.h
endif
ifeq ($(arch), $(filter $(arch), x86_64 amd64 i386 i486 i586 i686))
SRC_DIR=src/x86/ SRC_DIR=src/x86/
SOURCE += $(COMMON_SRC) $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)uarch.c SOURCE += $(COMMON_SRC) $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)uarch.c
HEADERS += $(COMMON_HDR) $(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)uarch.h HEADERS += $(COMMON_HDR) $(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)uarch.h $(SRC_DIR)freq/freq.h
ifeq ($(os), Linux)
SOURCE += $(SRC_DIR)freq/freq.c freq_nov.o freq_avx.o freq_avx512.o
HEADERS += $(SRC_DIR)freq/freq.h
CFLAGS += -pthread
endif
ifeq ($(os), FreeBSD)
SOURCE += $(SRC_COMMON)sysctl.c
HEADERS += $(SRC_COMMON)sysctl.h
endif
CFLAGS += -DARCH_X86 -std=c99 -fstack-protector-all CFLAGS += -DARCH_X86 -std=c99 -fstack-protector-all
else ifeq ($(arch), $(filter $(arch), ppc64le ppc64 ppcle ppc)) else ifeq ($(arch), $(filter $(arch), ppc64le ppc64 ppcle ppc))
SRC_DIR=src/ppc/ SRC_DIR=src/ppc/
SOURCE += $(COMMON_SRC) $(SRC_DIR)ppc.c $(SRC_DIR)uarch.c $(SRC_DIR)udev.c SOURCE += $(COMMON_SRC) $(SRC_DIR)ppc.c $(SRC_DIR)uarch.c $(SRC_DIR)udev.c
HEADERS += $(COMMON_HDR) $(SRC_DIR)ppc.h $(SRC_DIR)uarch.h $(SRC_DIR)udev.c HEADERS += $(COMMON_HDR) $(SRC_DIR)ppc.h $(SRC_DIR)uarch.h $(SRC_DIR)udev.c
CFLAGS += -DARCH_PPC -std=gnu99 -fstack-protector-all CFLAGS += -DARCH_PPC -std=gnu99 -fstack-protector-all -Wno-language-extension-token
else ifeq ($(arch), $(filter $(arch), arm aarch64_be aarch64 arm64 armv8b armv8l armv7l armv6l)) else ifeq ($(arch), $(filter $(arch), arm aarch64_be aarch64 arm64 armv8b armv8l armv7l armv6l))
SRC_DIR=src/arm/ SRC_DIR=src/arm/
SOURCE += $(COMMON_SRC) $(SRC_DIR)midr.c $(SRC_DIR)uarch.c $(SRC_DIR)soc.c $(SRC_DIR)udev.c SOURCE += $(COMMON_SRC) $(SRC_DIR)midr.c $(SRC_DIR)uarch.c $(SRC_COMMON)soc.c $(SRC_DIR)soc.c $(SRC_COMMON)pci.c $(SRC_DIR)udev.c sve.o
HEADERS += $(COMMON_HDR) $(SRC_DIR)midr.h $(SRC_DIR)uarch.h $(SRC_DIR)soc.h $(SRC_DIR)udev.c $(SRC_DIR)socs.h HEADERS += $(COMMON_HDR) $(SRC_DIR)midr.h $(SRC_DIR)uarch.h $(SRC_COMMON)soc.h $(SRC_DIR)soc.h $(SRC_COMMON)pci.h $(SRC_DIR)udev.c $(SRC_DIR)socs.h
CFLAGS += -DARCH_ARM -Wno-unused-parameter -std=c99 -fstack-protector-all CFLAGS += -DARCH_ARM -Wno-unused-parameter -std=c99 -fstack-protector-all
os := $(shell uname -s) # Check if the compiler supports -march=armv8-a+sve. We will use it (if supported) to compile SVE detection code later
ifeq ($(os), Darwin) is_sve_flag_supported := $(shell $(CC) -march=armv8-a+sve -c $(SRC_DIR)sve.c -o sve_test.o 2> /dev/null && echo 'yes'; rm -f sve_test.o)
SOURCE += $(SRC_DIR)sysctl.c ifeq ($(is_sve_flag_supported), yes)
HEADERS += $(SRC_DIR)sysctl.h SVE_FLAGS += -march=armv8-a+sve
endif endif
ifeq ($(os), Darwin)
SOURCE += $(SRC_COMMON)sysctl.c
HEADERS += $(SRC_COMMON)sysctl.h
endif
else ifeq ($(arch), $(filter $(arch), riscv64 riscv32))
SRC_DIR=src/riscv/
SOURCE += $(COMMON_SRC) $(SRC_DIR)riscv.c $(SRC_DIR)uarch.c $(SRC_COMMON)soc.c $(SRC_DIR)soc.c $(SRC_DIR)udev.c
HEADERS += $(COMMON_HDR) $(SRC_DIR)riscv.h $(SRC_DIR)uarch.h $(SRC_COMMON)soc.h $(SRC_DIR)soc.h $(SRC_DIR)udev.h $(SRC_DIR)socs.h
CFLAGS += -DARCH_RISCV -Wno-unused-parameter -std=c99 -fstack-protector-all
else else
# Error lines should not be tabulated because Makefile complains about it # Error lines should not be tabulated because Makefile complains about it
$(warning Unsupported arch detected: $(arch). See https://github.com/Dr-Noob/cpufetch#1-support) $(warning Unsupported arch detected: $(arch). See https://github.com/Dr-Noob/cpufetch#1-support)
@@ -43,6 +71,7 @@ $(error Aborting compilation)
OUTPUT=cpufetch OUTPUT=cpufetch
else else
# Assume x86_64 # Assume x86_64
GIT_VERSION := ""
SRC_DIR=src/x86/ SRC_DIR=src/x86/
SOURCE += $(COMMON_SRC) $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)uarch.c SOURCE += $(COMMON_SRC) $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)uarch.c
HEADERS += $(COMMON_HDR) $(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)uarch.h HEADERS += $(COMMON_HDR) $(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)uarch.h
@@ -51,33 +80,49 @@ else
OUTPUT=cpufetch.exe OUTPUT=cpufetch.exe
endif endif
all: CFLAGS += -O3 all: CFLAGS += -O2
all: $(OUTPUT) all: $(OUTPUT)
debug: CFLAGS += -g -O0 debug: CFLAGS += -g -O0
debug: $(OUTPUT) debug: $(OUTPUT)
static: CFLAGS += -static -O3 static: CFLAGS += -static -O2
static: $(OUTPUT) static: $(OUTPUT)
strict: CFLAGS += -O3 -Werror -fsanitize=undefined -D_FORTIFY_SOURCE=2 strict: CFLAGS += -O2 -Werror -fsanitize=undefined -D_FORTIFY_SOURCE=2
strict: $(OUTPUT) strict: $(OUTPUT)
freq_nov.o: Makefile $(SRC_DIR)freq/freq_nov.c $(SRC_DIR)freq/freq_nov.h $(SRC_DIR)freq/freq.h
$(CC) $(CFLAGS) $(SANITY_FLAGS) -c -pthread $(SRC_DIR)freq/freq_nov.c -o $@
freq_avx.o: Makefile $(SRC_DIR)freq/freq_avx.c $(SRC_DIR)freq/freq_avx.h $(SRC_DIR)freq/freq.h
$(CC) $(CFLAGS) $(SANITY_FLAGS) -c -mavx -pthread $(SRC_DIR)freq/freq_avx.c -o $@
freq_avx512.o: Makefile $(SRC_DIR)freq/freq_avx512.c $(SRC_DIR)freq/freq_avx512.h $(SRC_DIR)freq/freq.h
$(CC) $(CFLAGS) $(SANITY_FLAGS) -c -mavx512f -pthread $(SRC_DIR)freq/freq_avx512.c -o $@
sve.o: Makefile $(SRC_DIR)sve.c $(SRC_DIR)sve.h
$(CC) $(CFLAGS) $(SANITY_FLAGS) $(SVE_FLAGS) -c $(SRC_DIR)sve.c -o $@
$(OUTPUT): Makefile $(SOURCE) $(HEADERS) $(OUTPUT): Makefile $(SOURCE) $(HEADERS)
ifeq ($(GIT_VERSION),"")
$(CC) $(CFLAGS) $(SANITY_FLAGS) $(SOURCE) -o $(OUTPUT) $(CC) $(CFLAGS) $(SANITY_FLAGS) $(SOURCE) -o $(OUTPUT)
else
$(CC) $(CFLAGS) $(SANITY_FLAGS) -DGIT_FULL_VERSION=\"$(GIT_VERSION)\" $(SOURCE) -o $(OUTPUT)
endif
run: $(OUTPUT) run: $(OUTPUT)
./$(OUTPUT) ./$(OUTPUT)
clean: clean:
@rm -f $(OUTPUT) @rm -f $(OUTPUT) *.o
install: $(OUTPUT) install: $(OUTPUT)
install -Dm755 "cpufetch" "$(DESTDIR)$(PREFIX)/bin/cpufetch" install -Dm755 "cpufetch" "$(DESTDIR)$(PREFIX)/bin/cpufetch"
install -Dm644 "LICENSE" "$(DESTDIR)$(PREFIX)/share/licenses/cpufetch-git/LICENSE" install -Dm644 "LICENSE" "$(DESTDIR)$(PREFIX)/share/licenses/cpufetch-git/LICENSE"
install -Dm644 "cpufetch.1" "$(DESTDIR)$(PREFIX)/share/man/man1/cpufetch.1.gz" install -Dm644 "cpufetch.1" "$(DESTDIR)$(PREFIX)/share/man/man1/cpufetch.1"
uninstall: uninstall:
rm -f "$(DESTDIR)$(PREFIX)/bin/cpufetch" rm -f "$(DESTDIR)$(PREFIX)/bin/cpufetch"
rm -f "$(DESTDIR)$(PREFIX)/share/licenses/cpufetch-git/LICENSE" rm -f "$(DESTDIR)$(PREFIX)/share/licenses/cpufetch-git/LICENSE"
rm -f "$(DESTDIR)$(PREFIX)/share/man/man1/cpufetch.1.gz" rm -f "$(DESTDIR)$(PREFIX)/share/man/man1/cpufetch.1"

174
README.md
View File

@@ -1,20 +1,35 @@
<p align="center"><img width=50% src="./pictures/cpufetch.png"></p> <p align="center"><img width=50% src="./pictures/cpufetch.png"></p>
<div align="center">
![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/Dr-Noob/cpufetch?label=cpufetch)
[![GitHub Repo stars](https://img.shields.io/github/stars/Dr-Noob/cpufetch?color=4CC61F)](https://github.com/Dr-Noob/cpufetch/stargazers)
[![GitHub issues](https://img.shields.io/github/issues/Dr-Noob/cpufetch)](https://github.com/Dr-Noob/cpufetch/issues)
[![Packaging status](https://repology.org/badge/tiny-repos/cpufetch.svg)](https://repology.org/project/cpufetch/versions)
[![License](https://img.shields.io/github/license/Dr-Noob/cpufetch?color=orange)](https://github.com/Dr-Noob/cpufetch/blob/master/LICENSE)
<h4 align="center">Simple yet fancy CPU architecture fetching tool</h4> <h4 align="center">Simple yet fancy CPU architecture fetching tool</h4>
&nbsp;
![cpu1](pictures/i9.png) <p align="center"> </p>
<div align="center">
<img height="22px" src="https://img.shields.io/github/v/tag/Dr-Noob/cpufetch?label=cpufetch&style=flat-square">
<a href="https://github.com/Dr-Noob/cpufetch/stargazers">
<img height="22px" src="https://img.shields.io/github/stars/Dr-Noob/cpufetch?color=4CC61F&style=flat-square">
</a>
<a href="https://github.com/Dr-Noob/cpufetch/issues">
<img height="22px" src="https://img.shields.io/github/issues/Dr-Noob/cpufetch?style=flat-square">
</a>
<a href="https://github.com/Dr-Noob/cpufetch/blob/master/README.md#1-support">
<img height="22px" src="pictures/os-shield.jpg">
</a>
<a href="https://github.com/Dr-Noob/cpufetch/blob/master/LICENSE">
<img height="22px" src="https://img.shields.io/github/license/Dr-Noob/cpufetch?color=orange&style=flat-square">
</a>
</div> </div>
<p align="center"> </p>
<p align="center">
cpufetch is a command-line tool written in C that displays the CPU information in a clean and beautiful way
</p>
<p align="center">
<img width=80% src="./pictures/examples.gif">
</p>
# Table of contents # Table of contents
<!-- UPDATE with: doctoc --notitle README.md --> <!-- UPDATE with: doctoc --notitle README.md -->
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- START doctoc generated TOC please keep comment here to allow auto update -->
@@ -24,44 +39,49 @@
- [1. Support](#1-support) - [1. Support](#1-support)
- [2. Installation](#2-installation) - [2. Installation](#2-installation)
- [2.1 Installing from a package](#21-installing-from-a-package) - [2.1 Installing from a package](#21-installing-from-a-package)
- [2.2 Building from source (Linux/Windows/macOS)](#22-building-from-source-linuxwindowsmacos) - [2.2 Building from source](#22-building-from-source)
- [2.3 Android](#23-android) - [2.3 Android](#23-android)
- [3. Examples](#3-examples) - [3. Examples](#3-examples)
- [3.1 x86_64 CPUs](#31-x86_64-cpus) - [3.1 x86_64](#31-x86_64)
- [3.2 ARM CPUs](#32-arm-cpus) - [3.2 ARM](#32-arm)
- [4. Colors and style](#4-colors-and-style) - [3.3 PowerPC](#33-powerpc)
- [3.4 RISC-V](#34-risc-v)
- [4. Colors](#4-colors)
- [4.1 Specifying a name](#41-specifying-a-name)
- [4.2 Specifying the colors in RGB format](#42-specifying-the-colors-in-rgb-format)
- [5. Implementation](#5-implementation) - [5. Implementation](#5-implementation)
- [6. Bugs or improvements](#6-bugs-or-improvements) - [6. Bugs or improvements](#6-bugs-or-improvements)
- [6.1 Unknown microarchitecture error](#61-unknown-microarchitecture-error)
- [6.2 Other situations](#62-other-situations)
- [7. Acknowledgements](#7-acknowledgements) - [7. Acknowledgements](#7-acknowledgements)
- [8. cpufetch for GPUs (gpufetch)](#8-cpufetch-for-gpus-gpufetch) - [8. cpufetch for GPUs (gpufetch)](#8-cpufetch-for-gpus-gpufetch)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
# 1. Support ## 1. Support
cpufetch supports the following architectures: | OS | x86_64 / x86 | ARM | RISC-V | PowerPC |
- x86 / x86_64 |:-----------:|:------------------:|:------------------:|:------------------:|:------------------:|
- ARM | GNU / Linux | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
- PowerPC | Windows | :heavy_check_mark: | :x: | :x: | :x: |
| Android | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
| macOS | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| FreeBSD | :heavy_check_mark: | :x: | :x: | :x: |
| OS | x86_64 / x86 | ARM | PowerPC | Notes | **NOTES:**
|:---------:|:------------------:|:------------------:|:------------------:|:-----------------:| - Colors will be used in Windows only if the terminal supports it.
| GNU/Linux | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Best support | - Support in macOS ARM is limited to Apple chips only
| Windows | :heavy_check_mark: | :x: | :x: | Some information may be missing. <br> Colors will be used if supported |
| Android | :heavy_check_mark: | :heavy_check_mark: | :x: | Some information may be missing |
| macOS | :heavy_check_mark: | :heavy_check_mark: | :x: | Only the Apple M1 is supported in ARM |
| FreeBSD | :heavy_check_mark: | :x: | :x: | Some information may be missing. |
# 2. Installation ## 2. Installation
## 2.1 Installing from a package ### 2.1 Installing from a package
Choose the right package for your operating system: Choose the right package for your operating system:
[![Packaging status](https://repology.org/badge/vertical-allrepos/cpufetch.svg)](https://repology.org/project/cpufetch/versions) [![Packaging status](https://repology.org/badge/vertical-allrepos/cpufetch.svg)](https://repology.org/project/cpufetch/versions)
If there is no available package for your OS, you can download the cpufetch binary from [the releases page](https://github.com/Dr-Noob/cpufetch/releases), or [build cpufetch from source](#22-building-from-source-linuxwindowsmacos) (see below). If there is no available package for your OS, you can download the cpufetch binary from [the releases page](https://github.com/Dr-Noob/cpufetch/releases), or [build cpufetch from source](#22-building-from-source-linuxwindowsmacos) (see below).
## 2.2 Building from source (Linux/Windows/macOS) ### 2.2 Building from source
You will need a C compiler (e.g, `gcc`), and `make` to compile `cpufetch`. To do so, just clone the repo and run `make`: You will need a C compiler (e.g, `gcc`) and `make` to compile `cpufetch`. Just clone the repo and run `make`:
``` ```
git clone https://github.com/Dr-Noob/cpufetch git clone https://github.com/Dr-Noob/cpufetch
@@ -70,9 +90,7 @@ make
./cpufetch ./cpufetch
``` ```
The Makefile is designed to work on Linux, Windows and macOS. ### 2.3 Android
## 2.3 Android
1. Install `termux` app (terminal emulator) 1. Install `termux` app (terminal emulator)
2. Run `pkg install -y git make clang` inside termux. 2. Run `pkg install -y git make clang` inside termux.
3. Build from source normally: 3. Build from source normally:
@@ -81,45 +99,89 @@ The Makefile is designed to work on Linux, Windows and macOS.
- make - make
- ./cpufetch - ./cpufetch
# 3. Examples ## 3. Examples
Here are more examples of how `cpufetch` looks on different CPUs. ### 3.1 x86_64
## 3.1 x86_64 CPUs <p align="center"><img width=90% src="pictures/epyc.png"></p>
<p align="center">AMD EPYC HPC server</p>
<p align="center"><img width=90% src="pictures/cascade_lake.jpg"></p>
<p align="center">Intel Xeon HPC server</p>
![cpu2](pictures/epyc.png) ### 3.2 ARM
![cpu3](pictures/cascade_lake.png) <p align="center">
<img width=45% src="pictures/exynos.jpg">
&nbsp;
<img width=45% src="pictures/snapd.png">
</p>
<p align="center">Samsung Galaxy S8 (left) Xiaomi Redmi Note 7 (right)</p>
## 3.2 ARM CPUs ### 3.3 PowerPC
![cpu4](pictures/exynos.png) <p align="center"><img width=90% src="pictures/ibm.png"></p>
<p align="center">Talos II</p>
![cpu5](pictures/snapdragon.png) ## 3.4 RISC-V
# 4. Colors and style <p align="center"><img width=80% src="pictures/starfive.png"></p>
By default, `cpufetch` will print the CPU art with the system colorscheme. However, you can always set a custom color scheme, either <p align="center">StarFive VisionFive 2</p>
specifying Intel or AMD, or specifying the colors in RGB format:
## 4. Colors
By default, `cpufetch` will print the CPU logo with the system colorscheme. However, you can set a custom color scheme in two different ways:
### 4.1 Specifying a name
By specifying a name, cpufetch will use the specific colors of each manufacture. Valid values are:
- intel
- intel-new
- amd
- ibm
- arm
``` ```
./cpufetch --color intel (default color for Intel) ./cpufetch --color intel (default color for Intel)
./cpufetch --color amd (default color for AMD)
./cpufetch --color 239,90,45:210,200,200:100,200,45:0,200,200 (example)
``` ```
In the case of setting the colors using RGB, 4 colors must be given in with the format: ``[R,G,B:R,G,B:R,G,B:R,G,B]``. These colors correspond to CPU art color (2 colors) and for the text colors (following 2). Thus, you can customize all the colors. ### 4.2 Specifying the colors in RGB format
# 5. Implementation 5 colors must be given in RGB with the format: ``[R,G,B:R,G,B:R,G,B:R,G,B:R,G,B]``. These colors correspond to the CPU logo color (first 3 colors) and for the text colors (following 2).
See [cpufetch programming documentation](https://github.com/Dr-Noob/cpufetch/doc/README.md).
# 6. Bugs or improvements ```
See [cpufetch contributing guidelines](https://github.com/Dr-Noob/cpufetch/CONTRIBUTING.md) ./cpufetch --color 239,90,45:210,200,200:0,0,0:100,200,45:0,200,200
```
# 7. Acknowledgements ## 5. Implementation
See [cpufetch programming documentation](https://github.com/Dr-Noob/cpufetch/tree/master/doc).
## 6. Bugs or improvements
### 6.1 Unknown microarchitecture error
If you get the `Unknown microarchitecture detected` error when running cpufetch, it might be caused by two possible reasons:
1. You are running an old release of cpufetch (most likely)
2. Your microarchitecture is not yet supported
Download and compile the latest version (see https://github.com/Dr-Noob/cpufetch#22-building-from-source for instructions)
and verify if the error persists.
* __If the error dissapears__: It means that this is the first situation. In this case, just use the
latest version of cpufetch which already has support for your hardware.
* __If the error does not dissapear__: It means that this is the
second situation. In this case, please create a new issue with the error message and the output of 'cpufetch --debug' on https://github.com/Dr-Noob/cpufetch/issues
### 6.2 Other situations
See [cpufetch contributing guidelines](https://github.com/Dr-Noob/cpufetch/blob/master/CONTRIBUTING.md).
## 7. Acknowledgements
Thanks to the fellow contributors and interested people in the project. Special thanks to: Thanks to the fellow contributors and interested people in the project. Special thanks to:
- [Gonzalocl](https://github.com/Gonzalocl), [OdnetninI](https://github.com/OdnetninI): Tested cpufetch in the earlier versions of the project in many different CPUs. - [Gonzalocl](https://github.com/Gonzalocl) and [OdnetninI](https://github.com/OdnetninI): Tested cpufetch in the earlier versions of the project in many different CPUs.
- [Kyngo](https://github.com/Kyngo): Tested cpufetch in the Apple M1 CPU. - [Kyngo](https://github.com/Kyngo): Tested cpufetch in the Apple M1 CPU.
- [avollmerhaus](https://github.com/avollmerhaus): Gave me ssh acess to a PowerPC machine, allowing me to develop the PowerPC port. - [avollmerhaus](https://github.com/avollmerhaus): Helped with PowerPC port giving ssh access to a PowerPC machine.
- [bbonev](https://github.com/bbonev), [stephan-cr](https://github.com/stephan-cr): Reviewed the source code. - [bbonev](https://github.com/bbonev) and [stephan-cr](https://github.com/stephan-cr): Reviewed the source code.
- [mdoksa76](https://github.com/mdoksa76) and [exkc](https://github.com/exkc): Excellent ideas and feedback for supporting Allwinner SoCs.
- [Sakura286](https://github.com/Sakura286), [exkc](https://github.com/exkc) and [Patola](https://github.com/Patola): Helped with RISC-V port with ssh access, ideas, testing, etc.
- [ThomasKaiser](https://github.com/ThomasKaiser): Very valuable feedback on improving ARM SoC detection (Apple, Allwinner, Rockchip).
- [zerkerX](https://github.com/zerkerX): Helped with feedback for supporting old (e.g., Pentium III) Intel CPUs.
# 8. cpufetch for GPUs (gpufetch) ## 8. cpufetch for GPUs (gpufetch)
See [gpufetch](https://github.com/Dr-Noob/gpufetch) project! See [gpufetch](https://github.com/Dr-Noob/gpufetch) project!

View File

@@ -1,12 +1,13 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.48.3. It was also manually adapted to look correctly .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.48.3. It was also manually adapted to look correctly
.TH CPUFETCH "1" "August 2021" "cpufetch v0.99 (Linux x86_64 build)" "User Commands" .\" help2man -N -n "Simple yet fancy CPU architecture fetching tool" ./cpufetch > cpufetch.1
.TH CPUFETCH "1" "September 2021" "cpufetch v1.00 (Linux x86_64 build)" "User Commands"
.SH NAME .SH NAME
cpufetch \- manual page for cpufetch v0.99 (Linux x86_64 build) cpufetch \- Simple yet fancy CPU architecture fetching tool
.SH SYNOPSIS .SH SYNOPSIS
.B cpufetch .B cpufetch
[\fI\,OPTION\/\fR]... [\fI\,OPTION\/\fR]...
.SH DESCRIPTION .SH DESCRIPTION
Simple yet fancy CPU architecture fetching tool cpufetch is a command-line tool written in C that displays the CPU information in a clean and beautiful way
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-c\fR, \fB\-\-color\fR \fB\-c\fR, \fB\-\-color\fR

BIN
pictures/cascade_lake.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 62 KiB

BIN
pictures/examples.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
pictures/exynos.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 32 KiB

BIN
pictures/ibm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
pictures/os-shield.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
pictures/snapd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
pictures/starfive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -8,21 +8,22 @@
#ifdef __linux__ #ifdef __linux__
#include <sys/auxv.h> #include <sys/auxv.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include "../common/freq.h"
#elif defined __APPLE__ || __MACH__ #elif defined __APPLE__ || __MACH__
#include "sysctl.h" #include "../common/sysctl.h"
// From Linux kernel: arch/arm64/include/asm/cputype.h
#define MIDR_APPLE_M1_ICESTORM 0x610F0220
#define MIDR_APPLE_M1_FIRESTORM 0x610F0230
#ifndef CPUFAMILY_ARM_FIRESTORM_ICESTORM
#define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1B588BB3
#endif
#endif #endif
#include "../common/global.h" #include "../common/global.h"
#include "../common/soc.h"
#include "../common/args.h"
#include "udev.h" #include "udev.h"
#include "midr.h" #include "midr.h"
#include "uarch.h" #include "uarch.h"
#include "soc.h" #include "sve.h"
bool cores_are_equal(int c1pos, int c2pos, uint32_t* midr_array, int32_t* freq_array) {
return midr_array[c1pos] == midr_array[c2pos] && freq_array[c1pos] == freq_array[c2pos];
}
struct cache* get_cache_info(struct cpuInfo* cpu) { struct cache* get_cache_info(struct cpuInfo* cpu) {
struct cache* cach = emalloc(sizeof(struct cache)); struct cache* cach = emalloc(sizeof(struct cache));
@@ -41,13 +42,22 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
struct frequency* get_frequency_info(uint32_t core) { struct frequency* get_frequency_info(uint32_t core) {
struct frequency* freq = emalloc(sizeof(struct frequency)); struct frequency* freq = emalloc(sizeof(struct frequency));
freq->base = UNKNOWN_FREQ; freq->measured = false;
freq->base = UNKNOWN_DATA;
freq->max = get_max_freq_from_file(core); freq->max = get_max_freq_from_file(core);
#ifdef __linux__
if (freq->max == UNKNOWN_DATA || measure_max_frequency_flag()) {
if (freq->max == UNKNOWN_DATA)
printWarn("Unable to find max frequency from udev, measuring CPU frequency");
freq->max = measure_max_frequency(core);
freq->measured = true;
}
#endif
return freq; return freq;
} }
struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, uint32_t* midr_array, int socket_idx, int ncores) { struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, uint32_t* midr_array, int32_t* freq_array, int socket_idx, int ncores) {
struct topology* topo = emalloc(sizeof(struct topology)); struct topology* topo = emalloc(sizeof(struct topology));
init_topology_struct(topo, cach); init_topology_struct(topo, cach);
@@ -57,7 +67,7 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, uint
int cores_in_socket = 0; int cores_in_socket = 0;
while(socket_idx + 1 > sockets_seen) { while(socket_idx + 1 > sockets_seen) {
if(currrent_core_idx < ncores && midr_array[first_core_idx] == midr_array[currrent_core_idx]) { if(currrent_core_idx < ncores && cores_are_equal(first_core_idx, currrent_core_idx, midr_array, freq_array)) {
currrent_core_idx++; currrent_core_idx++;
cores_in_socket++; cores_in_socket++;
} }
@@ -77,24 +87,26 @@ int64_t get_peak_performance(struct cpuInfo* cpu) {
//First check we have consistent data //First check we have consistent data
for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) { for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
if(get_freq(ptr->freq) == UNKNOWN_FREQ) { if(get_freq(ptr->freq) == UNKNOWN_DATA) {
return -1; return -1;
} }
} }
int64_t flops = 0; int64_t total_flops = 0;
ptr = cpu; ptr = cpu;
for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) { for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
flops += ptr->topo->total_cores * (get_freq(ptr->freq) * 1000000); int vpus = get_number_of_vpus(ptr);
int vpus_width = get_vpus_width(ptr);
bool has_fma = has_fma_support(ptr);
int64_t flops = ptr->topo->total_cores * get_freq(ptr->freq) * 1000000 * vpus * (vpus_width/32);
if(has_fma) flops = flops * 2;
total_flops += flops;
} }
if(cpu->feat->NEON) flops = flops * 4;
return flops; return total_flops;
}
bool cores_are_equal(int c1pos, int c2pos, uint32_t* midr_array, int32_t* freq_array) {
return midr_array[c1pos] == midr_array[c2pos] && freq_array[c1pos] == freq_array[c2pos];
} }
uint32_t fill_ids_from_midr(uint32_t* midr_array, int32_t* freq_array, uint32_t* ids_array, int len) { uint32_t fill_ids_from_midr(uint32_t* midr_array, int32_t* freq_array, uint32_t* ids_array, int len) {
@@ -136,7 +148,7 @@ void init_cpu_info(struct cpuInfo* cpu) {
// true... // true...
// ARM32 https://elixir.bootlin.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h // ARM32 https://elixir.bootlin.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
// ARM64 https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h // ARM64 https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
struct features* get_features_info() { struct features* get_features_info(void) {
struct features* feat = emalloc(sizeof(struct features)); struct features* feat = emalloc(sizeof(struct features));
bool *ptr = &(feat->AES); bool *ptr = &(feat->AES);
for(uint32_t i = 0; i < sizeof(struct features)/sizeof(bool); i++, ptr++) { for(uint32_t i = 0; i < sizeof(struct features)/sizeof(bool); i++, ptr++) {
@@ -157,6 +169,17 @@ struct features* get_features_info() {
feat->SHA1 = hwcaps & HWCAP_SHA1; feat->SHA1 = hwcaps & HWCAP_SHA1;
feat->SHA2 = hwcaps & HWCAP_SHA2; feat->SHA2 = hwcaps & HWCAP_SHA2;
feat->NEON = hwcaps & HWCAP_ASIMD; feat->NEON = hwcaps & HWCAP_ASIMD;
feat->SVE = hwcaps & HWCAP_SVE;
hwcaps = getauxval(AT_HWCAP2);
if (errno == ENOENT) {
printWarn("Unable to retrieve AT_HWCAP2 using getauxval");
}
else {
#ifdef HWCAP2_SVE2
feat->SVE2 = hwcaps & HWCAP2_SVE2;
#endif
}
} }
#else #else
else { else {
@@ -172,6 +195,8 @@ struct features* get_features_info() {
feat->CRC32 = hwcaps & HWCAP2_CRC32; feat->CRC32 = hwcaps & HWCAP2_CRC32;
feat->SHA1 = hwcaps & HWCAP2_SHA1; feat->SHA1 = hwcaps & HWCAP2_SHA1;
feat->SHA2 = hwcaps & HWCAP2_SHA2; feat->SHA2 = hwcaps & HWCAP2_SHA2;
feat->SVE = false;
feat->SVE2 = false;
} }
#endif // ifdef __aarch64__ #endif // ifdef __aarch64__
#elif defined __APPLE__ || __MACH__ #elif defined __APPLE__ || __MACH__
@@ -181,8 +206,14 @@ struct features* get_features_info() {
feat->SHA1 = true; feat->SHA1 = true;
feat->SHA2 = true; feat->SHA2 = true;
feat->NEON = true; feat->NEON = true;
feat->SVE = false;
feat->SVE2 = false;
#endif // ifdef __linux__ #endif // ifdef __linux__
if (feat->SVE || feat->SVE2) {
feat->cntb = sve_cntb();
}
return feat; return feat;
} }
@@ -204,7 +235,7 @@ struct cpuInfo* get_cpu_info_linux(struct cpuInfo* cpu) {
} }
freq_array[i] = get_max_freq_from_file(i); freq_array[i] = get_max_freq_from_file(i);
if(freq_array[i] == UNKNOWN_FREQ) { if(freq_array[i] == UNKNOWN_DATA) {
printWarn("Unable to fetch max frequency for core %d. This is probably because the core is offline", i); printWarn("Unable to fetch max frequency for core %d. This is probably because the core is offline", i);
freq_array[i] = freq_array[0]; freq_array[i] = freq_array[0];
} }
@@ -231,20 +262,20 @@ struct cpuInfo* get_cpu_info_linux(struct cpuInfo* cpu) {
ptr->feat = get_features_info(); ptr->feat = get_features_info();
ptr->freq = get_frequency_info(midr_idx); ptr->freq = get_frequency_info(midr_idx);
ptr->cach = get_cache_info(ptr); ptr->cach = get_cache_info(ptr);
ptr->topo = get_topology_info(ptr, ptr->cach, midr_array, i, ncores); ptr->topo = get_topology_info(ptr, ptr->cach, midr_array, freq_array, i, ncores);
} }
cpu->num_cpus = sockets; cpu->num_cpus = sockets;
cpu->hv = emalloc(sizeof(struct hypervisor)); cpu->hv = emalloc(sizeof(struct hypervisor));
cpu->hv->present = false; cpu->hv->present = false;
cpu->soc = get_soc(); cpu->soc = get_soc(cpu);
cpu->peak_performance = get_peak_performance(cpu); cpu->peak_performance = get_peak_performance(cpu);
return cpu; return cpu;
} }
#elif defined __APPLE__ || __MACH__ #elif defined __APPLE__ || __MACH__
void fill_cpu_info_firestorm_icestorm(struct cpuInfo* cpu) { void fill_cpu_info_firestorm_icestorm(struct cpuInfo* cpu, uint32_t pcores, uint32_t ecores) {
// 1. Fill ICESTORM // 1. Fill ICESTORM
struct cpuInfo* ice = cpu; struct cpuInfo* ice = cpu;
@@ -254,9 +285,9 @@ void fill_cpu_info_firestorm_icestorm(struct cpuInfo* cpu) {
ice->feat = get_features_info(); ice->feat = get_features_info();
ice->topo = malloc(sizeof(struct topology)); ice->topo = malloc(sizeof(struct topology));
ice->topo->cach = ice->cach; ice->topo->cach = ice->cach;
ice->topo->total_cores = 4; ice->topo->total_cores = ecores;
ice->freq = malloc(sizeof(struct frequency)); ice->freq = malloc(sizeof(struct frequency));
ice->freq->base = UNKNOWN_FREQ; ice->freq->base = UNKNOWN_DATA;
ice->freq->max = 2064; ice->freq->max = 2064;
ice->hv = malloc(sizeof(struct hypervisor)); ice->hv = malloc(sizeof(struct hypervisor));
ice->hv->present = false; ice->hv->present = false;
@@ -270,28 +301,128 @@ void fill_cpu_info_firestorm_icestorm(struct cpuInfo* cpu) {
fire->feat = get_features_info(); fire->feat = get_features_info();
fire->topo = malloc(sizeof(struct topology)); fire->topo = malloc(sizeof(struct topology));
fire->topo->cach = fire->cach; fire->topo->cach = fire->cach;
fire->topo->total_cores = 4; fire->topo->total_cores = pcores;
fire->freq = malloc(sizeof(struct frequency)); fire->freq = malloc(sizeof(struct frequency));
fire->freq->base = UNKNOWN_FREQ; fire->freq->base = UNKNOWN_DATA;
fire->freq->max = 3200; fire->freq->max = 3200;
fire->hv = malloc(sizeof(struct hypervisor)); fire->hv = malloc(sizeof(struct hypervisor));
fire->hv->present = false; fire->hv->present = false;
fire->next_cpu = NULL; fire->next_cpu = NULL;
} }
struct cpuInfo* get_cpu_info_mach(struct cpuInfo* cpu) { void fill_cpu_info_avalanche_blizzard(struct cpuInfo* cpu, uint32_t pcores, uint32_t ecores) {
uint32_t cpu_family = get_sys_info_by_name("hw.cpufamily"); // 1. Fill BLIZZARD
struct cpuInfo* bli = cpu;
// Manually fill the cpuInfo assuming that the CPU bli->midr = MIDR_APPLE_M2_BLIZZARD;
// is a ARM_FIRESTORM_ICESTORM (Apple M1) bli->arch = get_uarch_from_midr(bli->midr, bli);
bli->cach = get_cache_info(bli);
bli->feat = get_features_info();
bli->topo = malloc(sizeof(struct topology));
bli->topo->cach = bli->cach;
bli->topo->total_cores = ecores;
bli->freq = malloc(sizeof(struct frequency));
bli->freq->base = UNKNOWN_DATA;
bli->freq->max = 2800;
bli->hv = malloc(sizeof(struct hypervisor));
bli->hv->present = false;
bli->next_cpu = malloc(sizeof(struct cpuInfo));
// 2. Fill AVALANCHE
struct cpuInfo* ava = bli->next_cpu;
ava->midr = MIDR_APPLE_M2_AVALANCHE;
ava->arch = get_uarch_from_midr(ava->midr, ava);
ava->cach = get_cache_info(ava);
ava->feat = get_features_info();
ava->topo = malloc(sizeof(struct topology));
ava->topo->cach = ava->cach;
ava->topo->total_cores = pcores;
ava->freq = malloc(sizeof(struct frequency));
ava->freq->base = UNKNOWN_DATA;
ava->freq->max = 3500;
ava->hv = malloc(sizeof(struct hypervisor));
ava->hv->present = false;
ava->next_cpu = NULL;
}
void fill_cpu_info_everest_sawtooth(struct cpuInfo* cpu, uint32_t pcores, uint32_t ecores) {
// 1. Fill SAWTOOTH
struct cpuInfo* saw = cpu;
saw->midr = MIDR_APPLE_M3_SAWTOOTH;
saw->arch = get_uarch_from_midr(saw->midr, saw);
saw->cach = get_cache_info(saw);
saw->feat = get_features_info();
saw->topo = malloc(sizeof(struct topology));
saw->topo->cach = saw->cach;
saw->topo->total_cores = ecores;
saw->freq = malloc(sizeof(struct frequency));
saw->freq->base = UNKNOWN_DATA;
saw->freq->max = 2750;
saw->hv = malloc(sizeof(struct hypervisor));
saw->hv->present = false;
saw->next_cpu = malloc(sizeof(struct cpuInfo));
// 2. Fill EVEREST
struct cpuInfo* eve = saw->next_cpu;
eve->midr = MIDR_APPLE_M3_EVEREST;
eve->arch = get_uarch_from_midr(eve->midr, eve);
eve->cach = get_cache_info(eve);
eve->feat = get_features_info();
eve->topo = malloc(sizeof(struct topology));
eve->topo->cach = eve->cach;
eve->topo->total_cores = pcores;
eve->freq = malloc(sizeof(struct frequency));
eve->freq->base = UNKNOWN_DATA;
eve->freq->max = 4050;
eve->hv = malloc(sizeof(struct hypervisor));
eve->hv->present = false;
eve->next_cpu = NULL;
}
struct cpuInfo* get_cpu_info_mach(struct cpuInfo* cpu) {
// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_system_capabilities
uint32_t nperflevels = get_sys_info_by_name("hw.nperflevels");
if((cpu->num_cpus = nperflevels) != 2) {
printBug("Expected to find SoC with 2 perf levels, found: %d", cpu->num_cpus);
return NULL;
}
uint32_t pcores = get_sys_info_by_name("hw.perflevel0.physicalcpu");
uint32_t ecores = get_sys_info_by_name("hw.perflevel1.physicalcpu");
if(ecores <= 0) {
printBug("Expected to find a numer of ecores > 0, found: %d", ecores);
return NULL;
}
if(pcores <= 0) {
printBug("Expected to find a numer of pcores > 0, found: %d", pcores);
return NULL;
}
uint32_t cpu_family = get_sys_info_by_name("hw.cpufamily");
// Manually fill the cpuInfo assuming that
// the CPU is an Apple SoC
if(cpu_family == CPUFAMILY_ARM_FIRESTORM_ICESTORM) { if(cpu_family == CPUFAMILY_ARM_FIRESTORM_ICESTORM) {
cpu->num_cpus = 2; fill_cpu_info_firestorm_icestorm(cpu, pcores, ecores);
cpu->soc = get_soc(); cpu->soc = get_soc(cpu);
fill_cpu_info_firestorm_icestorm(cpu); cpu->peak_performance = get_peak_performance(cpu);
}
else if(cpu_family == CPUFAMILY_ARM_AVALANCHE_BLIZZARD) {
fill_cpu_info_avalanche_blizzard(cpu, pcores, ecores);
cpu->soc = get_soc(cpu);
cpu->peak_performance = get_peak_performance(cpu);
}
else if(cpu_family == CPUFAMILY_ARM_EVEREST_SAWTOOTH ||
cpu_family == CPUFAMILY_ARM_EVEREST_SAWTOOTH_2 ||
cpu_family == CPUFAMILY_ARM_EVEREST_SAWTOOTH_PRO ||
cpu_family == CPUFAMILY_ARM_EVEREST_SAWTOOTH_MAX) {
fill_cpu_info_everest_sawtooth(cpu, pcores, ecores);
cpu->soc = get_soc(cpu);
cpu->peak_performance = get_peak_performance(cpu); cpu->peak_performance = get_peak_performance(cpu);
} }
else { else {
printBug("Found invalid cpu_family: 0x%.8X", cpu_family); printBugCheckRelease("Found invalid cpu_family: 0x%.8X", cpu_family);
return NULL; return NULL;
} }
@@ -299,7 +430,7 @@ struct cpuInfo* get_cpu_info_mach(struct cpuInfo* cpu) {
} }
#endif #endif
struct cpuInfo* get_cpu_info() { struct cpuInfo* get_cpu_info(void) {
struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo));
init_cpu_info(cpu); init_cpu_info(cpu);
@@ -320,7 +451,7 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc
char* get_str_features(struct cpuInfo* cpu) { char* get_str_features(struct cpuInfo* cpu) {
struct features* feat = cpu->feat; struct features* feat = cpu->feat;
uint32_t max_len = strlen("NEON,SHA1,SHA2,AES,CRC32,") + 1; uint32_t max_len = strlen("NEON,SHA1,SHA2,AES,CRC32,SVE,SVE2,") + 1;
uint32_t len = 0; uint32_t len = 0;
char* string = ecalloc(max_len, sizeof(char)); char* string = ecalloc(max_len, sizeof(char));
@@ -328,6 +459,14 @@ char* get_str_features(struct cpuInfo* cpu) {
strcat(string, "NEON,"); strcat(string, "NEON,");
len += 5; len += 5;
} }
if(feat->SVE) {
strcat(string, "SVE,");
len += 4;
}
if(feat->SVE2) {
strcat(string, "SVE2,");
len += 5;
}
if(feat->SHA1) { if(feat->SHA1) {
strcat(string, "SHA1,"); strcat(string, "SHA1,");
len += 5; len += 5;
@@ -368,7 +507,7 @@ void print_debug(struct cpuInfo* cpu) {
else { else {
printf("0x%.8X ", midr); printf("0x%.8X ", midr);
} }
if(freq == UNKNOWN_FREQ) { if(freq == UNKNOWN_DATA) {
printWarn("Unable to fetch max frequency for core %d. This is probably because the core is offline", i); printWarn("Unable to fetch max frequency for core %d. This is probably because the core is offline", i);
printf("%ld MHz\n", get_max_freq_from_file(0)); printf("%ld MHz\n", get_max_freq_from_file(0));
} }
@@ -376,6 +515,19 @@ void print_debug(struct cpuInfo* cpu) {
printf("%ld MHz\n", freq); printf("%ld MHz\n", freq);
} }
} }
if (cpu->feat->SVE || cpu->feat->SVE2) {
printf("- cntb: %d\n", (int) cpu->feat->cntb);
}
#if defined(__APPLE__) || defined(__MACH__)
printf("hw.cpufamily: 0x%.8X\n", get_sys_info_by_name("hw.cpufamily"));
printf("hw.cpusubfamily: 0x%.8X\n", get_sys_info_by_name("hw.cpusubfamily"));
printf("hw.nperflevels: %d\n", get_sys_info_by_name("hw.nperflevels"));
printf("hw.physicalcpu: %d\n", get_sys_info_by_name("hw.physicalcpu"));
printf("hw.perflevel0.physicalcpu: %d\n", get_sys_info_by_name("hw.perflevel0.physicalcpu"));
printf("hw.perflevel1.physicalcpu: %d\n", get_sys_info_by_name("hw.perflevel1.physicalcpu"));
#endif
} }
void free_topo_struct(struct topology* topo) { void free_topo_struct(struct topology* topo) {

View File

@@ -3,7 +3,7 @@
#include "../common/cpu.h" #include "../common/cpu.h"
struct cpuInfo* get_cpu_info(); struct cpuInfo* get_cpu_info(void);
uint32_t get_nsockets(struct topology* topo); uint32_t get_nsockets(struct topology* topo);
char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket); char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket);

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,10 @@
#ifndef __SOC__ #ifndef __SOC_ARM__
#define __SOC__ #define __SOC_ARM__
#include "../common/cpu.h" #include "../common/cpu.h"
#include "../common/soc.h"
#include <stdint.h> #include <stdint.h>
typedef int32_t SOC; struct system_on_chip* get_soc(struct cpuInfo* cpu);
enum {
SOC_VENDOR_UNKNOWN,
SOC_VENDOR_SNAPDRAGON,
SOC_VENDOR_MEDIATEK,
SOC_VENDOR_EXYNOS,
SOC_VENDOR_KIRIN,
SOC_VENDOR_BROADCOM,
SOC_VENDOR_APPLE
};
struct system_on_chip {
SOC soc_model;
VENDOR soc_vendor;
int32_t process;
char* soc_name;
char* raw_name;
};
struct system_on_chip* get_soc();
char* get_soc_name(struct system_on_chip* soc);
VENDOR get_soc_vendor(struct system_on_chip* soc);
char* get_str_process(struct system_on_chip* soc);
#endif #endif

View File

@@ -10,7 +10,6 @@ enum {
SOC_BCM_2836, SOC_BCM_2836,
SOC_BCM_2837, SOC_BCM_2837,
SOC_BCM_2837B0, SOC_BCM_2837B0,
SOC_BCM_2711,
SOC_BCM_21553, SOC_BCM_21553,
SOC_BCM_21553T, SOC_BCM_21553T,
SOC_BCM_21663, SOC_BCM_21663,
@@ -20,6 +19,8 @@ enum {
SOC_BCM_28145, SOC_BCM_28145,
SOC_BCM_2157, SOC_BCM_2157,
SOC_BCM_21654, SOC_BCM_21654,
SOC_BCM_2711,
SOC_BCM_2712,
// Hisilicon // // Hisilicon //
SOC_HISILICON_3620, SOC_HISILICON_3620,
SOC_HISILICON_3630, SOC_HISILICON_3630,
@@ -28,6 +29,10 @@ enum {
SOC_HISILICON_3670, SOC_HISILICON_3670,
SOC_HISILICON_3680, SOC_HISILICON_3680,
SOC_HISILICON_3690, SOC_HISILICON_3690,
SOC_HISILICON_9000S,
// Kunpeng //
SOC_KUNPENG_920,
SOC_KUNPENG_930,
// Exynos // // Exynos //
SOC_EXYNOS_3475, SOC_EXYNOS_3475,
SOC_EXYNOS_4210, SOC_EXYNOS_4210,
@@ -63,37 +68,23 @@ enum {
SOC_EXYNOS_980, SOC_EXYNOS_980,
SOC_EXYNOS_880, SOC_EXYNOS_880,
// Mediatek // // Mediatek //
SOC_MTK_MT6889, SOC_MTK_MT5327,
SOC_MTK_MT6885Z, SOC_MTK_MT5329,
SOC_MTK_MT6853, SOC_MTK_MT5366,
SOC_MTK_MT6873, SOC_MTK_MT5389,
SOC_MTK_MT6875, SOC_MTK_MT5395,
SOC_MTK_MT6761D, SOC_MTK_MT5396,
SOC_MTK_MT6761, SOC_MTK_MT5398,
SOC_MTK_MT6762D, SOC_MTK_MT5505,
SOC_MTK_MT6755, SOC_MTK_MT5561,
SOC_MTK_MT6755M, SOC_MTK_MT5580,
SOC_MTK_MT6755T, SOC_MTK_MT5582,
SOC_MTK_MT6757, SOC_MTK_MT5592,
SOC_MTK_MT6762, SOC_MTK_MT5595,
SOC_MTK_MT6763V, SOC_MTK_MT5596,
SOC_MTK_MT6763T, SOC_MTK_MT5597,
SOC_MTK_MT6757CD, SOC_MTK_MT5889,
SOC_MTK_MT6758, SOC_MTK_MT5895,
SOC_MTK_MT6765,
SOC_MTK_MT6771,
SOC_MTK_MT6768,
SOC_MTK_MT6771T,
SOC_MTK_MT6771V,
SOC_MTK_MT6779,
SOC_MTK_MT6795,
SOC_MTK_MT6795T,
SOC_MTK_MT6797,
SOC_MTK_MT6797M,
SOC_MTK_MT6797D,
SOC_MTK_MT6797T,
SOC_MTK_MT6797X,
SOC_MTK_MT6799,
SOC_MTK_MT6515, SOC_MTK_MT6515,
SOC_MTK_MT6516, SOC_MTK_MT6516,
SOC_MTK_MT6517, SOC_MTK_MT6517,
@@ -123,7 +114,51 @@ enum {
SOC_MTK_MT6750T, SOC_MTK_MT6750T,
SOC_MTK_MT6752, SOC_MTK_MT6752,
SOC_MTK_MT6753, SOC_MTK_MT6753,
SOC_MTK_MT6755M,
SOC_MTK_MT6755T,
SOC_MTK_MT6757,
SOC_MTK_MT6757CD,
SOC_MTK_MT6758,
SOC_MTK_MT6761,
SOC_MTK_MT6761D,
SOC_MTK_MT6762,
SOC_MTK_MT6762D,
SOC_MTK_MT6762G,
SOC_MTK_MT6763T,
SOC_MTK_MT6763V,
SOC_MTK_MT6765,
SOC_MTK_MT6765G,
SOC_MTK_MT6765H,
SOC_MTK_MT6768,
SOC_MTK_MT6769H,
SOC_MTK_MT6769T,
SOC_MTK_MT6769V,
SOC_MTK_MT6769Z,
SOC_MTK_MT6771,
SOC_MTK_MT6779V_CU,
SOC_MTK_MT6779V_CV,
SOC_MTK_MT6785V_CC,
SOC_MTK_MT6785V_CD,
SOC_MTK_MT6789,
SOC_MTK_MT6795,
SOC_MTK_MT6797,
SOC_MTK_MT6797T,
SOC_MTK_MT6797X,
SOC_MTK_MT6799,
SOC_MTK_MT6833,
SOC_MTK_MT6850, SOC_MTK_MT6850,
SOC_MTK_MT6853,
SOC_MTK_MT6853V,
SOC_MTK_MT6873,
SOC_MTK_MT6875,
SOC_MTK_MT6879,
SOC_MTK_MT6883Z,
SOC_MTK_MT6885Z,
SOC_MTK_MT6889,
SOC_MTK_MT6889Z,
SOC_MTK_MT6891,
SOC_MTK_MT6893,
SOC_MTK_MT6893Z,
SOC_MTK_MT8121, SOC_MTK_MT8121,
SOC_MTK_MT8125, SOC_MTK_MT8125,
SOC_MTK_MT8127, SOC_MTK_MT8127,
@@ -138,7 +173,25 @@ enum {
SOC_MTK_MT8581, SOC_MTK_MT8581,
SOC_MTK_MT8735, SOC_MTK_MT8735,
SOC_MTK_MT8765B, SOC_MTK_MT8765B,
SOC_MTK_MT8781V,
SOC_MTK_MT8783, SOC_MTK_MT8783,
SOC_MTK_MT9602,
SOC_MTK_MT9612,
SOC_MTK_MT9613,
SOC_MTK_MT9615,
SOC_MTK_MT9618,
SOC_MTK_MT9632,
SOC_MTK_MT9638,
SOC_MTK_MT9652,
SOC_MTK_MT9653,
SOC_MTK_MT9675,
SOC_MTK_MT9685,
SOC_MTK_MT9686,
SOC_MTK_MT9689,
SOC_MTK_MT9902,
SOC_MTK_MT9950,
SOC_MTK_MT9972,
SOC_MTK_MT9982,
// Snapdragon // // Snapdragon //
SOC_SNAPD_QSD8650, SOC_SNAPD_QSD8650,
SOC_SNAPD_QSD8250, SOC_SNAPD_QSD8250,
@@ -218,11 +271,16 @@ enum {
SOC_SNAPD_SDM660, SOC_SNAPD_SDM660,
SOC_SNAPD_SM6115, SOC_SNAPD_SM6115,
SOC_SNAPD_SM6125, SOC_SNAPD_SM6125,
SOC_SNAPD_SM6375_AC,
SOC_SNAPD_SM6450,
SOC_SNAPD_SDM670, SOC_SNAPD_SDM670,
SOC_SNAPD_SM6150, SOC_SNAPD_SM6150,
SOC_SNAPD_SM6350, SOC_SNAPD_SM6350,
SOC_SNAPD_SDM710, SOC_SNAPD_SDM710,
SOC_SNAPD_SDM712, SOC_SNAPD_SDM712,
SOC_SNAPD_SM4375,
SOC_SNAPD_SM4450,
SOC_SNAPD_SM4635,
SOC_SNAPD_SM7125, SOC_SNAPD_SM7125,
SOC_SNAPD_SM7150_AA, SOC_SNAPD_SM7150_AA,
SOC_SNAPD_SM7150_AB, SOC_SNAPD_SM7150_AB,
@@ -231,6 +289,11 @@ enum {
SOC_SNAPD_SM7250_AA, SOC_SNAPD_SM7250_AA,
SOC_SNAPD_SM7250_AB, SOC_SNAPD_SM7250_AB,
SOC_SNAPD_SM7250_AC, SOC_SNAPD_SM7250_AC,
SOC_SNAPD_SM7435_AB,
SOC_SNAPD_SM7450,
SOC_SNAPD_SM7475,
SOC_SNAPD_SM7550_AB,
SOC_SNAPD_SM7675_AB,
SOC_SNAPD_MSM8974AA, SOC_SNAPD_MSM8974AA,
SOC_SNAPD_MSM8974AB, SOC_SNAPD_MSM8974AB,
SOC_SNAPD_MSM8974AC, SOC_SNAPD_MSM8974AC,
@@ -250,18 +313,106 @@ enum {
SOC_SNAPD_SM8250, SOC_SNAPD_SM8250,
SOC_SNAPD_SM8250_AB, SOC_SNAPD_SM8250_AB,
SOC_SNAPD_SM8350, SOC_SNAPD_SM8350,
SOC_SNAPD_SM8450,
SOC_SNAPD_SM8475,
SOC_SNAPD_SM8550_AB,
SOC_SNAPD_SM8635,
SOC_SNAPD_SM8650_AB,
// APPLE // APPLE
SOC_APPLE_M1 SOC_APPLE_M1,
SOC_APPLE_M1_PRO,
SOC_APPLE_M1_MAX,
SOC_APPLE_M1_ULTRA,
SOC_APPLE_M2,
SOC_APPLE_M2_PRO,
SOC_APPLE_M2_MAX,
SOC_APPLE_M2_ULTRA,
SOC_APPLE_M3,
SOC_APPLE_M3_PRO,
SOC_APPLE_M3_MAX,
// ALLWINNER
SOC_ALLWINNER_A10,
SOC_ALLWINNER_A13,
SOC_ALLWINNER_A10S,
SOC_ALLWINNER_A20,
SOC_ALLWINNER_A23,
SOC_ALLWINNER_A31,
SOC_ALLWINNER_A31S,
SOC_ALLWINNER_A33,
SOC_ALLWINNER_A40,
SOC_ALLWINNER_A50,
SOC_ALLWINNER_A64,
SOC_ALLWINNER_A80,
SOC_ALLWINNER_A83T,
SOC_ALLWINNER_V3S,
SOC_ALLWINNER_HZP,
SOC_ALLWINNER_H2PLUS,
SOC_ALLWINNER_S3,
SOC_ALLWINNER_H3,
SOC_ALLWINNER_H8,
SOC_ALLWINNER_H5,
SOC_ALLWINNER_H6,
SOC_ALLWINNER_H64,
SOC_ALLWINNER_H616,
SOC_ALLWINNER_H618,
SOC_ALLWINNER_R8,
SOC_ALLWINNER_R16,
SOC_ALLWINNER_R40,
SOC_ALLWINNER_R58,
SOC_ALLWINNER_R328,
// ROCKCHIP
SOC_ROCKCHIP_3288,
SOC_ROCKCHIP_3229,
SOC_ROCKCHIP_3308,
SOC_ROCKCHIP_3318,
SOC_ROCKCHIP_3326,
SOC_ROCKCHIP_3328,
SOC_ROCKCHIP_3368,
SOC_ROCKCHIP_3399,
SOC_ROCKCHIP_3528,
SOC_ROCKCHIP_3562,
SOC_ROCKCHIP_3566,
SOC_ROCKCHIP_3568,
SOC_ROCKCHIP_3588,
// GOOGLE
SOC_GOOGLE_TENSOR,
SOC_GOOGLE_TENSOR_G2,
SOC_GOOGLE_TENSOR_G3,
// NVIDIA,
SOC_TEGRA_X1,
// ALTRA
SOC_AMPERE_ALTRA,
// NXP
SOC_NXP_IMX8QM,
SOC_NXP_IMX8QP,
SOC_NXP_IMX8MP,
SOC_NXP_IMX8MN,
SOC_NXP_IMX8MM,
SOC_NXP_IMX8DXP,
SOC_NXP_IMX8QXP,
SOC_NXP_IMX93,
// AMLOGIC
SOC_AMLOGIC_A311D,
// UNKNOWN
SOC_MODEL_UNKNOWN
}; };
inline static VENDOR get_soc_vendor_from_soc(SOC soc) { inline static VENDOR get_soc_vendor_from_soc(SOC soc) {
if(soc >= SOC_BCM_2835 && soc <= SOC_BCM_21654) return SOC_VENDOR_BROADCOM; if(soc >= SOC_BCM_2835 && soc <= SOC_BCM_2712) return SOC_VENDOR_BROADCOM;
else if(soc >= SOC_HISILICON_3620 && soc <= SOC_HISILICON_3690) return SOC_VENDOR_KIRIN; else if(soc >= SOC_HISILICON_3620 && soc <= SOC_HISILICON_9000S) return SOC_VENDOR_KIRIN;
else if(soc >= SOC_KUNPENG_920 && soc <= SOC_KUNPENG_930) return SOC_VENDOR_KUNPENG;
else if(soc >= SOC_EXYNOS_3475 && soc <= SOC_EXYNOS_880) return SOC_VENDOR_EXYNOS; else if(soc >= SOC_EXYNOS_3475 && soc <= SOC_EXYNOS_880) return SOC_VENDOR_EXYNOS;
else if(soc >= SOC_MTK_MT6889 && soc <= SOC_MTK_MT8783) return SOC_VENDOR_MEDIATEK; else if(soc >= SOC_MTK_MT6893 && soc <= SOC_MTK_MT8783) return SOC_VENDOR_MEDIATEK;
else if(soc >= SOC_SNAPD_QSD8650 && soc <= SOC_SNAPD_SM8350) return SOC_VENDOR_SNAPDRAGON; else if(soc >= SOC_SNAPD_QSD8650 && soc <= SOC_SNAPD_SM8650_AB) return SOC_VENDOR_SNAPDRAGON;
else if(soc >= SOC_APPLE_M1 && soc <= SOC_APPLE_M1) return SOC_VENDOR_APPLE; else if(soc >= SOC_APPLE_M1 && soc <= SOC_APPLE_M3_MAX) return SOC_VENDOR_APPLE;
return SOC_VENDOR_UNKNOWN; else if(soc >= SOC_ALLWINNER_A10 && soc <= SOC_ALLWINNER_R328) return SOC_VENDOR_ALLWINNER;
else if(soc >= SOC_ROCKCHIP_3288 && soc <= SOC_ROCKCHIP_3588) return SOC_VENDOR_ROCKCHIP;
else if(soc >= SOC_GOOGLE_TENSOR && soc <= SOC_GOOGLE_TENSOR_G3) return SOC_VENDOR_GOOGLE;
else if(soc >= SOC_TEGRA_X1 && soc <= SOC_TEGRA_X1) return SOC_VENDOR_NVIDIA;
else if(soc >= SOC_AMPERE_ALTRA && soc <= SOC_AMPERE_ALTRA) return SOC_VENDOR_AMPERE;
else if(soc >= SOC_NXP_IMX8QM && soc <= SOC_NXP_IMX93) return SOC_VENDOR_NXP;
else if(soc >= SOC_AMLOGIC_A311D && soc <= SOC_AMLOGIC_A311D) return SOC_VENDOR_AMLOGIC;
return SOC_VENDOR_UNKNOWN;
} }
#endif #endif

15
src/arm/sve.c Normal file
View File

@@ -0,0 +1,15 @@
#include <stdint.h>
#include "../common/global.h"
// https://learn.arm.com/learning-paths/servers-and-cloud-computing/sve/sve_basics/#:~:text=Using%20a%20text%20editor%20of%20your%20choice%2C%20copy,svcntb%28%29%29%3B%20%7D%20This%20program%20prints%20the%20vector%20length
uint64_t sve_cntb(void) {
#ifdef __ARM_FEATURE_SVE
uint64_t x0 = 0;
__asm volatile("cntb %0"
: "=r"(x0));
return x0;
#else
printWarn("sve_cntb: Hardware supports SVE, but it was not enabled by the compiler");
return 0;
#endif
}

6
src/arm/sve.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __SVE_DETECTION__
#define __SVE_DETECTION__
uint64_t sve_cntb(void);
#endif

View File

@@ -1,6 +0,0 @@
#ifndef __SYSCTL__
#define __SYSCTL__
uint32_t get_sys_info_by_name(char* name);
#endif

View File

@@ -10,7 +10,6 @@
// Data not available // Data not available
#define NA -1 #define NA -1
typedef uint32_t MICROARCH;
typedef uint32_t ISA; typedef uint32_t ISA;
struct uarch { struct uarch {
@@ -33,76 +32,10 @@ enum {
ISA_ARMv8_2_A, ISA_ARMv8_2_A,
ISA_ARMv8_3_A, ISA_ARMv8_3_A,
ISA_ARMv8_4_A, ISA_ARMv8_4_A,
}; ISA_ARMv8_5_A,
ISA_ARMv8_6_A,
enum { ISA_ARMv9_A,
UARCH_UNKNOWN, ISA_ARMv9_2_A
// ARM
UARCH_ARM7,
UARCH_ARM9,
UARCH_ARM1136,
UARCH_ARM1156,
UARCH_ARM1176,
UARCH_ARM11MPCORE,
UARCH_CORTEX_A5,
UARCH_CORTEX_A7,
UARCH_CORTEX_A8,
UARCH_CORTEX_A9,
UARCH_CORTEX_A12,
UARCH_CORTEX_A15,
UARCH_CORTEX_A17,
UARCH_CORTEX_A32,
UARCH_CORTEX_A35,
UARCH_CORTEX_A53,
UARCH_CORTEX_A55r0, // ARM Cortex-A55 revision 0 (restricted dual-issue capabilities compared to revision 1+).
UARCH_CORTEX_A55,
UARCH_CORTEX_A57,
UARCH_CORTEX_A65,
UARCH_CORTEX_A72,
UARCH_CORTEX_A73,
UARCH_CORTEX_A75,
UARCH_CORTEX_A76,
UARCH_CORTEX_A77,
UARCH_CORTEX_A78,
UARCH_NEOVERSE_N1,
UARCH_NEOVERSE_E1,
UARCH_SCORPION,
UARCH_KRAIT,
UARCH_KYRO,
UARCH_FALKOR,
UARCH_SAPHIRA,
UARCH_DENVER,
UARCH_DENVER2,
UARCH_CARMEL,
// SAMSUNG
UARCH_EXYNOS_M1, // Samsung Exynos M1 (Exynos 8890 big cores)
UARCH_EXYNOS_M2, // Samsung Exynos M2 (Exynos 8895 big cores)
UARCH_EXYNOS_M3, // Samsung Exynos M3 (Exynos 9810 big cores)
UARCH_EXYNOS_M4, // Samsung Exynos M4 (Exynos 9820 big cores)
UARCH_EXYNOS_M5, // Samsung Exynos M5 (Exynos 9830 big cores)
// APPLE
UARCH_SWIFT, // Apple A6 and A6X processors.
UARCH_CYCLONE, // Apple A7 processor.
UARCH_TYPHOON, // Apple A8 and A8X processor
UARCH_TWISTER, // Apple A9 and A9X processor.
UARCH_HURRICANE, // Apple A10 and A10X processor.
UARCH_MONSOON, // Apple A11 processor (big cores).
UARCH_MISTRAL, // Apple A11 processor (little cores).
UARCH_VORTEX, // Apple A12 processor (big cores).
UARCH_TEMPEST, // Apple A12 processor (big cores).
UARCH_LIGHTNING, // Apple A13 processor (big cores).
UARCH_THUNDER, // Apple A13 processor (little cores).
UARCH_ICESTORM, // Apple M1 processor (little cores).
UARCH_FIRESTORM, // Apple M1 processor (big cores).
// CAVIUM
UARCH_THUNDERX, // Cavium ThunderX
UARCH_THUNDERX2, // Cavium ThunderX2 (originally Broadcom Vulkan).
// MARVELL
UARCH_PJ4,
UARCH_BRAHMA_B15,
UARCH_BRAHMA_B53,
UARCH_XGENE, // Applied Micro X-Gene.
UARCH_TAISHAN_V110 // HiSilicon TaiShan v110 (Huawei Kunpeng 920 series processors).
}; };
static const ISA isas_uarch[] = { static const ISA isas_uarch[] = {
@@ -130,13 +63,33 @@ static const ISA isas_uarch[] = {
[UARCH_CORTEX_A76] = ISA_ARMv8_2_A, [UARCH_CORTEX_A76] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A77] = ISA_ARMv8_2_A, [UARCH_CORTEX_A77] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A78] = ISA_ARMv8_2_A, [UARCH_CORTEX_A78] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A78C] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A78AE] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A510] = ISA_ARMv9_A,
[UARCH_CORTEX_A520] = ISA_ARMv9_2_A,
[UARCH_CORTEX_A710] = ISA_ARMv9_A,
[UARCH_CORTEX_A715] = ISA_ARMv9_A,
[UARCH_CORTEX_A720] = ISA_ARMv9_2_A,
[UARCH_CORTEX_A725] = ISA_ARMv9_2_A,
[UARCH_CORTEX_X1] = ISA_ARMv8_2_A,
[UARCH_CORTEX_X1C] = ISA_ARMv8_2_A, // Assuming same as X1
[UARCH_CORTEX_X2] = ISA_ARMv9_A,
[UARCH_CORTEX_X3] = ISA_ARMv9_A,
[UARCH_CORTEX_X4] = ISA_ARMv9_2_A,
[UARCH_CORTEX_X925] = ISA_ARMv9_2_A,
[UARCH_NEOVERSE_N1] = ISA_ARMv8_2_A, [UARCH_NEOVERSE_N1] = ISA_ARMv8_2_A,
[UARCH_NEOVERSE_N2] = ISA_ARMv9_A,
[UARCH_NEOVERSE_E1] = ISA_ARMv8_2_A, [UARCH_NEOVERSE_E1] = ISA_ARMv8_2_A,
[UARCH_NEOVERSE_V1] = ISA_ARMv8_4_A,
[UARCH_NEOVERSE_V2] = ISA_ARMv9_A,
[UARCH_NEOVERSE_V3] = ISA_ARMv9_2_A,
[UARCH_BRAHMA_B15] = ISA_ARMv7_A, // Same as Cortex-A15 [UARCH_BRAHMA_B15] = ISA_ARMv7_A, // Same as Cortex-A15
[UARCH_BRAHMA_B53] = ISA_ARMv8_A, // Same as Cortex-A53 [UARCH_BRAHMA_B53] = ISA_ARMv8_A, // Same as Cortex-A53
[UARCH_THUNDERX] = ISA_ARMv8_A, [UARCH_THUNDERX] = ISA_ARMv8_A,
[UARCH_THUNDERX2] = ISA_ARMv8_1_A, [UARCH_THUNDERX2] = ISA_ARMv8_1_A,
[UARCH_TAISHAN_V110] = ISA_ARMv8_2_A, [UARCH_TAISHAN_V110] = ISA_ARMv8_2_A,
[UARCH_TAISHAN_V120] = ISA_ARMv8_2_A, // Not confirmed
[UARCH_TAISHAN_V200] = ISA_ARMv8_2_A, // Not confirmed
[UARCH_DENVER] = ISA_ARMv8_A, [UARCH_DENVER] = ISA_ARMv8_A,
[UARCH_DENVER2] = ISA_ARMv8_A, [UARCH_DENVER2] = ISA_ARMv8_A,
[UARCH_CARMEL] = ISA_ARMv8_A, [UARCH_CARMEL] = ISA_ARMv8_A,
@@ -151,9 +104,14 @@ static const ISA isas_uarch[] = {
[UARCH_EXYNOS_M3] = ISA_ARMv8_A, [UARCH_EXYNOS_M3] = ISA_ARMv8_A,
[UARCH_EXYNOS_M4] = ISA_ARMv8_2_A, [UARCH_EXYNOS_M4] = ISA_ARMv8_2_A,
[UARCH_EXYNOS_M5] = ISA_ARMv8_2_A, [UARCH_EXYNOS_M5] = ISA_ARMv8_2_A,
[UARCH_ICESTORM] = ISA_ARMv8_4_A, [UARCH_ICESTORM] = ISA_ARMv8_5_A, // https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Support/AArch64TargetParser.def
[UARCH_FIRESTORM] = ISA_ARMv8_4_A, [UARCH_FIRESTORM] = ISA_ARMv8_5_A,
[UARCH_BLIZZARD] = ISA_ARMv8_6_A, // https://github.com/llvm/llvm-project/blob/main/llvm/unittests/TargetParser/TargetParserTest.cpp
[UARCH_AVALANCHE] = ISA_ARMv8_6_A, // https://github.com/llvm/llvm-project/blob/main/llvm/unittests/TargetParser/TargetParserTest.cpp
[UARCH_SAWTOOTH] = ISA_ARMv8_6_A, // https://github.com/llvm/llvm-project/blob/main/llvm/unittests/TargetParser/TargetParserTest.cpp
[UARCH_EVEREST] = ISA_ARMv8_6_A, // https://github.com/llvm/llvm-project/blob/main/llvm/unittests/TargetParser/TargetParserTest.cpp
[UARCH_PJ4] = ISA_ARMv7_A, [UARCH_PJ4] = ISA_ARMv7_A,
[UARCH_XIAOMI] = ISA_ARMv8_A,
}; };
static char* isas_string[] = { static char* isas_string[] = {
@@ -167,13 +125,18 @@ static char* isas_string[] = {
[ISA_ARMv8_1_A] = "ARMv8.1", [ISA_ARMv8_1_A] = "ARMv8.1",
[ISA_ARMv8_2_A] = "ARMv8.2", [ISA_ARMv8_2_A] = "ARMv8.2",
[ISA_ARMv8_3_A] = "ARMv8.3", [ISA_ARMv8_3_A] = "ARMv8.3",
[ISA_ARMv8_4_A] = "ARMv8.4" [ISA_ARMv8_4_A] = "ARMv8.4",
[ISA_ARMv8_5_A] = "ARMv8.5",
[ISA_ARMv8_6_A] = "ARMv8.6",
[ISA_ARMv9_A] = "ARMv9",
[ISA_ARMv9_2_A] = "ARMv9.2",
}; };
#define UARCH_START if (false) {} #define UARCH_START if (false) {}
#define CHECK_UARCH(arch, cpu, im_, p_, v_, r_, str, uarch, vendor) \ #define CHECK_UARCH(arch, cpu, im_, p_, v_, r_, str, uarch, vendor) \
else if (im_ == im && p_ == p && (v_ == NA || v_ == v) && (r_ == NA || r_ == r)) fill_uarch(arch, cpu, str, uarch, vendor); else if (im_ == im && p_ == p && (v_ == NA || v_ == v) && (r_ == NA || r_ == r)) fill_uarch(arch, cpu, str, uarch, vendor);
#define UARCH_END else { printBug("Unknown microarchitecture detected: IM=0x%.8X P=0x%.8X V=0x%.8X R=0x%.8X", im, p, v, r); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); } #define UARCH_END else { printBugCheckRelease("Unknown microarchitecture detected: IM=0x%X P=0x%X V=0x%X R=0x%X", im, p, v, r); \
fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u, VENDOR vendor) { void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u, VENDOR vendor) {
arch->uarch = u; arch->uarch = u;
@@ -189,10 +152,11 @@ void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u,
/* /*
* Codes are based on pytorch/cpuinfo, more precisely: * Codes are based on pytorch/cpuinfo, more precisely:
* - https://github.com/pytorch/cpuinfo/blob/master/src/arm/uarch.c * - https://github.com/pytorch/cpuinfo/blob/main/src/arm/uarch.c
* Other sources: * Other sources:
* - https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/cputype.h * - https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/cputype.h
* - https://elixir.bootlin.com/linux/latest/source/arch/arm/include/asm/cputype.h * - https://elixir.bootlin.com/linux/latest/source/arch/arm/include/asm/cputype.h
* - https://github.com/AsahiLinux/m1n1/blob/main/src/chickens.c
*/ */
struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) { struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
struct uarch* arch = emalloc(sizeof(struct uarch)); struct uarch* arch = emalloc(sizeof(struct uarch));
@@ -235,8 +199,26 @@ struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
CHECK_UARCH(arch, cpu, 'A', 0xD0C, NA, NA, "Neoverse N1", UARCH_NEOVERSE_N1, CPU_VENDOR_ARM) CHECK_UARCH(arch, cpu, 'A', 0xD0C, NA, NA, "Neoverse N1", UARCH_NEOVERSE_N1, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD0D, NA, NA, "Cortex-A77", UARCH_CORTEX_A77, CPU_VENDOR_ARM) CHECK_UARCH(arch, cpu, 'A', 0xD0D, NA, NA, "Cortex-A77", UARCH_CORTEX_A77, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD0E, NA, NA, "Cortex-A76", UARCH_CORTEX_A76, CPU_VENDOR_ARM) CHECK_UARCH(arch, cpu, 'A', 0xD0E, NA, NA, "Cortex-A76", UARCH_CORTEX_A76, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD40, NA, NA, "Neoverse V1", UARCH_NEOVERSE_V1, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD41, NA, NA, "Cortex-A78", UARCH_CORTEX_A78, CPU_VENDOR_ARM) CHECK_UARCH(arch, cpu, 'A', 0xD41, NA, NA, "Cortex-A78", UARCH_CORTEX_A78, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD42, NA, NA, "Cortex-A78AE", UARCH_CORTEX_A78AE, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD44, NA, NA, "Cortex-X1", UARCH_CORTEX_X1, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD46, NA, NA, "CortexA510", UARCH_CORTEX_A510, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD47, NA, NA, "CortexA710", UARCH_CORTEX_A710, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD48, NA, NA, "Cortex-X2", UARCH_CORTEX_X2, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD49, NA, NA, "Neoverse N2", UARCH_NEOVERSE_N2, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD4A, NA, NA, "Neoverse E1", UARCH_NEOVERSE_E1, CPU_VENDOR_ARM) CHECK_UARCH(arch, cpu, 'A', 0xD4A, NA, NA, "Neoverse E1", UARCH_NEOVERSE_E1, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD4B, NA, NA, "Cortex-A78C", UARCH_CORTEX_A78C, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD4C, NA, NA, "Cortex-X1C", UARCH_CORTEX_X1C, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD4D, NA, NA, "Cortex-A715", UARCH_CORTEX_A715, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD4E, NA, NA, "Cortex-X3", UARCH_CORTEX_X3, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD4F, NA, NA, "Neoverse V2", UARCH_NEOVERSE_V2, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD80, NA, NA, "Cortex-A520", UARCH_CORTEX_A520, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD81, NA, NA, "Cortex-A720", UARCH_CORTEX_A720, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD82, NA, NA, "Cortex-X4", UARCH_CORTEX_X4, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD84, NA, NA, "Neoverse V3", UARCH_NEOVERSE_V3, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD85, NA, NA, "Cortex-X925", UARCH_CORTEX_X925, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD87, NA, NA, "Cortex-A725", UARCH_CORTEX_A725, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'B', 0x00F, NA, NA, "Brahma B15", UARCH_BRAHMA_B15, CPU_VENDOR_BROADCOM) CHECK_UARCH(arch, cpu, 'B', 0x00F, NA, NA, "Brahma B15", UARCH_BRAHMA_B15, CPU_VENDOR_BROADCOM)
CHECK_UARCH(arch, cpu, 'B', 0x100, NA, NA, "Brahma B53", UARCH_BRAHMA_B53, CPU_VENDOR_BROADCOM) CHECK_UARCH(arch, cpu, 'B', 0x100, NA, NA, "Brahma B53", UARCH_BRAHMA_B53, CPU_VENDOR_BROADCOM)
@@ -248,8 +230,11 @@ struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
CHECK_UARCH(arch, cpu, 'C', 0x0A3, NA, NA, "ThunderX 81XX", UARCH_THUNDERX, CPU_VENDOR_CAVIUM) CHECK_UARCH(arch, cpu, 'C', 0x0A3, NA, NA, "ThunderX 81XX", UARCH_THUNDERX, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'C', 0x0AF, NA, NA, "ThunderX2 99XX", UARCH_THUNDERX2, CPU_VENDOR_CAVIUM) CHECK_UARCH(arch, cpu, 'C', 0x0AF, NA, NA, "ThunderX2 99XX", UARCH_THUNDERX2, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'H', 0xD01, NA, NA, "TaiShan v110", UARCH_TAISHAN_V110, CPU_VENDOR_HUAWUEI) // Kunpeng 920 series CHECK_UARCH(arch, cpu, 'H', 0xD01, NA, NA, "TaiShan v110", UARCH_TAISHAN_V110, CPU_VENDOR_HUAWEI) // Kunpeng 920 series
CHECK_UARCH(arch, cpu, 'H', 0xD40, NA, NA, "Cortex-A76", UARCH_CORTEX_A76, CPU_VENDOR_ARM) // Kirin 980 Big/Medium cores -> Cortex-A76 CHECK_UARCH(arch, cpu, 'H', 0xD02, 2, 2, "TaiShan v120", UARCH_TAISHAN_V120, CPU_VENDOR_HUAWEI) // Kiring 9000S Big cores (https://github.com/Dr-Noob/cpufetch/issues/259)
CHECK_UARCH(arch, cpu, 'H', 0xD02, NA, NA, "TaiShan v200", UARCH_TAISHAN_V200, CPU_VENDOR_HUAWEI) // Kunpeng 930 series (found in openeuler: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/XQCV7NX2UKRIUWUFKRF4PO3QENCOUFR3)
CHECK_UARCH(arch, cpu, 'H', 0xD40, NA, NA, "Cortex-A76", UARCH_CORTEX_A76, CPU_VENDOR_ARM) // Kirin 980 Big/Medium cores -> Cortex-A76
CHECK_UARCH(arch, cpu, 'H', 0xD42, NA, NA, "TaiShan v120", UARCH_TAISHAN_V120, CPU_VENDOR_HUAWEI) // Kiring 9000S Small Cores (https://github.com/Dr-Noob/cpufetch/issues/259)
CHECK_UARCH(arch, cpu, 'N', 0x000, NA, NA, "Denver", UARCH_DENVER, CPU_VENDOR_NVIDIA) CHECK_UARCH(arch, cpu, 'N', 0x000, NA, NA, "Denver", UARCH_DENVER, CPU_VENDOR_NVIDIA)
CHECK_UARCH(arch, cpu, 'N', 0x003, NA, NA, "Denver2", UARCH_DENVER2, CPU_VENDOR_NVIDIA) CHECK_UARCH(arch, cpu, 'N', 0x003, NA, NA, "Denver2", UARCH_DENVER2, CPU_VENDOR_NVIDIA)
@@ -286,8 +271,17 @@ struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
CHECK_UARCH(arch, cpu, 'S', 0x003, 1, NA, "Exynos M4", UARCH_EXYNOS_M4, CPU_VENDOR_SAMSUNG) // Exynos 9820 CHECK_UARCH(arch, cpu, 'S', 0x003, 1, NA, "Exynos M4", UARCH_EXYNOS_M4, CPU_VENDOR_SAMSUNG) // Exynos 9820
CHECK_UARCH(arch, cpu, 'S', 0x004, 1, NA, "Exynos M5", UARCH_EXYNOS_M5, CPU_VENDOR_SAMSUNG) // Exynos 9820 (this one looks wrong at uarch.c ...) CHECK_UARCH(arch, cpu, 'S', 0x004, 1, NA, "Exynos M5", UARCH_EXYNOS_M5, CPU_VENDOR_SAMSUNG) // Exynos 9820 (this one looks wrong at uarch.c ...)
CHECK_UARCH(arch, cpu, 'p', 0x663, 1, NA, "Xiaomi", UARCH_XIAOMI, CPU_VENDOR_PHYTIUM) // From a fellow contributor (https://github.com/Dr-Noob/cpufetch/issues/125)
// Also interesting: https://en.wikipedia.org/wiki/FeiTeng_(processor)
CHECK_UARCH(arch, cpu, 'a', 0x022, NA, NA, "Icestorm", UARCH_ICESTORM, CPU_VENDOR_APPLE) CHECK_UARCH(arch, cpu, 'a', 0x022, NA, NA, "Icestorm", UARCH_ICESTORM, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'a', 0x023, NA, NA, "Firestorm", UARCH_FIRESTORM, CPU_VENDOR_APPLE) CHECK_UARCH(arch, cpu, 'a', 0x023, NA, NA, "Firestorm", UARCH_FIRESTORM, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'a', 0x024, NA, NA, "Icestorm", UARCH_ICESTORM, CPU_VENDOR_APPLE) // https://github.com/Dr-Noob/cpufetch/issues/263
CHECK_UARCH(arch, cpu, 'a', 0x025, NA, NA, "Firestorm", UARCH_FIRESTORM, CPU_VENDOR_APPLE) // https://github.com/Dr-Noob/cpufetch/issues/263
CHECK_UARCH(arch, cpu, 'a', 0x030, NA, NA, "Blizzard", UARCH_BLIZZARD, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'a', 0x031, NA, NA, "Avalanche", UARCH_AVALANCHE, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'a', 0x048, NA, NA, "Sawtooth", UARCH_SAWTOOTH, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'a', 0x049, NA, NA, "Everest", UARCH_EVEREST, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'V', 0x581, NA, NA, "PJ4", UARCH_PJ4, CPU_VENDOR_MARVELL) CHECK_UARCH(arch, cpu, 'V', 0x581, NA, NA, "PJ4", UARCH_PJ4, CPU_VENDOR_MARVELL)
CHECK_UARCH(arch, cpu, 'V', 0x584, NA, NA, "PJ4B-MP", UARCH_PJ4, CPU_VENDOR_MARVELL) CHECK_UARCH(arch, cpu, 'V', 0x584, NA, NA, "PJ4B-MP", UARCH_PJ4, CPU_VENDOR_MARVELL)
@@ -297,10 +291,112 @@ struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
return arch; return arch;
} }
bool is_ARMv8_or_newer(struct cpuInfo* cpu) {
return cpu->arch->isa >= ISA_ARMv8_A;
}
bool has_fma_support(struct cpuInfo* cpu) {
// Arm A64 Instruction Set Architecture
// https://developer.arm.com/documentation/ddi0596/2021-12/SIMD-FP-Instructions
return is_ARMv8_or_newer(cpu);
}
int get_vpus_width(struct cpuInfo* cpu) {
// If the CPU has NEON, width can be 64 or 128 [1].
// In >= ARMv8, NEON are 128 bits width [2]
// If the CPU has SVE/SVE2, width can be between 128-2048 [3],
// so we get the exact value from cntb [4]
//
// [1] https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(Neon)
// [2] https://developer.arm.com/documentation/102474/0100/Fundamentals-of-Armv8-Neon-technology
// [3] https://www.anandtech.com/show/16640/arm-announces-neoverse-v1-n2-platforms-cpus-cmn700-mesh/5
// [4] https://developer.arm.com/documentation/ddi0596/2020-12/SVE-Instructions/CNTB--CNTD--CNTH--CNTW--Set-scalar-to-multiple-of-predicate-constraint-element-count-
if (cpu->feat->SVE && cpu->feat->cntb > 0) {
return cpu->feat->cntb * 8;
}
else if (cpu->feat->NEON) {
if(is_ARMv8_or_newer(cpu)) {
return 128;
}
else {
return 64;
}
}
else {
return 32;
}
}
int get_number_of_vpus(struct cpuInfo* cpu) {
MICROARCH ua = cpu->arch->uarch;
switch(ua) {
case UARCH_CORTEX_X925: // [https://www.anandtech.com/show/21399/arm-unveils-2024-cpu-core-designs-cortex-x925-a725-and-a520-arm-v9-2-redefined-for-3nm-/2]
return 6;
case UARCH_EVEREST: // Just a guess, needs confirmation.
case UARCH_FIRESTORM: // [https://dougallj.github.io/applecpu/firestorm-simd.html]
case UARCH_AVALANCHE: // [https://en.wikipedia.org/wiki/Comparison_of_ARM_processors]
case UARCH_CORTEX_X1: // [https://www.anandtech.com/show/15813/arm-cortex-a78-cortex-x1-cpu-ip-diverging/3]
case UARCH_CORTEX_X1C: // Assuming same as X1
case UARCH_CORTEX_X2: // [https://www.anandtech.com/show/16693/arm-announces-mobile-armv9-cpu-microarchitectures-cortexx2-cortexa710-cortexa510/2]
case UARCH_CORTEX_X3: // [https://www.hwcooling.net/en/cortex-x3-the-new-fastest-arm-core-architecture-analysis: "The FPU and SIMD unit of the core still has four pipelines"]
case UARCH_CORTEX_X4: // [https://www.anandtech.com/show/18871/arm-unveils-armv92-mobile-architecture-cortex-x4-a720-and-a520-64bit-exclusive/2]: "Cortex-X4: Out-of-Order Core"
case UARCH_NEOVERSE_V1: // [https://en.wikichip.org/wiki/arm_holdings/microarchitectures/neoverse_v1]
case UARCH_NEOVERSE_V2: // [https://chipsandcheese.com/2023/09/11/hot-chips-2023-arms-neoverse-v2/]
case UARCH_NEOVERSE_V3: // Assuming same as V2
return 4;
case UARCH_SAWTOOTH: // Needs confirmation, rn this is the best we know: https://mastodon.social/@dougall/111118317031041336
case UARCH_EXYNOS_M3: // [https://www.anandtech.com/show/12361/samsung-exynos-m3-architecture]
case UARCH_EXYNOS_M4: // [https://en.wikichip.org/wiki/samsung/microarchitectures/m4#Block_Diagram]
case UARCH_EXYNOS_M5: // [https://en.wikichip.org/wiki/samsung/microarchitectures/m5]
return 3;
case UARCH_ICESTORM: // [https://dougallj.github.io/applecpu/icestorm-simd.html]
case UARCH_BLIZZARD: // [https://en.wikipedia.org/wiki/Comparison_of_ARM_processors]
case UARCH_TAISHAN_V110:// [https://www-file.huawei.com/-/media/corp2020/pdf/publications/huawei-research/2022/huawei-research-issue1-en.pdf]: "128-bit x 2 for single precision"
case UARCH_TAISHAN_V120:// Not confirmed, asssuming same as v110
case UARCH_TAISHAN_V200:// Not confirmed, asssuming same as v110
case UARCH_CORTEX_A57: // [https://www.anandtech.com/show/8718/the-samsung-galaxy-note-4-exynos-review/5]
case UARCH_CORTEX_A72: // [https://www.anandtech.com/show/10347/arm-cortex-a73-artemis-unveiled/2]
case UARCH_CORTEX_A73: // [https://www.anandtech.com/show/10347/arm-cortex-a73-artemis-unveiled/2]
case UARCH_CORTEX_A75: // [https://www.anandtech.com/show/11441/dynamiq-and-arms-new-cpus-cortex-a75-a55/3]
case UARCH_CORTEX_A76: // [https://www.anandtech.com/show/12785/arm-cortex-a76-cpu-unveiled-7nm-powerhouse/3]
case UARCH_CORTEX_A77: // [https://fuse.wikichip.org/news/2339/arm-unveils-cortex-a77-emphasizes-single-thread-performance]
case UARCH_CORTEX_A78: // [https://fuse.wikichip.org/news/3536/arm-unveils-the-cortex-a78-when-less-is-more]
case UARCH_CORTEX_A78C: // Assuming same as A78
case UARCH_CORTEX_A78AE:// Assuming same as A78
case UARCH_EXYNOS_M1: // [https://www.anandtech.com/show/12361/samsung-exynos-m3-architecture]
case UARCH_EXYNOS_M2: // [https://www.anandtech.com/show/12361/samsung-exynos-m3-architecture]
case UARCH_NEOVERSE_N1: // [https://en.wikichip.org/wiki/arm_holdings/microarchitectures/neoverse_n1#Individual_Core]
case UARCH_NEOVERSE_N2: // [https://chipsandcheese.com/2023/08/18/arms-neoverse-n2-cortex-a710-for-servers/]
case UARCH_CORTEX_A710: // [https://chipsandcheese.com/2023/08/11/arms-cortex-a710-winning-by-default/]: Fig in Core Overview. Table in Instruction Scheduling and Execution
case UARCH_CORTEX_A715: // [https://www.hwcooling.net/en/arm-introduces-new-cortex-a715-core-architecture-analysis/]: "the numbers of ALU and FPU execution units themselves >
case UARCH_CORTEX_A720: // Assuming same as A715: https://www.anandtech.com/show/18871/arm-unveils-armv92-mobile-architecture-cortex-x4-a720-and-a520-64bit-exclusive/3
case UARCH_CORTEX_A725: // Assuming same as A720
return 2;
case UARCH_NEOVERSE_E1: // [https://www.anandtech.com/show/13959/arm-announces-neoverse-n1-platform/5]
// A510 is integrated as part of a Complex. Normally, each complex would incorporate two Cortex-A510 cores.
// Each complex incorporates a single VPU with 2 ports, so for each A510 there is theoretically 1 port.
case UARCH_CORTEX_A510: // [https://en.wikichip.org/wiki/arm_holdings/microarchitectures/cortex-a510#Vector_Processing_Unit_.28VPU.29]
case UARCH_CORTEX_A520: // Assuming same as A50: https://www.anandtech.com/show/18871/arm-unveils-armv92-mobile-architecture-cortex-x4-a720-and-a520-64bit-exclusive/4
return 1;
default:
// ARMv6
// ARMv7
// Remaining UARCH_CORTEX_AXX
// Old Snapdragon (e.g., Scorpion, Krait, etc)
return 1;
}
}
char* get_str_uarch(struct cpuInfo* cpu) { char* get_str_uarch(struct cpuInfo* cpu) {
return cpu->arch->uarch_str; return cpu->arch->uarch_str;
} }
MICROARCH get_uarch(struct uarch* arch) {
return arch->uarch;
}
void free_uarch_struct(struct uarch* arch) { void free_uarch_struct(struct uarch* arch) {
free(arch->uarch_str); free(arch->uarch_str);
free(arch); free(arch);

View File

@@ -5,8 +5,111 @@
#include "midr.h" #include "midr.h"
enum {
UARCH_UNKNOWN,
// ARM
UARCH_ARM7,
UARCH_ARM9,
UARCH_ARM1136,
UARCH_ARM1156,
UARCH_ARM1176,
UARCH_ARM11MPCORE,
UARCH_CORTEX_A5,
UARCH_CORTEX_A7,
UARCH_CORTEX_A8,
UARCH_CORTEX_A9,
UARCH_CORTEX_A12,
UARCH_CORTEX_A15,
UARCH_CORTEX_A17,
UARCH_CORTEX_A32,
UARCH_CORTEX_A35,
UARCH_CORTEX_A53,
UARCH_CORTEX_A55r0, // ARM Cortex-A55 revision 0 (restricted dual-issue capabilities compared to revision 1+).
UARCH_CORTEX_A55,
UARCH_CORTEX_A57,
UARCH_CORTEX_A65,
UARCH_CORTEX_A72,
UARCH_CORTEX_A73,
UARCH_CORTEX_A75,
UARCH_CORTEX_A76,
UARCH_CORTEX_A77,
UARCH_CORTEX_A78,
UARCH_CORTEX_A78AE,
UARCH_CORTEX_A78C,
UARCH_CORTEX_A510,
UARCH_CORTEX_A520,
UARCH_CORTEX_A710,
UARCH_CORTEX_A715,
UARCH_CORTEX_A720,
UARCH_CORTEX_A725,
UARCH_CORTEX_X1,
UARCH_CORTEX_X1C,
UARCH_CORTEX_X2,
UARCH_CORTEX_X3,
UARCH_CORTEX_X4,
UARCH_CORTEX_X925,
UARCH_NEOVERSE_N1,
UARCH_NEOVERSE_N2,
UARCH_NEOVERSE_E1,
UARCH_NEOVERSE_V1,
UARCH_NEOVERSE_V2,
UARCH_NEOVERSE_V3,
UARCH_SCORPION,
UARCH_KRAIT,
UARCH_KYRO,
UARCH_FALKOR,
UARCH_SAPHIRA,
UARCH_DENVER,
UARCH_DENVER2,
UARCH_CARMEL,
// SAMSUNG
UARCH_EXYNOS_M1, // Samsung Exynos M1 (Exynos 8890 big cores)
UARCH_EXYNOS_M2, // Samsung Exynos M2 (Exynos 8895 big cores)
UARCH_EXYNOS_M3, // Samsung Exynos M3 (Exynos 9810 big cores)
UARCH_EXYNOS_M4, // Samsung Exynos M4 (Exynos 9820 big cores)
UARCH_EXYNOS_M5, // Samsung Exynos M5 (Exynos 9830 big cores)
// APPLE
UARCH_SWIFT, // Apple A6 and A6X processors.
UARCH_CYCLONE, // Apple A7 processor.
UARCH_TYPHOON, // Apple A8 and A8X processor
UARCH_TWISTER, // Apple A9 and A9X processor.
UARCH_HURRICANE, // Apple A10 and A10X processor.
UARCH_MONSOON, // Apple A11 processor (big cores).
UARCH_MISTRAL, // Apple A11 processor (little cores).
UARCH_VORTEX, // Apple A12 processor (big cores).
UARCH_TEMPEST, // Apple A12 processor (big cores).
UARCH_LIGHTNING, // Apple A13 processor (big cores).
UARCH_THUNDER, // Apple A13 processor (little cores).
UARCH_ICESTORM, // Apple M1 processor (little cores).
UARCH_FIRESTORM, // Apple M1 processor (big cores).
UARCH_BLIZZARD, // Apple M2 processor (little cores).
UARCH_AVALANCHE, // Apple M2 processor (big cores).
UARCH_SAWTOOTH, // Apple M3 processor (little cores).
UARCH_EVEREST, // Apple M3 processor (big cores).
// CAVIUM
UARCH_THUNDERX, // Cavium ThunderX
UARCH_THUNDERX2, // Cavium ThunderX2 (originally Broadcom Vulkan).
// MARVELL
UARCH_PJ4,
UARCH_BRAHMA_B15,
UARCH_BRAHMA_B53,
UARCH_XGENE, // Applied Micro X-Gene.
// HUAWEI
UARCH_TAISHAN_V110, // HiSilicon TaiShan v110
UARCH_TAISHAN_V120, // HiSilicon TaiShan v120
UARCH_TAISHAN_V200, // HiSilicon TaiShan v200
// PHYTIUM
UARCH_XIAOMI, // Not to be confused with Xiaomi Inc
};
typedef uint32_t MICROARCH;
struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu); struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu);
int get_number_of_vpus(struct cpuInfo* cpu);
int get_vpus_width(struct cpuInfo* cpu);
bool has_fma_support(struct cpuInfo* cpu);
char* get_str_uarch(struct cpuInfo* cpu); char* get_str_uarch(struct cpuInfo* cpu);
void free_uarch_struct(struct uarch* arch); void free_uarch_struct(struct uarch* arch);
MICROARCH get_uarch(struct uarch* arch);
#endif #endif

View File

@@ -3,9 +3,6 @@
#include "midr.h" #include "midr.h"
#define _PATH_DEVICETREE_MODEL "/sys/firmware/devicetree/base/model" #define _PATH_DEVICETREE_MODEL "/sys/firmware/devicetree/base/model"
#define _PATH_CPUS_PRESENT _PATH_SYS_SYSTEM _PATH_SYS_CPU "/present"
#define _PATH_CPUINFO "/proc/cpuinfo"
//#define _PATH_CPUINFO "cpuinfo_debug"
#define CPUINFO_CPU_IMPLEMENTER_STR "CPU implementer\t: " #define CPUINFO_CPU_IMPLEMENTER_STR "CPU implementer\t: "
#define CPUINFO_CPU_ARCHITECTURE_STR "CPU architecture: " #define CPUINFO_CPU_ARCHITECTURE_STR "CPU architecture: "
@@ -17,48 +14,6 @@
#define CPUINFO_CPU_STRING "processor" #define CPUINFO_CPU_STRING "processor"
// https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html
int get_ncores_from_cpuinfo() {
// Examples:
// 0-271
// 0-7
// 0
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUS_PRESENT, &filelen)) == NULL) {
printWarn("read_file: %s: %s\n", _PATH_CPUS_PRESENT, strerror(errno));
return UNKNOWN;
}
int ncores;
char* tmp1;
if((tmp1 = strstr(buf, "-")) == NULL) {
// file contains no - character, we assume that it contains 0,
// which means that the CPU contains only one core
return 1;
}
else {
tmp1++;
}
char* tmp2 = strstr(buf, "\n");
char ncores_str[filelen];
memset(ncores_str, 0, sizeof(char) * filelen);
memcpy(ncores_str, tmp1, tmp2-tmp1);
char* end;
errno = 0;
ncores = strtol(ncores_str, &end, 10) + 1;
if(errno != 0) {
printWarn("strtol: %s:\n", strerror(errno));
return UNKNOWN;
}
free(buf);
return ncores;
}
long parse_cpuinfo_field(char* buf, char* field_str, int field_base) { long parse_cpuinfo_field(char* buf, char* field_str, int field_base) {
char* tmp = strstr(buf, field_str); char* tmp = strstr(buf, field_str);
if(tmp == NULL) return -1; if(tmp == NULL) return -1;
@@ -151,36 +106,15 @@ uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success) {
return midr; return midr;
} }
char* get_field_from_cpuinfo(char* CPUINFO_FIELD) { char* get_hardware_from_cpuinfo(void) {
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUINFO, &filelen)) == NULL) {
printWarn("read_file: %s: %s:\n", _PATH_CPUINFO, strerror(errno));
return NULL;
}
char* tmp1 = strstr(buf, CPUINFO_FIELD);
if(tmp1 == NULL) return NULL;
tmp1 = tmp1 + strlen(CPUINFO_FIELD);
char* tmp2 = strstr(tmp1, "\n");
int strlen = (1 + (tmp2-tmp1));
char* hardware = emalloc(sizeof(char) * strlen);
memset(hardware, 0, sizeof(char) * strlen);
strncpy(hardware, tmp1, tmp2-tmp1);
return hardware;
}
char* get_hardware_from_cpuinfo() {
return get_field_from_cpuinfo(CPUINFO_HARDWARE_STR); return get_field_from_cpuinfo(CPUINFO_HARDWARE_STR);
} }
char* get_revision_from_cpuinfo() { char* get_revision_from_cpuinfo(void) {
return get_field_from_cpuinfo(CPUINFO_REVISION_STR); return get_field_from_cpuinfo(CPUINFO_REVISION_STR);
} }
bool is_raspberry_pi() { bool is_raspberry_pi(void) {
int filelen; int filelen;
char* buf; char* buf;
if((buf = read_file(_PATH_DEVICETREE_MODEL, &filelen)) == NULL) { if((buf = read_file(_PATH_DEVICETREE_MODEL, &filelen)) == NULL) {

View File

@@ -3,12 +3,16 @@
#include "../common/udev.h" #include "../common/udev.h"
#define _PATH_SUNXI_NVMEM "/sys/bus/nvmem/devices/sunxi-sid0/nvmem"
#define _PATH_RK_EFUSE0 "/sys/bus/nvmem/devices/rockchip-efuse0/nvmem"
#define _PATH_RK_OTP0 "/sys/bus/nvmem/devices/rockchip-otp0/nvmem"
#define UNKNOWN -1 #define UNKNOWN -1
int get_ncores_from_cpuinfo(); int get_ncores_from_cpuinfo(void);
uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success); uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success);
char* get_hardware_from_cpuinfo(); char* get_hardware_from_cpuinfo(void);
char* get_revision_from_cpuinfo(); char* get_revision_from_cpuinfo(void);
bool is_raspberry_pi(); bool is_raspberry_pi(void);
#endif #endif

View File

@@ -12,6 +12,8 @@
#define COLOR_STR_AMD "amd" #define COLOR_STR_AMD "amd"
#define COLOR_STR_IBM "ibm" #define COLOR_STR_IBM "ibm"
#define COLOR_STR_ARM "arm" #define COLOR_STR_ARM "arm"
#define COLOR_STR_ROCKCHIP "rockchip"
#define COLOR_STR_SIFIVE "sifive"
static const char *SYTLES_STR_LIST[] = { static const char *SYTLES_STR_LIST[] = {
[STYLE_EMPTY] = NULL, [STYLE_EMPTY] = NULL,
@@ -25,6 +27,8 @@ struct args_struct {
bool debug_flag; bool debug_flag;
bool help_flag; bool help_flag;
bool raw_flag; bool raw_flag;
bool accurate_pp;
bool measure_max_frequency_flag;
bool full_cpu_name_flag; bool full_cpu_name_flag;
bool logo_long; bool logo_long;
bool logo_short; bool logo_short;
@@ -37,86 +41,98 @@ struct args_struct {
}; };
const char args_chr[] = { const char args_chr[] = {
/* [ARG_STYLE] = */ 's', /* [ARG_STYLE] = */ 's',
/* [ARG_COLOR] = */ 'c', /* [ARG_COLOR] = */ 'c',
/* [ARG_HELP] = */ 'h', /* [ARG_HELP] = */ 'h',
/* [ARG_RAW] = */ 'r', /* [ARG_RAW] = */ 'r',
/* [ARG_FULLCPUNAME] = */ 'F', /* [ARG_FULLCPUNAME] = */ 'F',
/* [ARG_LOGO_LONG] = */ 1, /* [ARG_LOGO_LONG] = */ 1,
/* [ARG_LOGO_SHORT] = */ 2, /* [ARG_LOGO_SHORT] = */ 2,
/* [ARG_LOGO_INTEL_NEW] = */ 3, /* [ARG_LOGO_INTEL_NEW] = */ 3,
/* [ARG_LOGO_INTEL_OLD] = */ 4, /* [ARG_LOGO_INTEL_OLD] = */ 4,
/* [ARG_DEBUG] = */ 'd', /* [ARG_ACCURATE_PP] = */ 5,
/* [ARG_VERBOSE] = */ 'v', /* [ARG_MEASURE_MAX_FREQ] = */ 6,
/* [ARG_VERSION] = */ 'V', /* [ARG_DEBUG] = */ 'd',
/* [ARG_VERBOSE] = */ 'v',
/* [ARG_VERSION] = */ 'V',
}; };
const char *args_str[] = { const char *args_str[] = {
/* [ARG_STYLE] = */ "style", /* [ARG_STYLE] = */ "style",
/* [ARG_COLOR] = */ "color", /* [ARG_COLOR] = */ "color",
/* [ARG_HELP] = */ "help", /* [ARG_HELP] = */ "help",
/* [ARG_RAW] = */ "raw", /* [ARG_RAW] = */ "raw",
/* [ARG_FULLCPUNAME] = */ "full-cpu-name", /* [ARG_FULLCPUNAME] = */ "full-cpu-name",
/* [ARG_LOGO_LONG] = */ "logo-long", /* [ARG_LOGO_LONG] = */ "logo-long",
/* [ARG_LOGO_SHORT] = */ "logo-short", /* [ARG_LOGO_SHORT] = */ "logo-short",
/* [ARG_LOGO_INTEL_NEW] = */ "logo-intel-new", /* [ARG_LOGO_INTEL_NEW] = */ "logo-intel-new",
/* [ARG_LOGO_INTEL_OLD] = */ "logo-intel-old", /* [ARG_LOGO_INTEL_OLD] = */ "logo-intel-old",
/* [ARG_DEBUG] = */ "debug", /* [ARG_ACCURATE_PP] = */ "accurate-pp",
/* [ARG_VERBOSE] = */ "verbose", /* [ARG_MEASURE_MAX_FREQ] = */ "measure-max-freq",
/* [ARG_VERSION] = */ "version", /* [ARG_DEBUG] = */ "debug",
/* [ARG_VERBOSE] = */ "verbose",
/* [ARG_VERSION] = */ "version",
}; };
static struct args_struct args; static struct args_struct args;
STYLE get_style() { STYLE get_style(void) {
return args.style; return args.style;
} }
struct color** get_colors() { struct color** get_colors(void) {
return args.colors; return args.colors;
} }
bool show_help() { bool show_help(void) {
return args.help_flag; return args.help_flag;
} }
bool show_version() { bool show_version(void) {
return args.version_flag; return args.version_flag;
} }
bool show_debug() { bool show_debug(void) {
return args.debug_flag; return args.debug_flag;
} }
bool show_raw() { bool show_raw(void) {
return args.raw_flag; return args.raw_flag;
} }
bool show_full_cpu_name() { bool accurate_pp(void) {
return args.accurate_pp;
}
bool measure_max_frequency_flag(void) {
return args.measure_max_frequency_flag;
}
bool show_full_cpu_name(void) {
return args.full_cpu_name_flag; return args.full_cpu_name_flag;
} }
bool show_logo_long() { bool show_logo_long(void) {
return args.logo_long; return args.logo_long;
} }
bool show_logo_short() { bool show_logo_short(void) {
return args.logo_short; return args.logo_short;
} }
bool show_logo_intel_new() { bool show_logo_intel_new(void) {
return args.logo_intel_new; return args.logo_intel_new;
} }
bool show_logo_intel_old() { bool show_logo_intel_old(void) {
return args.logo_intel_old; return args.logo_intel_old;
} }
bool verbose_enabled() { bool verbose_enabled(void) {
return args.verbose_flag; return args.verbose_flag;
} }
int max_arg_str_length() { int max_arg_str_length(void) {
int max_len = -1; int max_len = -1;
int len = sizeof(args_str) / sizeof(args_str[0]); int len = sizeof(args_str) / sizeof(args_str[0]);
for(int i=0; i < len; i++) { for(int i=0; i < len; i++) {
@@ -161,6 +177,8 @@ bool parse_color(char* optarg_str, struct color*** cs) {
else if(strcmp(optarg_str, COLOR_STR_AMD) == 0) color_to_copy = COLOR_DEFAULT_AMD; else if(strcmp(optarg_str, COLOR_STR_AMD) == 0) color_to_copy = COLOR_DEFAULT_AMD;
else if(strcmp(optarg_str, COLOR_STR_IBM) == 0) color_to_copy = COLOR_DEFAULT_IBM; else if(strcmp(optarg_str, COLOR_STR_IBM) == 0) color_to_copy = COLOR_DEFAULT_IBM;
else if(strcmp(optarg_str, COLOR_STR_ARM) == 0) color_to_copy = COLOR_DEFAULT_ARM; else if(strcmp(optarg_str, COLOR_STR_ARM) == 0) color_to_copy = COLOR_DEFAULT_ARM;
else if(strcmp(optarg_str, COLOR_STR_ROCKCHIP) == 0) color_to_copy = COLOR_DEFAULT_ROCKCHIP;
else if(strcmp(optarg_str, COLOR_STR_SIFIVE) == 0) color_to_copy = COLOR_DEFAULT_SIFIVE;
else { else {
str_to_parse = optarg_str; str_to_parse = optarg_str;
free_ptr = false; free_ptr = false;
@@ -204,19 +222,27 @@ bool parse_color(char* optarg_str, struct color*** cs) {
return true; return true;
} }
char* build_short_options() { char* build_short_options(void) {
const char *c = args_chr; const char *c = args_chr;
int len = sizeof(args_chr) / sizeof(args_chr[0]); int len = sizeof(args_chr) / sizeof(args_chr[0]);
char* str = (char *) emalloc(sizeof(char) * (len*2 + 1)); char* str = (char *) ecalloc(len*2 + 1, sizeof(char));
memset(str, 0, sizeof(char) * (len*2 + 1));
#ifdef ARCH_X86 #ifdef ARCH_X86
sprintf(str, "%c:%c:%c%c%c%c%c%c%c%c%c%c", sprintf(str, "%c:%c:%c%c%c%c%c%c%c%c%c%c%c%c",
c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP], c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP],
c[ARG_RAW], c[ARG_FULLCPUNAME], c[ARG_RAW], c[ARG_FULLCPUNAME],
c[ARG_LOGO_SHORT], c[ARG_LOGO_LONG], c[ARG_LOGO_SHORT], c[ARG_LOGO_LONG],
c[ARG_LOGO_INTEL_NEW], c[ARG_LOGO_INTEL_OLD], c[ARG_LOGO_INTEL_NEW], c[ARG_LOGO_INTEL_OLD],
c[ARG_DEBUG], c[ARG_VERBOSE], c[ARG_VERSION]); c[ARG_ACCURATE_PP], c[ARG_MEASURE_MAX_FREQ],
c[ARG_DEBUG], c[ARG_VERBOSE],
c[ARG_VERSION]);
#elif ARCH_ARM
sprintf(str, "%c:%c:%c%c%c%c%c%c%c",
c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP],
c[ARG_LOGO_SHORT], c[ARG_LOGO_LONG],
c[ARG_MEASURE_MAX_FREQ],
c[ARG_DEBUG], c[ARG_VERBOSE],
c[ARG_VERSION]);
#else #else
sprintf(str, "%c:%c:%c%c%c%c%c%c", sprintf(str, "%c:%c:%c%c%c%c%c%c",
c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP], c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP],
@@ -235,6 +261,7 @@ bool parse_args(int argc, char* argv[]) {
bool color_flag = false; bool color_flag = false;
args.debug_flag = false; args.debug_flag = false;
args.accurate_pp = false;
args.full_cpu_name_flag = false; args.full_cpu_name_flag = false;
args.raw_flag = false; args.raw_flag = false;
args.verbose_flag = false; args.verbose_flag = false;
@@ -250,20 +277,24 @@ bool parse_args(int argc, char* argv[]) {
set_log_level(true); set_log_level(true);
const struct option long_options[] = { const struct option long_options[] = {
{args_str[ARG_STYLE], required_argument, 0, args_chr[ARG_STYLE] }, {args_str[ARG_STYLE], required_argument, 0, args_chr[ARG_STYLE] },
{args_str[ARG_COLOR], required_argument, 0, args_chr[ARG_COLOR] }, {args_str[ARG_COLOR], required_argument, 0, args_chr[ARG_COLOR] },
{args_str[ARG_HELP], no_argument, 0, args_chr[ARG_HELP] }, {args_str[ARG_HELP], no_argument, 0, args_chr[ARG_HELP] },
#ifdef ARCH_X86 #ifdef ARCH_X86
{args_str[ARG_LOGO_INTEL_NEW], no_argument, 0, args_chr[ARG_LOGO_INTEL_NEW] }, {args_str[ARG_LOGO_INTEL_NEW], no_argument, 0, args_chr[ARG_LOGO_INTEL_NEW] },
{args_str[ARG_LOGO_INTEL_OLD], no_argument, 0, args_chr[ARG_LOGO_INTEL_OLD] }, {args_str[ARG_LOGO_INTEL_OLD], no_argument, 0, args_chr[ARG_LOGO_INTEL_OLD] },
{args_str[ARG_FULLCPUNAME], no_argument, 0, args_chr[ARG_FULLCPUNAME] }, {args_str[ARG_ACCURATE_PP], no_argument, 0, args_chr[ARG_ACCURATE_PP] },
{args_str[ARG_RAW], no_argument, 0, args_chr[ARG_RAW] }, {args_str[ARG_MEASURE_MAX_FREQ], no_argument, 0, args_chr[ARG_MEASURE_MAX_FREQ] },
{args_str[ARG_FULLCPUNAME], no_argument, 0, args_chr[ARG_FULLCPUNAME] },
{args_str[ARG_RAW], no_argument, 0, args_chr[ARG_RAW] },
#elif ARCH_ARM
{args_str[ARG_MEASURE_MAX_FREQ], no_argument, 0, args_chr[ARG_MEASURE_MAX_FREQ] },
#endif #endif
{args_str[ARG_LOGO_SHORT], no_argument, 0, args_chr[ARG_LOGO_SHORT] }, {args_str[ARG_LOGO_SHORT], no_argument, 0, args_chr[ARG_LOGO_SHORT] },
{args_str[ARG_LOGO_LONG], no_argument, 0, args_chr[ARG_LOGO_LONG] }, {args_str[ARG_LOGO_LONG], no_argument, 0, args_chr[ARG_LOGO_LONG] },
{args_str[ARG_DEBUG], no_argument, 0, args_chr[ARG_DEBUG] }, {args_str[ARG_DEBUG], no_argument, 0, args_chr[ARG_DEBUG] },
{args_str[ARG_VERBOSE], no_argument, 0, args_chr[ARG_VERBOSE] }, {args_str[ARG_VERBOSE], no_argument, 0, args_chr[ARG_VERBOSE] },
{args_str[ARG_VERSION], no_argument, 0, args_chr[ARG_VERSION] }, {args_str[ARG_VERSION], no_argument, 0, args_chr[ARG_VERSION] },
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@@ -296,6 +327,12 @@ bool parse_args(int argc, char* argv[]) {
else if(opt == args_chr[ARG_HELP]) { else if(opt == args_chr[ARG_HELP]) {
args.help_flag = true; args.help_flag = true;
} }
else if(opt == args_chr[ARG_ACCURATE_PP]) {
args.accurate_pp = true;
}
else if(opt == args_chr[ARG_MEASURE_MAX_FREQ]) {
args.measure_max_frequency_flag = true;
}
else if(opt == args_chr[ARG_FULLCPUNAME]) { else if(opt == args_chr[ARG_FULLCPUNAME]) {
args.full_cpu_name_flag = true; args.full_cpu_name_flag = true;
} }
@@ -349,6 +386,13 @@ bool parse_args(int argc, char* argv[]) {
args.logo_long = false; args.logo_long = false;
} }
#if defined(ARCH_X86) && ! defined(__linux__)
if(args.accurate_pp) {
printWarn("%s option is valid only in Linux x86_64", args_str[ARG_ACCURATE_PP]);
args.help_flag = true;
}
#endif
// Leave log level untouched after returning // Leave log level untouched after returning
set_log_level(false); set_log_level(false);

View File

@@ -28,6 +28,8 @@ enum {
ARG_LOGO_SHORT, ARG_LOGO_SHORT,
ARG_LOGO_INTEL_NEW, ARG_LOGO_INTEL_NEW,
ARG_LOGO_INTEL_OLD, ARG_LOGO_INTEL_OLD,
ARG_ACCURATE_PP,
ARG_MEASURE_MAX_FREQ,
ARG_DEBUG, ARG_DEBUG,
ARG_VERBOSE, ARG_VERBOSE,
ARG_VERSION ARG_VERSION
@@ -38,20 +40,22 @@ extern const char *args_str[];
#include "printer.h" #include "printer.h"
int max_arg_str_length(); int max_arg_str_length(void);
bool parse_args(int argc, char* argv[]); bool parse_args(int argc, char* argv[]);
bool show_help(); bool show_help(void);
bool show_full_cpu_name(); bool accurate_pp(void);
bool show_logo_long(); bool measure_max_frequency_flag(void);
bool show_logo_short(); bool show_full_cpu_name(void);
bool show_logo_intel_new(); bool show_logo_long(void);
bool show_logo_intel_old(); bool show_logo_short(void);
bool show_raw(); bool show_logo_intel_new(void);
bool show_debug(); bool show_logo_intel_old(void);
bool show_version(); bool show_raw(void);
bool verbose_enabled(); bool show_debug(void);
bool show_version(void);
bool verbose_enabled(void);
void free_colors_struct(struct color** cs); void free_colors_struct(struct color** cs);
struct color** get_colors(); struct color** get_colors(void);
STYLE get_style(); STYLE get_style(void);
#endif #endif

View File

@@ -33,7 +33,7 @@ struct ascii_logo {
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
bool replace_blocks; bool replace_blocks;
char color_ascii[3][100]; char color_ascii[4][100];
char color_text[2][100]; char color_text[2][100];
}; };
@@ -105,6 +105,19 @@ $C1 MMM :MMM NMM dMMK dMMX MMN \
$C1 MMM :MMM NMM dMMMoo OMM0....:Nx. MMN \ $C1 MMM :MMM NMM dMMMoo OMM0....:Nx. MMN \
$C1 MMM :WWW XWW lONMM 'xXMMMMNOc MMN " $C1 MMM :WWW XWW lONMM 'xXMMMMNOc MMN "
#define ASCII_HYGON \
"$C1 \
$C1 \
$C1 \
$C1 ## ## ## ## ###### ###### ## # \
$C1 ##....## ## ## ## ## ## #### # \
$C1 ######## ## ## ##. ## ## # #### \
$C1 ## ## ## *######. ###### # ## \
$C1 \
$C1 \
$C1 \
$C1 "
#define ASCII_SNAPD \ #define ASCII_SNAPD \
" $C1@@$C2######## \ " $C1@@$C2######## \
$C1@@@@@$C2########### \ $C1@@@@@$C2########### \
@@ -145,6 +158,25 @@ $C2 Exynos \
$C2 \ $C2 \
$C2 " $C2 "
#define ASCII_KUNPENG \
"$C2 . \
$C2 .. \
$C2 .## \
$C1 .$CR $C2.###. \
$C1 ..$CR $C2#####. \
$C1 .#.$CR $C2.#######. \
$C1 .####.$CR $C2.#######. \
$C1 ..######*$CR $C2.#######. . \
$C1 .#########*$CR $C2.#######* . \
$C1 ######*$CR $C2.#######. .#. \
$C1*#######*$CR $C2.#######. *##. \
$C1 ##*$CR $C2.#######. ####### \
$C2 ###.$CR $C1#####$C2 *### \
$C1 *########## \
$C1 *######## \
$C1 #####. \
$C1 *###. "
#define ASCII_KIRIN \ #define ASCII_KIRIN \
"$C1 ####### \ "$C1 ####### \
$C1 ##### #################### \ $C1 ##### #################### \
@@ -218,6 +250,189 @@ $C1 kMMMMMMMMMMMMMMMMMMMMMMd \
$C1 'KMMMMMMMWXXWMMMMMMMk. \ $C1 'KMMMMMMMWXXWMMMMMMMk. \
$C1 \"cooc\"* \"*coo'\" " $C1 \"cooc\"* \"*coo'\" "
#define ASCII_GOOGLE \
"$C1 aaaaaaaa \
$C1 .MMMMMMMMMMMMMMMM. \
$C1 .MMMMMMMMMMMMMMMMMMMMM* \
$C1 .MMMMMMMM** *MM* \
$C2 MM$C1MMMMM. \
$C2 *MMM$C1MM. \
$C2*MMMMMM $C4lMMMMMMMMMMMMMMM* \
$C2MMMMMMM $C4lMMMMMMMMMMMMMMMM \
$C2*MMMMMM $C4lMMMMMMMMMMMMMMMd \
$C2 MMMM$C3MMM. $C4*MMMMM. \
$C2 MM$C3MMMMMM. $C4.MMMMMM. \
$C3 *MMMMMMMMM*.......MMM$C4MMMMMM* \
$C3 *MMMMMMMMMMMMMMMMMMMM$C4MM* \
$C3 *MMMMMMMMMMMMMM* \
$C3 ****** "
#define ASCII_ALLWINNER \
"$C1 \
$C1 ################# \
$C1 .######## ##### #### \
$C1 ###### ####### \
$C1 #####. ## ..## ####. \
$C1 .#### #### ##### #### \
$C1 #### ## ### ###. ##### . \
$C1#### ## ## #### .###### ####* . \
$C1### ## ##.### ## #### .###### \
$C1### #.## ### ##### ##### . \
$C1### ### ### .### ### . \
$C1 #### ### #### #. \
$C1 #### #* \
$C1 ##### ##. \
$C1 ###########. \
$C1 "
#define ASCII_ROCKCHIP \
"$C1 \
$C1 $C2## \
$C1 ###### ## ## \
$C1 ##. ### ##### ##### ## .## ##### ######. ## ##### \
$C1 #######. ##. # #. ##### ##. ### ### # .## \
$C1##. ###. ####. #### ### .## #### ### ### #.##### \
$C1 ## \
$C1 "
#define ASCII_RISCV \
"$C1 \
$C1 ************ \
$C1 %%%%%%%%% *********** \
$C1 %%%%%%%%%% ********** \
$C1 %%%%%%%%% ********* \
$C1 % ******** \
$C1 %% .********* % \
$C1 %%%% ******* %%% \
$C1 %%%%%%. **** %%%%% \
$C1 %%%%%%%%. %%%%%%% \
$C1 \
$C1 \
$C1 ########### ## .######### ######### .## ## \
$C1 ## ## ## ## ## ### ### \
$C1 ########### ## ##########. ## #### .## ## \
$C1 ## ### ## ##. ## ### ### \
$C1 ## ### ## ##########. ########## ### \
$C1 "
#define ASCII_SIFIVE \
"$C1 ############################################## \
$C1 ###########@@@@@@@@@@@@@@@@@@@@@@@@########### \
$C1 #########@@@@@@@@@@@@@@@@@@@@@@@@@@@@######### \
$C1 ########@@@@######################@@@@######## \
$C1 #######@@@@########################@@@@####### \
$C1 ######@@@@##########################@@@@###### \
$C1 #####@@@@#######@@@@@@@@@@@@@@@@@@@@@@@@@##### \
$C1 ####@@@@#######@@@@@@@@@@@@@@@@@@@@@@@@@@@#### \
$C1 ###@@@@################################@@@@### \
$C1 ##@@@@##################################@@@@## \
$C1 #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#########@@@@# \
$C1 #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@###########@@@@# \
$C1 ##@@@@@@############@@@@@@############@@@@@@## \
$C1 ######@@@@@###########@@###########@@@@@###### \
$C1 #########@@@@@@################@@@@@@######### \
$C1 #############@@@@@##########@@@@@############# \
$C1 ################@@@@@@##@@@@@@################ \
$C1 ####################@@@@@@#################### \
$C1 ############################################## "
#define ASCII_STARFIVE \
"$C1 # \
$C1 ########## \
$C1 ######## ######## \
$C1 ######## #### \
$C1 ####### #### \
$C1 #### ####### \
$C1 #### ##### ####### \
$C1 ####### ######## .## \
$C1 ######## ######## \
$C1 ### ########. ####### \
$C1 ####### ##### #### \
$C1 ######## #. #### \
$C1 # #### ####### \
$C1 ##### ####### \
$C1 ######## ######## \
$C1 ######### \
$C1 # "
#define ASCII_SIPEED \
"$C1 #################################### \
$C1######@@################################ \
$C1####@@##@@####@@@@@@@@@@@@@@@@########## \
$C1######@@####@@@@@@@@@@@@@@@@@@########## \
$C1#########@@@@########################### \
$C1#######@@@@@@########################### \
$C1#########@@@@########################### \
$C1###########@@@@@@@@@@@@@@@############## \
$C1##############@@@@@@@@@@@@@@@########### \
$C1###########################@@@@@######## \
$C1###########################@@@@@@####### \
$C1###########################@@@@@######## \
$C1##########@@@@@@@@@@@@@@@@@@@########### \
$C1##########@@@@@@@@@@@@@@@@############## \
$C1######################################## \
$C1 #################################### "
#define ASCII_NVIDIA \
"$C1 'cccccccccccccccccccccccccc \
$C1 ;oooooooooooooooooooooooool \
$C1 .:::. .oooooooooooooooooool \
$C1 .:cll; ,c:::. cooooooooooooool \
$C1 ,clo' ;. oolc: ooooooooooool \
$C1.cloo ;cclo . .olc. coooooooool \
$C1oooo :lo, ;ll; looc :oooooooool \
$C1 oooc ool. ;oooc;clol :looooooooool \
$C1 :ooc ,ol; ;oooooo. .cloo; loool \
$C1 ool; .olc. ,:lool .lool \
$C1 ool:. ,::::ccloo. :clooool \
$C1 oolc::. ':cclooooooool \
$C1 ;oooooooooooooooooooooooool \
$C1 \
$C1 \
$C2######. ## ## ## ###### ## ### \
$C2## ## ## ## ## ## ## ## #: :# \
$C2## ## ## ## ## ## ## ## ####### \
$C2## ## ### ## ###### ## ## ## "
#define ASCII_AMPERE \
"$C1 \
$C1 \
$C1 ## \
$C1 #### \
$C1 ### ## \
$C1 ### ### \
$C1 ### ### \
$C1 ### ### \
$C1 ## ### \
$C1 ####### ### ### \
$C1 ###### ## ###### ### \
$C1 #### ### ######## \
$C1 #### ### #### \
$C1 ### ### #### \
$C1 ## ### ### \
$C1 \
$C1 "
#define ASCII_NXP \
"$C1##### # $C2####### ####### $C3########## \
$C1####### ## $C2####### ####### $C3############### \
$C1########## #### $C2###### ###### $C3### ###### \
$C1############ ##### $C2############ $C3##### ##### \
$C1##### ####### ##### $C2########## $C3################### \
$C1##### ######### $C2############## $C3############### \
$C1##### ###### $C2###### ###### $C3#### \
$C1##### ## $C2###### ###### $C3## "
#define ASCII_AMLOGIC \
"$C1 .#####. ### ### \
$C1 ######## ### \
$C1 ####..### ########## ### ### ##### ### ### \
$C1 .## #. ### ## ## ## ### ## ## ## ## ### ## \
$C1 #### #.# ### ## ## ## ### ## ## ## ## ### ## \
$C1#########.### ## ## ## ## ### ###### ## ### \
$C1 ### \
$C1 ### "
// --------------------- LONG LOGOS ------------------------- // // --------------------- LONG LOGOS ------------------------- //
#define ASCII_AMD_L \ #define ASCII_AMD_L \
"$C1 \ "$C1 \
@@ -302,28 +517,110 @@ $C1 ############ ################## ######### #### ######### \
$C1 \ $C1 \
$C1 ############ ################ ######### ## ######### " $C1 ############ ################ ######### ## ######### "
#define ASCII_SIFIVE_L \
"$C1 ################################################### \
$C1 ###########@@@@@@@@@@@@@@@@@@@@@@@@@@@@############ \
$C1 ##########@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@########### \
$C1 #########@@@@@#######################@@@@########## \
$C1 ########@@@@@#########################@@@@######### \
$C1 #######@@@@@###########################@@@@######## \
$C1 ######@@@@@########@@@@@@@@@@@@@@@@@@@@@@@@@####### \
$C1 #####@@@@@########@@@@@@@@@@@@@@@@@@@@@@@@@@@###### \
$C1 ####@@@@@################################@@@@@##### \
$C1 ###@@@@@##################################@@@@@#### \
$C1 ##@@@@@####################################@@@@@### \
$C1 ##@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#########@@@@### \
$C1 ##@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@############@@@@### \
$C1 ####@@@@@#############@@@@@@@############@@@@@##### \
$C1 #######@@@@@@############@############@@@@@@####### \
$C1 ##########@@@@@@###################@@@@@@########## \
$C1 ##############@@@@@@###########@@@@@@############## \
$C1 #################@@@@@@#####@@@@@@################# \
$C1 ####################@@@@@@@@@@@#################### \
$C1 ########################@@@######################## \
$C1 ################################################### "
#define ASCII_STARFIVE_L \
"$C1 ####### \
$C1 ################. \
$C1 ############ ########### \
$C1 ############ ##########. \
$C1 ############ # ###### \
$C1 ########### ##### ## \
$C1 #######. ########## \
$C1 ###### ### *########### \
$C1 ###### #######. ########## \
$C1 ######### ############ ###### \
$C1 ###########. ###########* # \
$C1 ############ ############ \
$C1 # ############. .########### \
$C1 ###### ########### ######### \
$C1 ########## .######, ##### \
$C1 ############ ##. #####. \
$C1 ######### ######## \
$C1 ## ##### ##########. \
$C1 ####### # ############ \
$C1 ########### ###########. \
$C1 ###########. ############ \
$C1 ################ \
$C1 ####### "
#define ASCII_NVIDIA_L \
"$C1 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM \
$C1 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM \
$C1 .:: 'MMMMMMMMMMMMMMMMMMMMMMMMM \
$C1 ccllooo;:;. ;MMMMMMMMMMMMMMMMMM \
$C1 cloc :ooollcc: :MMMMMMMMMMMMMMM \
$C1 cloc :ccl; lolc, ;MMMMMMMMMMMM \
$C1.cloo: :clo ;c: .ool; MMMMMMMMMMM \
$C1 ooo: ooo :ool, .cloo. ;lMMMMMMMMMMM \
$C1 ooo: ooc :ooooccooo. :MMMM lMMMMMMM \
$C1 ooc. ool: :oooooo' ,cloo. MMMM \
$C1 ool:. olc: .:cloo. :MMMM \
$C1 olc, ;:::cccloo. :MMMMMMMM \
$C1 olcc::; ,:ccloMMMMMMMMM \
$C1 :......oMMMMMMMMMMMMMMMMMMMMMM \
$C1 :lllMMMMMMMMMMMMMMMMMMMMMMMMMM "
typedef struct ascii_logo asciiL; typedef struct ascii_logo asciiL;
// ------------------------------------------------------------------------------------------------------+ // +-----------------------------------------------------------------------------------------------------------------+
// | LOGO | W | H | REPLACE | COLORS LOGO (>0 && <10) | COLORS TEXT (=2) | // | LOGO | W | H | REPLACE | COLORS LOGO (>0 && <10) | COLORS TEXT (=2) |
// ------------------------------------------------------------------------------------------------------+ // +-----------------------------------------------------------------------------------------------------------------+
asciiL logo_amd = { ASCII_AMD, 39, 15, false, {C_FG_WHITE, C_FG_GREEN}, {C_FG_WHITE, C_FG_GREEN} }; asciiL logo_amd = { ASCII_AMD, 39, 15, false, {C_FG_WHITE, C_FG_GREEN}, {C_FG_WHITE, C_FG_GREEN} };
asciiL logo_intel = { ASCII_INTEL, 48, 14, false, {C_FG_CYAN}, {C_FG_CYAN, C_FG_WHITE} }; asciiL logo_intel = { ASCII_INTEL, 48, 14, false, {C_FG_CYAN}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_intel_new = { ASCII_INTEL_NEW, 51, 9, false, {C_FG_CYAN}, {C_FG_CYAN, C_FG_WHITE} }; asciiL logo_intel_new = { ASCII_INTEL_NEW, 51, 9, false, {C_FG_CYAN}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_snapd = { ASCII_SNAPD, 39, 16, false, {C_FG_RED, C_FG_WHITE}, {C_FG_RED, C_FG_WHITE} }; asciiL logo_hygon = { ASCII_HYGON, 51, 11, false, {C_FG_RED}, {C_FG_RED, C_FG_WHITE} };
asciiL logo_mtk = { ASCII_MTK, 59, 5, false, {C_FG_BLUE, C_FG_YELLOW}, {C_FG_BLUE, C_FG_YELLOW} }; asciiL logo_snapd = { ASCII_SNAPD, 39, 16, false, {C_FG_RED, C_FG_WHITE}, {C_FG_RED, C_FG_WHITE} };
asciiL logo_exynos = { ASCII_EXYNOS, 22, 13, true, {C_BG_BLUE, C_FG_WHITE}, {C_FG_BLUE, C_FG_WHITE} }; asciiL logo_mtk = { ASCII_MTK, 59, 5, false, {C_FG_BLUE, C_FG_YELLOW}, {C_FG_BLUE, C_FG_YELLOW} };
asciiL logo_kirin = { ASCII_KIRIN, 53, 12, false, {C_FG_RED}, {C_FG_WHITE, C_FG_RED} }; asciiL logo_exynos = { ASCII_EXYNOS, 22, 13, true, {C_BG_BLUE, C_FG_WHITE}, {C_FG_BLUE, C_FG_WHITE} };
asciiL logo_broadcom = { ASCII_BROADCOM, 44, 19, false, {C_FG_WHITE, C_FG_RED}, {C_FG_WHITE, C_FG_RED} }; asciiL logo_kirin = { ASCII_KIRIN, 53, 12, false, {C_FG_RED}, {C_FG_WHITE, C_FG_RED} };
asciiL logo_arm = { ASCII_ARM, 42, 5, false, {C_FG_CYAN}, {C_FG_WHITE, C_FG_CYAN} }; asciiL logo_kunpeng = { ASCII_KUNPENG, 48, 17, false, {C_FG_RED, C_FG_WHITE}, {C_FG_WHITE, C_FG_RED} };
asciiL logo_ibm = { ASCII_IBM, 42, 9, false, {C_FG_CYAN, C_FG_WHITE}, {C_FG_CYAN, C_FG_WHITE} }; asciiL logo_broadcom = { ASCII_BROADCOM, 44, 19, false, {C_FG_WHITE, C_FG_RED}, {C_FG_WHITE, C_FG_RED} };
asciiL logo_apple = { ASCII_APPLE, 32, 17, false, {C_FG_WHITE}, {C_FG_B_BLACK, C_FG_B_WHITE} }; asciiL logo_arm = { ASCII_ARM, 42, 5, false, {C_FG_CYAN}, {C_FG_WHITE, C_FG_CYAN} };
// Long variants | ----------------------------------------------------------------------------------------------------| asciiL logo_ibm = { ASCII_IBM, 42, 9, false, {C_FG_CYAN, C_FG_WHITE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_amd_l = { ASCII_AMD_L, 62, 19, true, {C_BG_WHITE, C_BG_GREEN}, {C_FG_WHITE, C_FG_GREEN} }; asciiL logo_apple = { ASCII_APPLE, 32, 17, false, {C_FG_WHITE}, {C_FG_CYAN, C_FG_B_WHITE} };
asciiL logo_intel_l = { ASCII_INTEL_L, 62, 19, true, {C_BG_CYAN, C_BG_WHITE}, {C_FG_CYAN, C_FG_WHITE} }; asciiL logo_google = { ASCII_GOOGLE, 35, 15, false, {C_FG_RED, C_FG_YELLOW, C_FG_GREEN, C_FG_BLUE}, {C_FG_BLUE, C_FG_B_WHITE} };
asciiL logo_intel_l_new = { ASCII_INTEL_L_NEW, 57, 14, true, {C_BG_CYAN, C_BG_WHITE, C_BG_BLUE}, {C_FG_CYAN, C_FG_WHITE} }; asciiL logo_allwinner = { ASCII_ALLWINNER, 47, 16, false, {C_FG_CYAN}, {C_FG_B_BLACK, C_FG_B_CYAN } };
asciiL logo_arm_l = { ASCII_ARM_L, 60, 8, true, {C_BG_CYAN}, {C_FG_WHITE, C_FG_CYAN} }; asciiL logo_rockchip = { ASCII_ROCKCHIP, 58, 8, false, {C_FG_CYAN, C_FG_YELLOW}, {C_FG_CYAN, C_FG_YELLOW} };
asciiL logo_ibm_l = { ASCII_IBM_L, 62, 13, true, {C_BG_CYAN, C_FG_WHITE}, {C_FG_CYAN, C_FG_WHITE} }; asciiL logo_riscv = { ASCII_RISCV, 63, 18, false, {C_FG_CYAN, C_FG_YELLOW}, {C_FG_CYAN, C_FG_YELLOW} };
asciiL logo_unknown = { NULL, 0, 0, false, {COLOR_NONE}, {COLOR_NONE, COLOR_NONE} }; asciiL logo_sifive = { ASCII_SIFIVE, 48, 19, true, {C_BG_WHITE, C_BG_BLACK}, {C_FG_WHITE, C_FG_BLUE} };
asciiL logo_starfive = { ASCII_STARFIVE, 33, 17, false, {C_FG_WHITE}, {C_FG_WHITE, C_FG_BLUE} };
asciiL logo_sipeed = { ASCII_SIPEED, 41, 16, true, {C_BG_RED, C_BG_WHITE}, {C_FG_RED, C_FG_WHITE} };
asciiL logo_nvidia = { ASCII_NVIDIA, 45, 19, false, {C_FG_GREEN, C_FG_WHITE}, {C_FG_WHITE, C_FG_GREEN} };
asciiL logo_ampere = { ASCII_AMPERE, 50, 17, false, {C_FG_RED}, {C_FG_WHITE, C_FG_RED} };
asciiL logo_nxp = { ASCII_NXP, 55, 8, false, {C_FG_YELLOW, C_FG_CYAN, C_FG_GREEN}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_amlogic = { ASCII_AMLOGIC, 58, 8, false, {C_FG_BLUE}, {C_FG_BLUE, C_FG_B_WHITE} };
// Long variants | ----------------------------------------------------------------------------------------------------------------|
asciiL logo_amd_l = { ASCII_AMD_L, 62, 19, true, {C_BG_WHITE, C_BG_GREEN}, {C_FG_WHITE, C_FG_GREEN} };
asciiL logo_intel_l = { ASCII_INTEL_L, 62, 19, true, {C_BG_CYAN, C_BG_WHITE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_intel_l_new = { ASCII_INTEL_L_NEW, 57, 14, true, {C_BG_CYAN, C_BG_WHITE, C_BG_BLUE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_arm_l = { ASCII_ARM_L, 60, 8, true, {C_BG_CYAN}, {C_FG_WHITE, C_FG_CYAN} };
asciiL logo_ibm_l = { ASCII_IBM_L, 62, 13, true, {C_BG_CYAN, C_FG_WHITE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_starfive_l = { ASCII_STARFIVE_L, 50, 22, false, {C_FG_WHITE}, {C_FG_WHITE, C_FG_BLUE} };
asciiL logo_sifive_l = { ASCII_SIFIVE_L, 53, 21, true, {C_BG_WHITE, C_BG_BLACK}, {C_FG_WHITE, C_FG_CYAN} };
asciiL logo_nvidia_l = { ASCII_NVIDIA_L, 50, 15, false, {C_FG_GREEN, C_FG_WHITE}, {C_FG_WHITE, C_FG_GREEN} };
asciiL logo_unknown = { NULL, 0, 0, false, {COLOR_NONE}, {COLOR_NONE, COLOR_NONE} };
#endif #endif

View File

@@ -14,10 +14,10 @@
#include "../ppc/uarch.h" #include "../ppc/uarch.h"
#elif ARCH_ARM #elif ARCH_ARM
#include "../arm/uarch.h" #include "../arm/uarch.h"
#elif ARCH_RISCV
#include "../riscv/uarch.h"
#endif #endif
#define UNUSED(x) (void)(x)
#define STRING_YES "Yes" #define STRING_YES "Yes"
#define STRING_NO "No" #define STRING_NO "No"
#define STRING_NONE "None" #define STRING_NONE "None"
@@ -145,17 +145,25 @@ char* get_str_l3(struct cache* cach) {
char* get_str_freq(struct frequency* freq) { char* get_str_freq(struct frequency* freq) {
//Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0' //Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0'
uint32_t size = (5+1+3+1); uint32_t size = (1+5+1+3+1);
assert(strlen(STRING_UNKNOWN)+1 <= size); assert(strlen(STRING_UNKNOWN)+1 <= size);
char* string = emalloc(sizeof(char)*size); char* string = ecalloc(size, sizeof(char));
memset(string, 0, sizeof(char)*size);
if(freq->max == UNKNOWN_FREQ || freq->max < 0) if(freq->max == UNKNOWN_DATA || freq->max < 0) {
snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN); snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN);
else if(freq->max >= 1000) }
snprintf(string,size,"%.3f "STRING_GIGAHERZ,(float)(freq->max)/1000); else if(freq->max >= 1000) {
else if (freq->measured)
snprintf(string,size,"%d "STRING_MEGAHERZ,freq->max); snprintf(string,size,"~%.3f "STRING_GIGAHERZ,(float)(freq->max)/1000);
else
snprintf(string,size,"%.3f "STRING_GIGAHERZ,(float)(freq->max)/1000);
}
else {
if (freq->measured)
snprintf(string,size,"~%d "STRING_MEGAHERZ,freq->max);
else
snprintf(string,size,"%d "STRING_MEGAHERZ,freq->max);
}
return string; return string;
} }
@@ -194,7 +202,7 @@ void init_topology_struct(struct topology* topo, struct cache* cach) {
topo->sockets = 0; topo->sockets = 0;
#ifdef ARCH_X86 #ifdef ARCH_X86
topo->smt_available = 0; topo->smt_available = 0;
topo->apic = emalloc(sizeof(struct apic)); topo->apic = ecalloc(1, sizeof(struct apic));
#endif #endif
#endif #endif
} }

View File

@@ -8,6 +8,7 @@ enum {
// ARCH_X86 // ARCH_X86
CPU_VENDOR_INTEL, CPU_VENDOR_INTEL,
CPU_VENDOR_AMD, CPU_VENDOR_AMD,
CPU_VENDOR_HYGON,
// ARCH_ARM // ARCH_ARM
CPU_VENDOR_ARM, CPU_VENDOR_ARM,
CPU_VENDOR_APPLE, CPU_VENDOR_APPLE,
@@ -16,9 +17,14 @@ enum {
CPU_VENDOR_NVIDIA, CPU_VENDOR_NVIDIA,
CPU_VENDOR_APM, CPU_VENDOR_APM,
CPU_VENDOR_QUALCOMM, CPU_VENDOR_QUALCOMM,
CPU_VENDOR_HUAWUEI, CPU_VENDOR_HUAWEI,
CPU_VENDOR_SAMSUNG, CPU_VENDOR_SAMSUNG,
CPU_VENDOR_MARVELL, CPU_VENDOR_MARVELL,
CPU_VENDOR_PHYTIUM,
// ARCH_RISCV
CPU_VENDOR_RISCV,
CPU_VENDOR_SIFIVE,
CPU_VENDOR_THEAD,
// OTHERS // OTHERS
CPU_VENDOR_UNKNOWN, CPU_VENDOR_UNKNOWN,
CPU_VENDOR_INVALID CPU_VENDOR_INVALID
@@ -27,14 +33,24 @@ enum {
enum { enum {
HV_VENDOR_KVM, HV_VENDOR_KVM,
HV_VENDOR_QEMU, HV_VENDOR_QEMU,
HV_VENDOR_VBOX,
HV_VENDOR_HYPERV, HV_VENDOR_HYPERV,
HV_VENDOR_VMWARE, HV_VENDOR_VMWARE,
HV_VENDOR_XEN, HV_VENDOR_XEN,
HV_VENDOR_PARALLELS, HV_VENDOR_PARALLELS,
HV_VENDOR_PHYP,
HV_VENDOR_BHYVE,
HV_VENDOR_APPLEVZ,
HV_VENDOR_INVALID HV_VENDOR_INVALID
}; };
#define UNKNOWN_FREQ -1 enum {
CORE_TYPE_EFFICIENCY,
CORE_TYPE_PERFORMANCE,
CORE_TYPE_UNKNOWN
};
#define UNKNOWN_DATA -1
#define CPU_NAME_MAX_LENGTH 64 #define CPU_NAME_MAX_LENGTH 64
typedef int32_t VENDOR; typedef int32_t VENDOR;
@@ -42,6 +58,8 @@ typedef int32_t VENDOR;
struct frequency { struct frequency {
int32_t base; int32_t base;
int32_t max; int32_t max;
// Indicates if max frequency was measured
bool measured;
}; };
struct hypervisor { struct hypervisor {
@@ -71,12 +89,13 @@ struct topology {
int32_t total_cores; int32_t total_cores;
struct cache* cach; struct cache* cach;
#if defined(ARCH_X86) || defined(ARCH_PPC) #if defined(ARCH_X86) || defined(ARCH_PPC)
uint32_t physical_cores; int32_t physical_cores;
uint32_t logical_cores; int32_t logical_cores;
uint32_t sockets; uint32_t sockets;
uint32_t smt_supported; // Number of SMT that CPU supports (equal to smt_available if SMT is enabled) uint32_t smt_supported; // Number of SMT that CPU supports (equal to smt_available if SMT is enabled)
#ifdef ARCH_X86 #ifdef ARCH_X86
uint32_t smt_available; // Number of SMT that is currently enabled uint32_t smt_available; // Number of SMT that is currently enabled
int32_t total_cores_module; // Total cores in the current module (only makes sense in hybrid archs, like ADL)
struct apic* apic; struct apic* apic;
#endif #endif
#endif #endif
@@ -105,19 +124,34 @@ struct features {
bool SHA1; bool SHA1;
bool SHA2; bool SHA2;
bool CRC32; bool CRC32;
bool SVE;
bool SVE2;
uint64_t cntb;
#endif #endif
}; };
struct extensions {
char* str;
uint64_t mask;
};
struct cpuInfo { struct cpuInfo {
VENDOR cpu_vendor; VENDOR cpu_vendor;
struct uarch* arch; struct uarch* arch;
struct hypervisor* hv; struct hypervisor* hv;
struct frequency* freq; struct frequency* freq;
struct cache* cach; struct cache* cach;
struct topology* topo; struct topology* topo;
struct features* feat;
int64_t peak_performance; int64_t peak_performance;
// Similar but not exactly equal
// to struct features
#ifdef ARCH_RISCV
struct extensions* ext;
#else
struct features* feat;
#endif
#if defined(ARCH_X86) || defined(ARCH_PPC) #if defined(ARCH_X86) || defined(ARCH_PPC)
// CPU name from model // CPU name from model
char* cpu_name; char* cpu_name;
@@ -130,6 +164,10 @@ struct cpuInfo {
uint32_t maxExtendedLevels; uint32_t maxExtendedLevels;
// Topology Extensions (AMD only) // Topology Extensions (AMD only)
bool topology_extensions; bool topology_extensions;
// Hybrid Flag (Intel only)
bool hybrid_flag;
// Core Type (P/E)
uint32_t core_type;
#elif ARCH_PPC #elif ARCH_PPC
uint32_t pvr; uint32_t pvr;
#elif ARCH_ARM #elif ARCH_ARM
@@ -137,13 +175,20 @@ struct cpuInfo {
uint32_t midr; uint32_t midr;
#endif #endif
#ifdef ARCH_ARM #if defined(ARCH_ARM) || defined(ARCH_RISCV)
struct system_on_chip* soc; struct system_on_chip* soc;
#endif
#if defined(ARCH_X86) || defined(ARCH_ARM)
// If SoC contains more than one CPU and they // If SoC contains more than one CPU and they
// are different, the others will be stored in // are different, the others will be stored in
// the next_cpu field // the next_cpu field
struct cpuInfo* next_cpu; struct cpuInfo* next_cpu;
uint8_t num_cpus; uint8_t num_cpus;
#ifdef ARCH_X86
// The index of the first core in the module
uint32_t first_core_id;
#endif
#endif #endif
}; };

195
src/common/freq.c Normal file
View File

@@ -0,0 +1,195 @@
#ifdef __linux__
#define _GNU_SOURCE
#include <time.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include "global.h"
#include "cpu.h"
static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags) {
int ret;
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}
#define INSERT_ASM_ONCE __asm volatile("nop");
#define INSERT_ASM_10_TIMES \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
INSERT_ASM_ONCE \
#define INSERT_ASM_100_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES \
INSERT_ASM_10_TIMES
#define INSERT_ASM_1000_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
INSERT_ASM_100_TIMES \
void nop_function(uint64_t iters) {
for (uint64_t i = 0; i < iters; i++) {
INSERT_ASM_1000_TIMES
INSERT_ASM_1000_TIMES
INSERT_ASM_1000_TIMES
INSERT_ASM_1000_TIMES
}
}
// Run the nop_function with the number of iterations specified and
// measure both the time and number of cycles
int measure_freq_iters(uint64_t iters, uint32_t core, double* freq) {
clockid_t clock = CLOCK_PROCESS_CPUTIME_ID;
struct timespec start, end;
struct perf_event_attr pe;
uint64_t cycles;
int fd;
int pid = 0;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_CPU_CYCLES;
pe.disabled = 1;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;
fd = perf_event_open(&pe, pid, core, -1, 0);
if (fd == -1) {
perror("perf_event_open");
if (errno == EPERM || errno == EACCES) {
printErr("You may not have permission to collect stats.\n"\
"Consider tweaking /proc/sys/kernel/perf_event_paranoid or running as root");
}
return -1;
}
if (clock_gettime(clock, &start) == -1) {
perror("clock_gettime");
return -1;
}
if(ioctl(fd, PERF_EVENT_IOC_RESET, 0) == -1) {
perror("ioctl");
return -1;
}
if(ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) == -1) {
perror("ioctl");
return -1;
}
nop_function(iters);
ssize_t ret = read(fd, &cycles, sizeof(uint64_t));
if (ret == -1) {
perror("read");
return -1;
}
if (ret != sizeof(uint64_t)) {
printErr("Read returned %d, expected %d", ret, sizeof(uint64_t));
return -1;
}
if(ioctl(fd, PERF_EVENT_IOC_DISABLE, 0) == -1) {
perror("ioctl");
return -1;
}
if (clock_gettime(clock, &end) == -1) {
perror("clock_gettime");
return -1;
}
uint64_t nsecs = (end.tv_sec*1e9 + end.tv_nsec) - (start.tv_sec*1e9 + start.tv_nsec);
uint64_t usecs = nsecs/1000;
*freq = cycles/((double)usecs);
return 0;
}
// Return a good number of iterations to run the nop_function in
// order to get a precise measurement of the frequency without taking
// too much time.
uint64_t get_num_iters_from_freq(double frequency) {
// Truncate to reduce variability
uint64_t freq_trunc = ((uint64_t) frequency / 100) * 100;
uint64_t osp_per_iter = 4 * 1000;
return freq_trunc * 1e7 * 1/osp_per_iter;
}
// Differences between x86 measure_frequency and this measure_max_frequency:
// - measure_frequency employs all cores simultaneously whereas
// measure_max_frequency only employs 1.
// - measure_frequency runs the computation and checks /proc/cpuinfo whereas
// measure_max_frequency does not rely on /proc/cpuinfo and simply
// counts cpu cycles to measure frequency.
// - measure_frequency uses actual computation while measuring the frequency
// whereas measure_max_frequency uses nop instructions. This makes the former
// x86 dependant whereas the latter is architecture independant.
int64_t measure_max_frequency(uint32_t core) {
if (!bind_to_cpu(core)) {
printErr("Failed binding the process to CPU %d", core);
return UNKNOWN_DATA;
}
// First, get very rough estimation of clock cycle to
// compute a reasonable value for the iterations
double estimation_freq, frequency;
uint64_t iters = 100000;
if (measure_freq_iters(iters, core, &estimation_freq) == -1)
return UNKNOWN_DATA;
if (estimation_freq <= 0.0) {
printErr("First frequency measurement yielded an invalid value: %f", estimation_freq);
return UNKNOWN_DATA;
}
iters = get_num_iters_from_freq(estimation_freq);
printWarn("Running frequency measurement with %ld iterations on core %d...", iters, core);
// Now perform actual measurement
const char* frequency_banner = "cpufetch is measuring the max frequency...";
printf("%s", frequency_banner);
fflush(stdout);
if (measure_freq_iters(iters, core, &frequency) == -1)
return UNKNOWN_DATA;
// Clean screen once measurement is finished
printf("\r%*c\r", (int) strlen(frequency_banner), ' ');
// Discard last digit in the frequency, which should help providing
// more reliable and predictable values.
return (((int) frequency + 5)/10) * 10;
}
#endif // #ifdef __linux__

6
src/common/freq.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __COMMON_FREQ__
#define __COMMON_FREQ__
int64_t measure_max_frequency(uint32_t core);
#endif

View File

@@ -1,3 +1,14 @@
#ifdef _WIN32
#define NOMINMAX
#include <windows.h>
#elif defined __linux__
#define _GNU_SOURCE
#include <sched.h>
#elif defined __FreeBSD__
#include <sys/param.h>
#include <sys/cpuset.h>
#endif
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -20,6 +31,40 @@
#endif #endif
#ifdef ARCH_X86
static const char* ARCH_STR = "x86 / x86_64 build";
#include "../x86/cpuid.h"
#elif ARCH_PPC
static const char* ARCH_STR = "PowerPC build";
#include "../ppc/ppc.h"
#elif ARCH_ARM
static const char* ARCH_STR = "ARM build";
#include "../arm/midr.h"
#elif ARCH_RISCV
static const char* ARCH_STR = "RISC-V build";
#include "../riscv/riscv.h"
#endif
#ifdef __linux__
#ifdef __ANDROID__
static const char* OS_STR = "Android";
#else
static const char* OS_STR = "Linux";
#endif
#elif __FreeBSD__
static const char* OS_STR = "FreeBSD";
#elif _WIN32
static const char* OS_STR = "Windows";
#elif defined __APPLE__ || __MACH__
static const char* OS_STR = "macOS";
#else
static const char* OS_STR = "Unknown OS";
#endif
#ifndef GIT_FULL_VERSION
static const char* VERSION = "1.06";
#endif
enum { enum {
LOG_LEVEL_NORMAL, LOG_LEVEL_NORMAL,
LOG_LEVEL_VERBOSE LOG_LEVEL_VERBOSE
@@ -27,6 +72,14 @@ enum {
int LOG_LEVEL; int LOG_LEVEL;
void printBugMessage(FILE *restrict stream) {
#if defined(ARCH_X86) || defined(ARCH_PPC)
fprintf(stream, "Please, create a new issue with this error message, the output of 'cpufetch' and 'cpufetch --debug' on https://github.com/Dr-Noob/cpufetch/issues\n");
#elif ARCH_ARM
fprintf(stream, "Please, create a new issue with this error message, your smartphone/computer model, the output of 'cpufetch --verbose' and 'cpufetch --debug' on https://github.com/Dr-Noob/cpufetch/issues\n");
#endif
}
void printWarn(const char *fmt, ...) { void printWarn(const char *fmt, ...) {
if(LOG_LEVEL == LOG_LEVEL_VERBOSE) { if(LOG_LEVEL == LOG_LEVEL_VERBOSE) {
int buffer_size = 4096; int buffer_size = 4096;
@@ -47,6 +100,8 @@ void printErr(const char *fmt, ...) {
vsnprintf(buffer,buffer_size, fmt, args); vsnprintf(buffer,buffer_size, fmt, args);
va_end(args); va_end(args);
fprintf(stderr,RED "[ERROR]: "RESET "%s\n",buffer); fprintf(stderr,RED "[ERROR]: "RESET "%s\n",buffer);
fprintf(stderr,"[VERSION]: ");
print_version(stderr);
} }
void printBug(const char *fmt, ...) { void printBug(const char *fmt, ...) {
@@ -57,10 +112,42 @@ void printBug(const char *fmt, ...) {
vsnprintf(buffer,buffer_size, fmt, args); vsnprintf(buffer,buffer_size, fmt, args);
va_end(args); va_end(args);
fprintf(stderr,RED "[ERROR]: "RESET "%s\n",buffer); fprintf(stderr,RED "[ERROR]: "RESET "%s\n",buffer);
#if defined(ARCH_X86) || defined(ARCH_PPC) fprintf(stderr,"[VERSION]: ");
fprintf(stderr,"Please, create a new issue with this error message and the output of 'cpufetch --debug' on https://github.com/Dr-Noob/cpufetch/issues\n"); print_version(stderr);
#elif ARCH_ARM printBugMessage(stderr);
fprintf(stderr,"Please, create a new issue with this error message, your smartphone/computer model and the output of 'cpufetch --debug' on https://github.com/Dr-Noob/cpufetch/issues\n"); }
bool isReleaseVersion(char *git_full_version) {
return strstr(git_full_version, "-") == NULL;
}
/// The unknown uarch errors are by far the most common error a user will encounter.
/// Rather than using the generic printBug function, which asks the user to report
/// the problem on the issues webpage, this function will check if the program is
/// the release version. In such case, support for this feature is most likely already
/// in the last version, so just tell the user to compile that one and not report this
/// in github.
void printBugCheckRelease(const char *fmt, ...) {
int buffer_size = 4096;
char buffer[buffer_size];
va_list args;
va_start(args, fmt);
vsnprintf(buffer,buffer_size, fmt, args);
va_end(args);
fprintf(stderr, RED "[ERROR]: "RESET "%s\n", buffer);
fprintf(stderr, "[VERSION]: ");
print_version(stderr);
#ifdef GIT_FULL_VERSION
if (isReleaseVersion(GIT_FULL_VERSION)) {
fprintf(stderr, RED "[ERROR]: "RESET "You are using an outdated version of cpufetch. Please compile cpufetch from source (see https://github.com/Dr-Noob/cpufetch?tab=readme-ov-file#22-building-from-source)");
}
else {
printBugMessage(stderr);
}
#else
printBugMessage(stderr);
#endif #endif
} }
@@ -111,3 +198,50 @@ void* ecalloc(size_t nmemb, size_t size) {
return ptr; return ptr;
} }
void* erealloc(void *ptr, size_t size) {
void* newptr = realloc(ptr, size);
if(newptr == NULL) {
printErr("realloc failed: %s", strerror(errno));
exit(1);
}
return newptr;
}
#ifndef __APPLE__
bool bind_to_cpu(int cpu_id) {
#ifdef _WIN32
HANDLE process = GetCurrentProcess();
DWORD_PTR processAffinityMask = 1 << cpu_id;
return SetProcessAffinityMask(process, processAffinityMask);
#elif defined __linux__
cpu_set_t currentCPU;
CPU_ZERO(&currentCPU);
CPU_SET(cpu_id, &currentCPU);
if (sched_setaffinity (0, sizeof(currentCPU), &currentCPU) == -1) {
printWarn("sched_setaffinity: %s", strerror(errno));
return false;
}
return true;
#elif defined __FreeBSD__
cpuset_t currentCPU;
CPU_ZERO(&currentCPU);
CPU_SET(cpu_id, &currentCPU);
if(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &currentCPU) == -1) {
printWarn("cpuset_setaffinity: %s", strerror(errno));
return false;
}
return true;
#endif
}
#endif
void print_version(FILE *restrict stream) {
#ifdef GIT_FULL_VERSION
fprintf(stream, "cpufetch %s (%s %s)\n", GIT_FULL_VERSION, OS_STR, ARCH_STR);
#else
fprintf(stream, "cpufetch v%s (%s %s)\n", VERSION, OS_STR, ARCH_STR);
#endif
}

View File

@@ -1,19 +1,27 @@
#ifndef __GLOBAL__ #ifndef __GLOBAL__
#define __GLOBAL__ #define __GLOBAL__
#include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#define STRING_UNKNOWN "Unknown" #define STRING_UNKNOWN "Unknown"
#define UNUSED(x) (void)(x)
void set_log_level(bool verbose); void set_log_level(bool verbose);
void printWarn(const char *fmt, ...); void printWarn(const char *fmt, ...);
void printErr(const char *fmt, ...); void printErr(const char *fmt, ...);
void printBug(const char *fmt, ...); void printBug(const char *fmt, ...);
void printBugCheckRelease(const char *fmt, ...);
int min(int a, int b); int min(int a, int b);
int max(int a, int b); int max(int a, int b);
char *strremove(char *str, const char *sub); char *strremove(char *str, const char *sub);
void* emalloc(size_t size); void* emalloc(size_t size);
void* ecalloc(size_t nmemb, size_t size); void* ecalloc(size_t nmemb, size_t size);
void* erealloc(void *ptr, size_t size);
#ifndef __APPLE__
bool bind_to_cpu(int cpu_id);
#endif
void print_version(FILE *restrict stream);
#endif #endif

View File

@@ -6,35 +6,6 @@
#include "printer.h" #include "printer.h"
#include "global.h" #include "global.h"
#ifdef ARCH_X86
static const char* ARCH_STR = "x86_64 build";
#include "../x86/cpuid.h"
#elif ARCH_PPC
static const char* ARCH_STR = "PowerPC build";
#include "../ppc/ppc.h"
#elif ARCH_ARM
static const char* ARCH_STR = "ARM build";
#include "../arm/midr.h"
#endif
#ifdef __linux__
#ifdef __ANDROID__
static const char* OS_STR = "Android";
#else
static const char* OS_STR = "Linux";
#endif
#elif __FreeBSD__
static const char* OS_STR = "FreeBSD";
#elif _WIN32
static const char* OS_STR = "Windows";
#elif defined __APPLE__ || __MACH__
static const char* OS_STR = "macOS";
#else
static const char* OS_STR = "Unknown OS";
#endif
static const char* VERSION = "1.00";
void print_help(char *argv[]) { void print_help(char *argv[]) {
const char **t = args_str; const char **t = args_str;
const char *c = args_chr; const char *c = args_chr;
@@ -57,19 +28,31 @@ void print_help(char *argv[]) {
printf(" --%s %*s Show the long version of the logo\n", t[ARG_LOGO_LONG], (int) (max_len-strlen(t[ARG_LOGO_LONG])), ""); printf(" --%s %*s Show the long version of the logo\n", t[ARG_LOGO_LONG], (int) (max_len-strlen(t[ARG_LOGO_LONG])), "");
printf(" -%c, --%s %*s Print extra information (if available) about how cpufetch tried fetching information\n", c[ARG_VERBOSE], t[ARG_VERBOSE], (int) (max_len-strlen(t[ARG_VERBOSE])), ""); printf(" -%c, --%s %*s Print extra information (if available) about how cpufetch tried fetching information\n", c[ARG_VERBOSE], t[ARG_VERBOSE], (int) (max_len-strlen(t[ARG_VERBOSE])), "");
#ifdef ARCH_X86 #ifdef ARCH_X86
#ifdef __linux__
printf(" --%s %*s Compute the peak performance accurately (measure the CPU frequency instead of using the maximum)\n", t[ARG_ACCURATE_PP], (int) (max_len-strlen(t[ARG_ACCURATE_PP])), "");
printf(" --%s %*s Measure the max CPU frequency instead of reading it\n", t[ARG_MEASURE_MAX_FREQ], (int) (max_len-strlen(t[ARG_MEASURE_MAX_FREQ])), "");
#endif // __linux__
printf(" --%s %*s Show the old Intel logo\n", t[ARG_LOGO_INTEL_OLD], (int) (max_len-strlen(t[ARG_LOGO_INTEL_OLD])), ""); printf(" --%s %*s Show the old Intel logo\n", t[ARG_LOGO_INTEL_OLD], (int) (max_len-strlen(t[ARG_LOGO_INTEL_OLD])), "");
printf(" --%s %*s Show the new Intel logo\n", t[ARG_LOGO_INTEL_NEW], (int) (max_len-strlen(t[ARG_LOGO_INTEL_NEW])), ""); printf(" --%s %*s Show the new Intel logo\n", t[ARG_LOGO_INTEL_NEW], (int) (max_len-strlen(t[ARG_LOGO_INTEL_NEW])), "");
printf(" -%c, --%s %*s Show the full CPU name (do not abbreviate it)\n", c[ARG_FULLCPUNAME], t[ARG_FULLCPUNAME], (int) (max_len-strlen(t[ARG_FULLCPUNAME])), ""); printf(" -%c, --%s %*s Show the full CPU name (do not abbreviate it)\n", c[ARG_FULLCPUNAME], t[ARG_FULLCPUNAME], (int) (max_len-strlen(t[ARG_FULLCPUNAME])), "");
printf(" -%c, --%s %*s Print raw cpuid data (debug purposes)\n", c[ARG_RAW], t[ARG_RAW], (int) (max_len-strlen(t[ARG_RAW])), ""); printf(" -%c, --%s %*s Print raw cpuid data (debug purposes)\n", c[ARG_RAW], t[ARG_RAW], (int) (max_len-strlen(t[ARG_RAW])), "");
#endif // ARCH_X86
#ifdef ARCH_ARM
#ifdef __linux__
printf(" --%s %*s Measure the max CPU frequency instead of reading it\n", t[ARG_MEASURE_MAX_FREQ], (int) (max_len-strlen(t[ARG_MEASURE_MAX_FREQ])), "");
#endif
#endif #endif
printf(" -%c, --%s %*s Print this help and exit\n", c[ARG_HELP], t[ARG_HELP], (int) (max_len-strlen(t[ARG_HELP])), ""); printf(" -%c, --%s %*s Print this help and exit\n", c[ARG_HELP], t[ARG_HELP], (int) (max_len-strlen(t[ARG_HELP])), "");
printf(" -%c, --%s %*s Print cpufetch version and exit\n", c[ARG_VERSION], t[ARG_VERSION], (int) (max_len-strlen(t[ARG_VERSION])), ""); printf(" -%c, --%s %*s Print cpufetch version and exit\n", c[ARG_VERSION], t[ARG_VERSION], (int) (max_len-strlen(t[ARG_VERSION])), "");
printf("\nCOLORS: \n"); printf("\nCOLORS: \n");
printf(" * \"intel\": Use Intel default color scheme \n"); printf(" * \"intel\": Use Intel color scheme \n");
printf(" * \"amd\": Use AMD default color scheme \n"); printf(" * \"intel-new\": Use Intel (new logo) color scheme \n");
printf(" * \"ibm\", Use IBM default color scheme \n"); printf(" * \"amd\": Use AMD color scheme \n");
printf(" * \"arm\": Use ARM default color scheme \n"); printf(" * \"ibm\", Use IBM color scheme \n");
printf(" * \"arm\": Use ARM color scheme \n");
printf(" * \"rockchip\": Use Rockchip color scheme \n");
printf(" * \"sifive\": Use SiFive color scheme \n");
printf(" * custom: If the argument of --color does not match any of the previous strings, a custom scheme can be specified.\n"); printf(" * custom: If the argument of --color does not match any of the previous strings, a custom scheme can be specified.\n");
printf(" 5 colors must be given in RGB with the format: R,G,B:R,G,B:...\n"); printf(" 5 colors must be given in RGB with the format: R,G,B:R,G,B:...\n");
printf(" The first 3 colors are the CPU art color and the next 2 colors are the text colors\n"); printf(" The first 3 colors are the CPU art color and the next 2 colors are the text colors\n");
@@ -99,12 +82,15 @@ void print_help(char *argv[]) {
printf("\nNOTE: \n"); printf("\nNOTE: \n");
printf(" Peak performance information is NOT accurate. cpufetch computes peak performance using the max\n"); printf(" Peak performance information is NOT accurate. cpufetch computes peak performance using the max\n");
printf(" frequency of the CPU. However, to compute the peak performance, you need to know the frequency of the\n"); printf(" frequency of the CPU. However, to compute the peak performance, you need to know the frequency of the\n");
printf(" CPU running AVX code. This value is not be fetched by cpufetch since it depends on each specific CPU.\n"); printf(" CPU running AVX code. By default, this value is not fetched by cpufetch, but you can use the\n");
printf(" To correctly measure peak performance, see: https://github.com/Dr-Noob/peakperf\n"); printf(" --accurate-pp option, which will measure the AVX frequency and show a more precise estimation\n");
} printf(" (this option is only available in x86 architectures).\n");
printf(" To precisely measure peak performance, see: https://github.com/Dr-Noob/peakperf\n");
void print_version() { printf("\n");
printf("cpufetch v%s (%s %s)\n",VERSION, OS_STR, ARCH_STR); printf(" Both --accurate-pp and --measure-max-freq measure the actual frequency of the CPU. However,\n");
printf(" they differ slightly. The former measures the max frequency while running vectorized SSE/AVX\n");
printf(" instructions and it is thus x86 only, whereas the latter simply measures the max clock cycle\n");
printf(" and is architecture independent.\n");
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
@@ -117,7 +103,7 @@ int main(int argc, char* argv[]) {
} }
if(show_version()) { if(show_version()) {
print_version(); print_version(stdout);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@@ -128,14 +114,15 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE; return EXIT_FAILURE;
if(show_debug()) { if(show_debug()) {
print_version(); print_version(stdout);
print_debug(cpu); print_debug(cpu);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// TODO: This should be moved to the end of args.c
if(show_raw()) { if(show_raw()) {
#ifdef ARCH_X86 #ifdef ARCH_X86
print_version(); print_version(stdout);
print_raw(cpu); print_raw(cpu);
return EXIT_SUCCESS; return EXIT_SUCCESS;
#else #else
@@ -144,8 +131,10 @@ int main(int argc, char* argv[]) {
#endif #endif
} }
if(print_cpufetch(cpu, get_style(), get_colors(), show_full_cpu_name())) if(print_cpufetch(cpu, get_style(), get_colors(), show_full_cpu_name())) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
else }
else {
return EXIT_FAILURE; return EXIT_FAILURE;
}
} }

133
src/common/pci.c Normal file
View File

@@ -0,0 +1,133 @@
#define _GNU_SOURCE
#include <sys/stat.h>
#include <dirent.h>
#include "udev.h"
#include "global.h"
#include "pci.h"
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#define PCI_PATH "/sys/bus/pci/devices/"
#define MAX_LENGTH_PCI_DIR_NAME 1024
// Return a list of PCI devices containing only
// the sysfs path
struct pci_devices * get_pci_paths(void) {
DIR *dirp;
if ((dirp = opendir(PCI_PATH)) == NULL) {
perror("opendir");
return NULL;
}
struct dirent *dp;
int numDirs = 0;
errno = 0;
while ((dp = readdir(dirp)) != NULL) {
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
numDirs++;
}
if (errno != 0) {
perror("readdir");
return NULL;
}
rewinddir(dirp);
struct pci_devices * pci = emalloc(sizeof(struct pci_devices));
pci->num_devices = numDirs;
pci->devices = emalloc(sizeof(struct pci_device) * pci->num_devices);
char * full_path = emalloc(PATH_MAX * sizeof(char));
struct stat stbuf;
int i = 0;
while ((dp = readdir(dirp)) != NULL) {
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue;
if (strlen(dp->d_name) > MAX_LENGTH_PCI_DIR_NAME) {
printErr("Directory name is too long: %s", dp->d_name);
return NULL;
}
memset(full_path, 0, PATH_MAX * sizeof(char));
snprintf(full_path, min(strlen(PCI_PATH) + strlen(dp->d_name) + 1, PATH_MAX), "%s%s", PCI_PATH, dp->d_name);
if (stat(full_path, &stbuf) == -1) {
perror("stat");
return NULL;
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
int strLen = min(MAX_LENGTH_PCI_DIR_NAME, strlen(dp->d_name)) + 1;
pci->devices[i] = emalloc(sizeof(struct pci_device));
pci->devices[i]->path = ecalloc(strLen, sizeof(char));
strncpy(pci->devices[i]->path, dp->d_name, strLen);
i++;
}
}
if (errno != 0) {
perror("readdir");
return NULL;
}
return pci;
}
// For each PCI device in the list pci, fetch its vendor and
// device id using sysfs (e.g., /sys/bus/pci/devices/XXX/{vendor/device})
void populate_pci_devices(struct pci_devices * pci) {
int filelen;
char* buf;
for (int i=0; i < pci->num_devices; i++) {
struct pci_device* dev = pci->devices[i];
int path_size = strlen(PCI_PATH) + strlen(dev->path) + 2;
// Read vendor_id
char *vendor_id_path = emalloc(sizeof(char) * (path_size + strlen("vendor") + 1));
sprintf(vendor_id_path, "%s/%s/%s", PCI_PATH, dev->path, "vendor");
if ((buf = read_file(vendor_id_path, &filelen)) == NULL) {
printWarn("read_file: %s: %s\n", vendor_id_path, strerror(errno));
dev->vendor_id = 0;
}
else {
dev->vendor_id = strtol(buf, NULL, 16);
}
// Read device_id
char *device_id_path = emalloc(sizeof(char) * (path_size + strlen("device") + 1));
sprintf(device_id_path, "%s/%s/%s", PCI_PATH, dev->path, "device");
if ((buf = read_file(device_id_path, &filelen)) == NULL) {
printWarn("read_file: %s: %s\n", device_id_path, strerror(errno));
dev->device_id = 0;
}
else {
dev->device_id = strtol(buf, NULL, 16);
}
free(vendor_id_path);
free(device_id_path);
}
}
// Return a list of PCI devices that could be used to infer the SoC.
// The criteria to determine which devices are suitable for this task
// is decided in filter_pci_devices.
struct pci_devices * get_pci_devices(void) {
struct pci_devices * pci = get_pci_paths();
if (pci == NULL)
return NULL;
populate_pci_devices(pci);
return pci;
}

23
src/common/pci.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef __PCI__
#define __PCI__
#define PCI_VENDOR_NVIDIA 0x10de
#define PCI_VENDOR_AMPERE 0x1def
#define PCI_DEVICE_TEGRA_X1 0x0faf
#define PCI_DEVICE_ALTRA 0xe100
struct pci_device {
char * path;
uint16_t vendor_id;
uint16_t device_id;
};
struct pci_devices {
struct pci_device ** devices;
int num_devices;
};
struct pci_devices * get_pci_devices(void);
#endif

View File

@@ -16,10 +16,15 @@
#elif ARCH_PPC #elif ARCH_PPC
#include "../ppc/uarch.h" #include "../ppc/uarch.h"
#include "../ppc/ppc.h" #include "../ppc/ppc.h"
#else #elif ARCH_ARM
#include "../arm/uarch.h" #include "../arm/uarch.h"
#include "../arm/midr.h" #include "../arm/midr.h"
#include "../arm/soc.h" #include "../arm/soc.h"
#include "../common/soc.h"
#elif ARCH_RISCV
#include "../riscv/riscv.h"
#include "../riscv/uarch.h"
#include "../riscv/soc.h"
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
@@ -42,8 +47,10 @@
enum { enum {
#if defined(ARCH_X86) || defined(ARCH_PPC) #if defined(ARCH_X86) || defined(ARCH_PPC)
ATTRIBUTE_NAME, ATTRIBUTE_NAME,
#elif ARCH_ARM #elif defined(ARCH_ARM) || defined(ARCH_RISCV)
ATTRIBUTE_SOC, ATTRIBUTE_SOC,
#endif
#if defined(ARCH_X86) || defined(ARCH_ARM)
ATTRIBUTE_CPU_NUM, ATTRIBUTE_CPU_NUM,
#endif #endif
ATTRIBUTE_HYPERVISOR, ATTRIBUTE_HYPERVISOR,
@@ -54,12 +61,15 @@ enum {
ATTRIBUTE_NCORES, ATTRIBUTE_NCORES,
ATTRIBUTE_NCORES_DUAL, ATTRIBUTE_NCORES_DUAL,
#ifdef ARCH_X86 #ifdef ARCH_X86
ATTRIBUTE_SSE,
ATTRIBUTE_AVX, ATTRIBUTE_AVX,
ATTRIBUTE_FMA, ATTRIBUTE_FMA,
#elif ARCH_PPC #elif ARCH_PPC
ATTRIBUTE_ALTIVEC, ATTRIBUTE_ALTIVEC,
#elif ARCH_ARM #elif ARCH_ARM
ATTRIBUTE_FEATURES, ATTRIBUTE_FEATURES,
#elif ARCH_RISCV
ATTRIBUTE_EXTENSIONS,
#endif #endif
ATTRIBUTE_L1i, ATTRIBUTE_L1i,
ATTRIBUTE_L1d, ATTRIBUTE_L1d,
@@ -73,8 +83,10 @@ static const char* ATTRIBUTE_FIELDS [] = {
"Name:", "Name:",
#elif ARCH_PPC #elif ARCH_PPC
"Part Number:", "Part Number:",
#elif ARCH_ARM #elif defined(ARCH_ARM) || defined(ARCH_RISCV)
"SoC:", "SoC:",
#endif
#if defined(ARCH_X86) || defined(ARCH_ARM)
"", "",
#endif #endif
"Hypervisor:", "Hypervisor:",
@@ -85,12 +97,15 @@ static const char* ATTRIBUTE_FIELDS [] = {
"Cores:", "Cores:",
"Cores (Total):", "Cores (Total):",
#ifdef ARCH_X86 #ifdef ARCH_X86
"SSE:",
"AVX:", "AVX:",
"FMA:", "FMA:",
#elif ARCH_PPC #elif ARCH_PPC
"Altivec: ", "Altivec: ",
#elif defined(ARCH_ARM) #elif defined(ARCH_ARM)
"Features: ", "Features: ",
#elif defined(ARCH_RISCV)
"Extensions: ",
#endif #endif
"L1i Size:", "L1i Size:",
"L1d Size:", "L1d Size:",
@@ -106,6 +121,8 @@ static const char* ATTRIBUTE_FIELDS_SHORT [] = {
"P/N:", "P/N:",
#elif ARCH_ARM #elif ARCH_ARM
"SoC:", "SoC:",
#endif
#if defined(ARCH_X86) || defined(ARCH_ARM)
"", "",
#endif #endif
"Hypervisor:", "Hypervisor:",
@@ -116,12 +133,15 @@ static const char* ATTRIBUTE_FIELDS_SHORT [] = {
"Cores:", "Cores:",
"Cores (Total):", "Cores (Total):",
#ifdef ARCH_X86 #ifdef ARCH_X86
"SSE:",
"AVX:", "AVX:",
"FMA:", "FMA:",
#elif ARCH_PPC #elif ARCH_PPC
"Altivec: ", "Altivec: ",
#elif defined(ARCH_ARM) #elif defined(ARCH_ARM)
"Features: ", "Features: ",
#elif defined(ARCH_RISCV)
"Extensions: ",
#endif #endif
"L1i Size:", "L1i Size:",
"L1d Size:", "L1d Size:",
@@ -297,8 +317,6 @@ bool ascii_fits_screen(int termw, struct ascii_logo logo, int lf) {
void replace_bgbyfg_color(struct ascii_logo* logo) { void replace_bgbyfg_color(struct ascii_logo* logo) {
// Replace background by foreground color // Replace background by foreground color
for(int i=0; i < 3; i++) { for(int i=0; i < 3; i++) {
if(logo->color_ascii[i] == NULL) break;
if(strcmp(logo->color_ascii[i], C_BG_BLACK) == 0) strcpy(logo->color_ascii[i], C_FG_BLACK); if(strcmp(logo->color_ascii[i], C_BG_BLACK) == 0) strcpy(logo->color_ascii[i], C_FG_BLACK);
else if(strcmp(logo->color_ascii[i], C_BG_RED) == 0) strcpy(logo->color_ascii[i], C_FG_RED); else if(strcmp(logo->color_ascii[i], C_BG_RED) == 0) strcpy(logo->color_ascii[i], C_FG_RED);
else if(strcmp(logo->color_ascii[i], C_BG_GREEN) == 0) strcpy(logo->color_ascii[i], C_FG_GREEN); else if(strcmp(logo->color_ascii[i], C_BG_GREEN) == 0) strcpy(logo->color_ascii[i], C_FG_GREEN);
@@ -321,6 +339,13 @@ struct ascii_logo* choose_ascii_art_aux(struct ascii_logo* logo_long, struct asc
} }
} }
// https://no-color.org/
bool is_color_enabled(void) {
const char *var_name = "NO_COLOR";
char *no_color = getenv(var_name);
return no_color == NULL || no_color[0] == '\0';
}
void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* term, int lf) { void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* term, int lf) {
// 1. Choose logo // 1. Choose logo
#ifdef ARCH_X86 #ifdef ARCH_X86
@@ -335,6 +360,9 @@ void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* ter
else if(art->vendor == CPU_VENDOR_AMD) { else if(art->vendor == CPU_VENDOR_AMD) {
art->art = choose_ascii_art_aux(&logo_amd_l, &logo_amd, term, lf); art->art = choose_ascii_art_aux(&logo_amd_l, &logo_amd, term, lf);
} }
else if(art->vendor == CPU_VENDOR_HYGON) {
art->art = &logo_hygon;
}
else { else {
art->art = &logo_unknown; art->art = &logo_unknown;
} }
@@ -349,17 +377,47 @@ void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* ter
art->art = &logo_exynos; art->art = &logo_exynos;
else if(art->vendor == SOC_VENDOR_KIRIN) else if(art->vendor == SOC_VENDOR_KIRIN)
art->art = &logo_kirin; art->art = &logo_kirin;
else if(art->vendor == SOC_VENDOR_KUNPENG)
art->art = &logo_kunpeng;
else if(art->vendor == SOC_VENDOR_BROADCOM) else if(art->vendor == SOC_VENDOR_BROADCOM)
art->art = &logo_broadcom; art->art = &logo_broadcom;
else if(art->vendor == SOC_VENDOR_APPLE) else if(art->vendor == SOC_VENDOR_APPLE)
art->art = &logo_apple; art->art = &logo_apple;
else if(art->vendor == SOC_VENDOR_GOOGLE)
art->art = &logo_google;
else if(art->vendor == SOC_VENDOR_ALLWINNER)
art->art = &logo_allwinner;
else if(art->vendor == SOC_VENDOR_ROCKCHIP)
art->art = &logo_rockchip;
else if(art->vendor == SOC_VENDOR_AMPERE)
art->art = &logo_ampere;
else if(art->vendor == SOC_VENDOR_NXP)
art->art = &logo_nxp;
else if(art->vendor == SOC_VENDOR_AMLOGIC)
art->art = &logo_amlogic;
else if(art->vendor == SOC_VENDOR_NVIDIA)
art->art = choose_ascii_art_aux(&logo_nvidia_l, &logo_nvidia, term, lf);
else { else {
art->art = choose_ascii_art_aux(&logo_arm_l, &logo_arm, term, lf); art->art = choose_ascii_art_aux(&logo_arm_l, &logo_arm, term, lf);
} }
#elif ARCH_RISCV
if(art->vendor == SOC_VENDOR_SIFIVE)
art->art = choose_ascii_art_aux(&logo_sifive_l, &logo_sifive, term, lf);
else if(art->vendor == SOC_VENDOR_STARFIVE)
art->art = choose_ascii_art_aux(&logo_starfive_l, &logo_starfive, term, lf);
else if(art->vendor == SOC_VENDOR_ALLWINNER)
art->art = &logo_allwinner;
else if(art->vendor == SOC_VENDOR_SIPEED)
art->art = &logo_sipeed;
else
art->art = &logo_riscv;
#endif #endif
// 2. Choose colors // 2. Choose colors
struct ascii_logo* logo = art->art; struct ascii_logo* logo = art->art;
bool color = is_color_enabled();
if (!color)
art->style = STYLE_LEGACY;
switch(art->style) { switch(art->style) {
case STYLE_LEGACY: case STYLE_LEGACY:
@@ -422,11 +480,12 @@ uint32_t longest_field_length(struct ascii* art, int la) {
} }
#if defined(ARCH_X86) || defined(ARCH_PPC) #if defined(ARCH_X86) || defined(ARCH_PPC)
void print_ascii_generic(struct ascii* art, uint32_t la, int32_t termw, const char** attribute_fields) { void print_ascii_generic(struct ascii* art, uint32_t la, int32_t termw, const char** attribute_fields, bool hybrid_architecture) {
struct ascii_logo* logo = art->art; struct ascii_logo* logo = art->art;
int attr_to_print = 0; int attr_to_print = 0;
int attr_type; int attr_type;
char* attr_value; char* attr_value;
int32_t beg_space;
int32_t space_right; int32_t space_right;
int32_t space_up = ((int)logo->height - (int)art->n_attributes_set)/2; int32_t space_up = ((int)logo->height - (int)art->n_attributes_set)/2;
int32_t space_down = (int)logo->height - (int)art->n_attributes_set - (int)space_up; int32_t space_down = (int)logo->height - (int)art->n_attributes_set - (int)space_up;
@@ -437,6 +496,7 @@ void print_ascii_generic(struct ascii* art, uint32_t la, int32_t termw, const ch
lbuf->buf = emalloc(sizeof(char) * LINE_BUFFER_SIZE); lbuf->buf = emalloc(sizeof(char) * LINE_BUFFER_SIZE);
lbuf->pos = 0; lbuf->pos = 0;
lbuf->chars = 0; lbuf->chars = 0;
bool add_space = false;
printf("\n"); printf("\n");
for(int32_t n=0; n < iters; n++) { for(int32_t n=0; n < iters; n++) {
@@ -471,9 +531,28 @@ void print_ascii_generic(struct ascii* art, uint32_t la, int32_t termw, const ch
attr_value = art->attributes[attr_to_print]->value; attr_value = art->attributes[attr_to_print]->value;
attr_to_print++; attr_to_print++;
space_right = 1 + (la - strlen(attribute_fields[attr_type])); #ifdef ARCH_X86
printOut(lbuf, strlen(attribute_fields[attr_type]) + space_right + strlen(attr_value), if(attr_type == ATTRIBUTE_L3) {
"%s%s%s%*s%s%s%s", logo->color_text[0], attribute_fields[attr_type], art->reset, space_right, "", logo->color_text[1], attr_value, art->reset); add_space = false;
}
if(attr_type == ATTRIBUTE_CPU_NUM) {
printOut(lbuf, strlen(attr_value), "%s%s%s", logo->color_text[0], attr_value, art->reset);
add_space = true;
}
else {
#endif
beg_space = 0;
space_right = 2 + 1 + (la - strlen(attribute_fields[attr_type]));
if(hybrid_architecture && add_space) {
beg_space = 2;
space_right -= 2;
}
printOut(lbuf, beg_space + strlen(attribute_fields[attr_type]) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attribute_fields[attr_type], art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
#ifdef ARCH_X86
}
#endif
} }
printOutLine(lbuf, art, termw); printOutLine(lbuf, art, termw);
printf("\n"); printf("\n");
@@ -498,48 +577,87 @@ bool print_cpufetch_x86(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
return false; return false;
art->new_intel_logo = choose_new_intel_logo(cpu); art->new_intel_logo = choose_new_intel_logo(cpu);
char* uarch = get_str_uarch(cpu);
char* manufacturing_process = get_str_process(cpu); uint32_t socket_num = 1;
char* sockets = get_str_sockets(cpu->topo); char* l1i, *l1d, *l2, *l3, *n_cores, *n_cores_dual, *sockets;
char* max_frequency = get_str_freq(cpu->freq); l1i = l1d = l2 = l3 = n_cores = n_cores_dual = sockets = NULL;
char* n_cores = get_str_topology(cpu, cpu->topo, false);
char* n_cores_dual = get_str_topology(cpu, cpu->topo, true);
char* cpu_name = get_str_cpu_name(cpu, fcpuname); char* cpu_name = get_str_cpu_name(cpu, fcpuname);
char* avx = get_str_avx(cpu); char* uarch = get_str_uarch(cpu);
char* fma = get_str_fma(cpu);
char* l1i = get_str_l1i(cpu->cach);
char* l1d = get_str_l1d(cpu->cach);
char* l2 = get_str_l2(cpu->cach);
char* l3 = get_str_l3(cpu->cach);
char* pp = get_str_peak_performance(cpu->peak_performance); char* pp = get_str_peak_performance(cpu->peak_performance);
char* manufacturing_process = get_str_process(cpu);
bool hybrid_architecture = cpu->next_cpu != NULL;
setAttribute(art,ATTRIBUTE_NAME,cpu_name); if(cpu->cach != NULL) {
l3 = get_str_l3(cpu->cach);
}
setAttribute(art, ATTRIBUTE_NAME, cpu_name);
if(cpu->hv->present) { if(cpu->hv->present) {
setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name); setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name);
} }
setAttribute(art,ATTRIBUTE_UARCH,uarch); setAttribute(art, ATTRIBUTE_UARCH, uarch);
setAttribute(art,ATTRIBUTE_TECHNOLOGY,manufacturing_process); setAttribute(art, ATTRIBUTE_TECHNOLOGY, manufacturing_process);
setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency);
uint32_t socket_num = get_nsockets(cpu->topo);
if (socket_num > 1) {
setAttribute(art, ATTRIBUTE_SOCKETS, sockets);
setAttribute(art, ATTRIBUTE_NCORES,n_cores);
setAttribute(art, ATTRIBUTE_NCORES_DUAL, n_cores_dual);
}
else {
setAttribute(art,ATTRIBUTE_NCORES,n_cores);
}
setAttribute(art,ATTRIBUTE_AVX,avx);
setAttribute(art,ATTRIBUTE_FMA,fma);
setAttribute(art,ATTRIBUTE_L1i,l1i);
setAttribute(art,ATTRIBUTE_L1d,l1d);
setAttribute(art,ATTRIBUTE_L2,l2);
if(l3 != NULL) {
setAttribute(art,ATTRIBUTE_L3,l3);
}
setAttribute(art,ATTRIBUTE_PEAK,pp);
struct cpuInfo* ptr = cpu;
for(int i = 0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
char* max_frequency = get_str_freq(ptr->freq);
char* avx = get_str_avx(ptr);
char* sse = get_str_sse(ptr);
char* fma = get_str_fma(ptr);
char* cpu_num = emalloc(sizeof(char) * 9);
if(ptr->topo != NULL) {
sockets = get_str_sockets(ptr->topo);
n_cores = get_str_topology(ptr, ptr->topo, false);
n_cores_dual = get_str_topology(ptr, ptr->topo, true);
}
if(ptr->cach != NULL) {
l1i = get_str_l1i(ptr->cach);
l1d = get_str_l1d(ptr->cach);
l2 = get_str_l2(ptr->cach);
}
if(hybrid_architecture) {
if(ptr->core_type == CORE_TYPE_EFFICIENCY) sprintf(cpu_num, "E-cores:");
else if(ptr->core_type == CORE_TYPE_PERFORMANCE) sprintf(cpu_num, "P-cores:");
else printBug("Found invalid core type!\n");
setAttribute(art, ATTRIBUTE_CPU_NUM, cpu_num);
}
setAttribute(art, ATTRIBUTE_FREQUENCY, max_frequency);
if(ptr->topo != NULL) {
socket_num = get_nsockets(ptr->topo);
if (socket_num > 1) {
setAttribute(art, ATTRIBUTE_SOCKETS, sockets);
setAttribute(art, ATTRIBUTE_NCORES, n_cores);
setAttribute(art, ATTRIBUTE_NCORES_DUAL, n_cores_dual);
}
else {
setAttribute(art, ATTRIBUTE_NCORES, n_cores);
}
}
// Show the most modern vector instructions.
if (strcmp(avx, "No") == 0) {
if (strcmp(sse, "No") != 0) {
setAttribute(art, ATTRIBUTE_SSE, sse);
}
}
else {
setAttribute(art, ATTRIBUTE_AVX, avx);
setAttribute(art, ATTRIBUTE_FMA, fma);
}
if(l1i != NULL) setAttribute(art, ATTRIBUTE_L1i, l1i);
if(l1d != NULL) setAttribute(art, ATTRIBUTE_L1d, l1d);
if(l2 != NULL) setAttribute(art, ATTRIBUTE_L2, l2);
}
if(l3 != NULL) setAttribute(art, ATTRIBUTE_L3, l3);
setAttribute(art, ATTRIBUTE_PEAK, pp);
// Step 3. Print output
const char** attribute_fields = ATTRIBUTE_FIELDS; const char** attribute_fields = ATTRIBUTE_FIELDS;
uint32_t longest_attribute = longest_attribute_length(art, attribute_fields); uint32_t longest_attribute = longest_attribute_length(art, attribute_fields);
uint32_t longest_field = longest_field_length(art, longest_attribute); uint32_t longest_field = longest_field_length(art, longest_attribute);
@@ -552,15 +670,12 @@ bool print_cpufetch_x86(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
longest_attribute = longest_attribute_length(art, attribute_fields); longest_attribute = longest_attribute_length(art, attribute_fields);
} }
print_ascii_generic(art, longest_attribute, term->w, attribute_fields); print_ascii_generic(art, longest_attribute, term->w, attribute_fields, hybrid_architecture);
free(manufacturing_process); free(manufacturing_process);
free(max_frequency);
free(sockets); free(sockets);
free(n_cores); free(n_cores);
free(n_cores_dual); free(n_cores_dual);
free(avx);
free(fma);
free(l1i); free(l1i);
free(l1d); free(l1d);
free(l2); free(l2);
@@ -571,8 +686,8 @@ bool print_cpufetch_x86(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
free(art); free(art);
if(cs != NULL) free_colors_struct(cs); if(cs != NULL) free_colors_struct(cs);
free_cache_struct(cpu->cach); if(cpu->cach != NULL) free_cache_struct(cpu->cach);
free_topo_struct(cpu->topo); if(cpu->topo != NULL) free_topo_struct(cpu->topo);
free_freq_struct(cpu->freq); free_freq_struct(cpu->freq);
free_cpuinfo_struct(cpu); free_cpuinfo_struct(cpu);
@@ -586,6 +701,7 @@ bool print_cpufetch_ppc(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
if(art == NULL) if(art == NULL)
return false; return false;
// Step 1. Retrieve attributes
char* uarch = get_str_uarch(cpu); char* uarch = get_str_uarch(cpu);
char* manufacturing_process = get_str_process(cpu); char* manufacturing_process = get_str_process(cpu);
char* sockets = get_str_sockets(cpu->topo); char* sockets = get_str_sockets(cpu->topo);
@@ -601,12 +717,16 @@ bool print_cpufetch_ppc(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
char* l3 = get_str_l3(cpu->cach); char* l3 = get_str_l3(cpu->cach);
char* pp = get_str_peak_performance(cpu->peak_performance); char* pp = get_str_peak_performance(cpu->peak_performance);
// Step 2. Set attributes
if(cpu_name != NULL) { if(cpu_name != NULL) {
setAttribute(art,ATTRIBUTE_NAME,cpu_name); setAttribute(art, ATTRIBUTE_NAME, cpu_name);
} }
setAttribute(art,ATTRIBUTE_UARCH,uarch); setAttribute(art, ATTRIBUTE_UARCH, uarch);
setAttribute(art,ATTRIBUTE_TECHNOLOGY,manufacturing_process); if(cpu->hv->present) {
setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency); setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name);
}
setAttribute(art, ATTRIBUTE_TECHNOLOGY, manufacturing_process);
setAttribute(art, ATTRIBUTE_FREQUENCY, max_frequency);
uint32_t socket_num = get_nsockets(cpu->topo); uint32_t socket_num = get_nsockets(cpu->topo);
if (socket_num > 1) { if (socket_num > 1) {
setAttribute(art, ATTRIBUTE_SOCKETS, sockets); setAttribute(art, ATTRIBUTE_SOCKETS, sockets);
@@ -614,17 +734,18 @@ bool print_cpufetch_ppc(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
setAttribute(art, ATTRIBUTE_NCORES_DUAL, n_cores_dual); setAttribute(art, ATTRIBUTE_NCORES_DUAL, n_cores_dual);
} }
else { else {
setAttribute(art,ATTRIBUTE_NCORES, n_cores); setAttribute(art, ATTRIBUTE_NCORES, n_cores);
} }
setAttribute(art,ATTRIBUTE_ALTIVEC, altivec); setAttribute(art, ATTRIBUTE_ALTIVEC, altivec);
setAttribute(art,ATTRIBUTE_L1i,l1i); setAttribute(art, ATTRIBUTE_L1i, l1i);
setAttribute(art,ATTRIBUTE_L1d,l1d); setAttribute(art, ATTRIBUTE_L1d, l1d);
setAttribute(art,ATTRIBUTE_L2,l2); setAttribute(art, ATTRIBUTE_L2, l2);
if(l3 != NULL) { if(l3 != NULL) {
setAttribute(art,ATTRIBUTE_L3,l3); setAttribute(art, ATTRIBUTE_L3, l3);
} }
setAttribute(art,ATTRIBUTE_PEAK,pp); setAttribute(art, ATTRIBUTE_PEAK, pp);
// Step 3. Print output
const char** attribute_fields = ATTRIBUTE_FIELDS; const char** attribute_fields = ATTRIBUTE_FIELDS;
uint32_t longest_attribute = longest_attribute_length(art, attribute_fields); uint32_t longest_attribute = longest_attribute_length(art, attribute_fields);
uint32_t longest_field = longest_field_length(art, longest_attribute); uint32_t longest_field = longest_field_length(art, longest_attribute);
@@ -637,7 +758,7 @@ bool print_cpufetch_ppc(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
longest_attribute = longest_attribute_length(art, attribute_fields); longest_attribute = longest_attribute_length(art, attribute_fields);
} }
print_ascii_generic(art, longest_attribute, term->w, attribute_fields); print_ascii_generic(art, longest_attribute, term->w, attribute_fields, false);
return true; return true;
} }
@@ -763,26 +884,17 @@ bool print_cpufetch_arm(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
char* manufacturing_process = get_str_process(cpu->soc); char* manufacturing_process = get_str_process(cpu->soc);
char* soc_name = get_soc_name(cpu->soc); char* soc_name = get_soc_name(cpu->soc);
char* features = get_str_features(cpu); char* features = get_str_features(cpu);
setAttribute(art,ATTRIBUTE_SOC,soc_name); setAttribute(art, ATTRIBUTE_SOC, soc_name);
setAttribute(art,ATTRIBUTE_TECHNOLOGY,manufacturing_process); setAttribute(art, ATTRIBUTE_TECHNOLOGY, manufacturing_process);
if(cpu->num_cpus == 1) { if(cpu->num_cpus == 1) {
char* uarch = get_str_uarch(cpu); char* uarch = get_str_uarch(cpu);
char* max_frequency = get_str_freq(cpu->freq); char* max_frequency = get_str_freq(cpu->freq);
char* n_cores = get_str_topology(cpu, cpu->topo, false); char* n_cores = get_str_topology(cpu, cpu->topo, false);
/*
* char* l1i = get_str_l1i(cpu->cach);
* char* l1d = get_str_l1d(cpu->cach);
* char* l2 = get_str_l2(cpu->cach);
* char* l3 = get_str_l3(cpu->cach);
* Do not setAttribute for caches.
* Cache functionality may be implemented
* in the future
*/
setAttribute(art,ATTRIBUTE_UARCH,uarch); setAttribute(art, ATTRIBUTE_UARCH, uarch);
setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency); setAttribute(art, ATTRIBUTE_FREQUENCY, max_frequency);
setAttribute(art,ATTRIBUTE_NCORES,n_cores); setAttribute(art, ATTRIBUTE_NCORES, n_cores);
if(features != NULL) { if(features != NULL) {
setAttribute(art, ATTRIBUTE_FEATURES, features); setAttribute(art, ATTRIBUTE_FEATURES, features);
} }
@@ -793,17 +905,8 @@ bool print_cpufetch_arm(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
char* uarch = get_str_uarch(ptr); char* uarch = get_str_uarch(ptr);
char* max_frequency = get_str_freq(ptr->freq); char* max_frequency = get_str_freq(ptr->freq);
char* n_cores = get_str_topology(ptr, ptr->topo, false); char* n_cores = get_str_topology(ptr, ptr->topo, false);
/*
* char* l1i = get_str_l1i(cpu->cach);
* char* l1d = get_str_l1d(cpu->cach);
* char* l2 = get_str_l2(cpu->cach);
* char* l3 = get_str_l3(cpu->cach);
* Do not setAttribute for caches.
* Cache functionality may be implemented
* in the future
*/
char* cpu_num = emalloc(sizeof(char) * 9); char* cpu_num = emalloc(sizeof(char) * 9);
sprintf(cpu_num, "CPU %d:", i+1); sprintf(cpu_num, "CPU %d:", i+1);
setAttribute(art, ATTRIBUTE_CPU_NUM, cpu_num); setAttribute(art, ATTRIBUTE_CPU_NUM, cpu_num);
setAttribute(art, ATTRIBUTE_UARCH, uarch); setAttribute(art, ATTRIBUTE_UARCH, uarch);
@@ -815,7 +918,7 @@ bool print_cpufetch_arm(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
} }
} }
char* pp = get_str_peak_performance(cpu->peak_performance); char* pp = get_str_peak_performance(cpu->peak_performance);
setAttribute(art,ATTRIBUTE_PEAK,pp); setAttribute(art, ATTRIBUTE_PEAK, pp);
if(cpu->hv->present) { if(cpu->hv->present) {
setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name); setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name);
} }
@@ -854,7 +957,142 @@ bool print_cpufetch_arm(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
} }
#endif #endif
struct terminal* get_terminal_size() { #ifdef ARCH_RISCV
// https://stackoverflow.com/a/2709523
uint64_t number_of_bits(uint64_t i) {
i = i - ((i >> 1) & 0x5555555555555555);
i = (i & 0x3333333333333333) + ((i >> 2) & 0x3333333333333333);
return (((i + (i >> 4)) & 0xF0F0F0F0F0F0F0F) * 0x101010101010101) >> 56;
}
void print_ascii_riscv(struct ascii* art, uint32_t la, int32_t termw, const char** attribute_fields, uint64_t extensions_mask) {
struct ascii_logo* logo = art->art;
int attr_to_print = 0;
int attr_type;
char* attr_value;
int32_t beg_space;
int32_t space_right;
int32_t ext_list_size = sizeof(extension_list)/sizeof(extension_list[0]);
int32_t ext_num = 0;
int32_t ext_to_print = 0;
int32_t num_extensions = number_of_bits(extensions_mask);
int32_t space_up = ((int)logo->height - (int)(art->n_attributes_set + num_extensions))/2;
int32_t space_down = (int)logo->height - (int)(art->n_attributes_set + num_extensions) - (int)space_up;
uint32_t logo_pos = 0;
int32_t iters = max(logo->height, art->n_attributes_set + num_extensions);
struct line_buffer* lbuf = emalloc(sizeof(struct line_buffer));
lbuf->buf = emalloc(sizeof(char) * LINE_BUFFER_SIZE);
lbuf->pos = 0;
lbuf->chars = 0;
printf("\n");
for(int32_t n=0; n < iters; n++) {
// 1. Print logo
if(space_up > 0 || (space_up + n >= 0 && space_up + n < (int)logo->height)) {
for(uint32_t i=0; i < logo->width; i++) {
if(logo->art[logo_pos] == '$') {
if(logo->replace_blocks) logo_pos += 3;
else parse_print_color(art, lbuf, &logo_pos);
}
if(logo->replace_blocks && logo->art[logo_pos] != ' ') {
if(logo->art[logo_pos] == '#') printOut(lbuf, 1, "%s%c%s", logo->color_ascii[0], ' ', art->reset);
else if(logo->art[logo_pos] == '@') printOut(lbuf, 1, "%s%c%s", logo->color_ascii[1], ' ', art->reset);
else if(logo->art[logo_pos] == '%') printOut(lbuf, 1, "%s%c%s", logo->color_ascii[2], ' ', art->reset);
else printOut(lbuf, 1, "%c", logo->art[logo_pos]);
}
else
printOut(lbuf, 1, "%c", logo->art[logo_pos]);
logo_pos++;
}
printOut(lbuf, 0, "%s", art->reset);
}
else {
// If logo should not be printed, fill with spaces
printOut(lbuf, logo->width, "%*c", logo->width, ' ');
}
// 2. Print text
if(space_up < 0 || (n > space_up-1 && n < (int)logo->height - space_down)) {
attr_type = art->attributes[attr_to_print]->type;
attr_value = art->attributes[attr_to_print]->value;
// Print extension
if(attr_to_print > 0 && art->attributes[attr_to_print-1]->type == ATTRIBUTE_EXTENSIONS && ext_num != num_extensions) {
// Search for the extension to print
while(ext_to_print < ext_list_size && !((extensions_mask >> extension_list[ext_to_print].id) & 1U)) ext_to_print++;
if(ext_to_print == ext_list_size) {
printBug("print_ascii_riscv: Unable to find the extension to print");
}
printOut(lbuf, 3 + strlen(extension_list[ext_to_print].str), "%s - %s%s", logo->color_text[0], extension_list[ext_to_print].str, art->reset);
ext_num++;
ext_to_print++;
}
else {
attr_to_print++;
beg_space = 0;
space_right = 2 + 1 + (la - strlen(attribute_fields[attr_type]));
printOut(lbuf, beg_space + strlen(attribute_fields[attr_type]) + space_right + strlen(attr_value),
"%*s%s%s%s%*s%s%s%s", beg_space, "", logo->color_text[0], attribute_fields[attr_type], art->reset, space_right, "", logo->color_text[1], attr_value, art->reset);
}
}
printOutLine(lbuf, art, termw);
printf("\n");
}
printf("\n");
free(lbuf->buf);
free(lbuf);
}
bool print_cpufetch_riscv(struct cpuInfo* cpu, STYLE s, struct color** cs, struct terminal* term) {
struct ascii* art = set_ascii(get_soc_vendor(cpu->soc), s);
if(art == NULL)
return false;
// Step 1. Retrieve attributes
char* uarch = get_str_uarch(cpu);
char* manufacturing_process = get_str_process(cpu->soc);
char* soc_name = get_soc_name(cpu->soc);
char* extensions = get_str_extensions(cpu);
char* max_frequency = get_str_freq(cpu->freq);
char* n_cores = get_str_topology(cpu, cpu->topo);
char* pp = get_str_peak_performance(cpu->peak_performance);
// Step 2. Set attributes
setAttribute(art, ATTRIBUTE_SOC, soc_name);
setAttribute(art, ATTRIBUTE_TECHNOLOGY, manufacturing_process);
setAttribute(art, ATTRIBUTE_UARCH, uarch);
setAttribute(art, ATTRIBUTE_NCORES, n_cores);
setAttribute(art, ATTRIBUTE_FREQUENCY, max_frequency);
if(extensions != NULL) {
setAttribute(art, ATTRIBUTE_EXTENSIONS, extensions);
}
setAttribute(art, ATTRIBUTE_PEAK, pp);
// Step 3. Print output
const char** attribute_fields = ATTRIBUTE_FIELDS;
uint32_t longest_attribute = longest_attribute_length(art, attribute_fields);
uint32_t longest_field = longest_field_length(art, longest_attribute);
choose_ascii_art(art, cs, term, longest_field);
if(!ascii_fits_screen(term->w, *art->art, longest_field)) {
// Despite of choosing the smallest logo, the output does not fit
// Choose the shorter field names and recalculate the longest attr
attribute_fields = ATTRIBUTE_FIELDS_SHORT;
longest_attribute = longest_attribute_length(art, attribute_fields);
}
print_ascii_riscv(art, longest_attribute, term->w, attribute_fields, cpu->ext->mask);
return true;
}
#endif
struct terminal* get_terminal_size(void) {
struct terminal* term = emalloc(sizeof(struct terminal)); struct terminal* term = emalloc(sizeof(struct terminal));
#ifdef _WIN32 #ifdef _WIN32
@@ -891,5 +1129,7 @@ bool print_cpufetch(struct cpuInfo* cpu, STYLE s, struct color** cs, bool show_f
return print_cpufetch_ppc(cpu, s, cs, term, show_full_cpu_name); return print_cpufetch_ppc(cpu, s, cs, term, show_full_cpu_name);
#elif ARCH_ARM #elif ARCH_ARM
return print_cpufetch_arm(cpu, s, cs, term); return print_cpufetch_arm(cpu, s, cs, term);
#elif ARCH_RISCV
return print_cpufetch_riscv(cpu, s, cs, term);
#endif #endif
} }

View File

@@ -11,6 +11,8 @@ typedef int STYLE;
#include "../ppc/ppc.h" #include "../ppc/ppc.h"
#elif ARCH_ARM #elif ARCH_ARM
#include "../arm/midr.h" #include "../arm/midr.h"
#elif ARCH_RISCV
#include "../riscv/riscv.h"
#endif #endif
// +-----------------------------------+-----------------------+ // +-----------------------------------+-----------------------+
@@ -21,6 +23,8 @@ typedef int STYLE;
#define COLOR_DEFAULT_AMD "250,250,250:000,154,102:000,000,000:250,250,250:000,154,102" #define COLOR_DEFAULT_AMD "250,250,250:000,154,102:000,000,000:250,250,250:000,154,102"
#define COLOR_DEFAULT_IBM "092,119,172:092,119,172:000,000,000:240,240,240:092,119,172" #define COLOR_DEFAULT_IBM "092,119,172:092,119,172:000,000,000:240,240,240:092,119,172"
#define COLOR_DEFAULT_ARM "000,145,189:000,145,189:000,000,000:240,240,240:000,145,189" #define COLOR_DEFAULT_ARM "000,145,189:000,145,189:000,000,000:240,240,240:000,145,189"
#define COLOR_DEFAULT_ROCKCHIP "114,159,207:229,195,000:000,000,000:240,240,240:114,159,207"
#define COLOR_DEFAULT_SIFIVE "255,255,255:000,000,000:000,000,000:255,255,255:000,000,000"
#ifdef ARCH_X86 #ifdef ARCH_X86
void print_levels(struct cpuInfo* cpu); void print_levels(struct cpuInfo* cpu);

93
src/common/soc.c Normal file
View File

@@ -0,0 +1,93 @@
#include "soc.h"
#ifdef ARCH_ARM
#include "../arm/socs.h"
#elif ARCH_RISCV
#include "../riscv/socs.h"
#endif
#include "udev.h"
#include "../common/global.h"
#include <string.h>
static char* soc_trademark_string[] = {
// ARM
[SOC_VENDOR_SNAPDRAGON] = "Snapdragon ",
[SOC_VENDOR_MEDIATEK] = "MediaTek ",
[SOC_VENDOR_EXYNOS] = "Exynos ",
[SOC_VENDOR_KIRIN] = "Kirin ",
[SOC_VENDOR_KUNPENG] = "Kunpeng ",
[SOC_VENDOR_BROADCOM] = "Broadcom ",
[SOC_VENDOR_APPLE] = "Apple ",
[SOC_VENDOR_ROCKCHIP] = "Rockchip ",
[SOC_VENDOR_GOOGLE] = "Google ",
[SOC_VENDOR_NVIDIA] = "NVIDIA ",
[SOC_VENDOR_AMPERE] = "Ampere ",
[SOC_VENDOR_NXP] = "NXP ",
[SOC_VENDOR_AMLOGIC] = "Amlogic ",
// RISC-V
[SOC_VENDOR_SIFIVE] = "SiFive ",
[SOC_VENDOR_STARFIVE] = "StarFive ",
[SOC_VENDOR_SIPEED] = "Sipeed ",
// ARM & RISC-V
[SOC_VENDOR_ALLWINNER] = "Allwinner "
};
VENDOR get_soc_vendor(struct system_on_chip* soc) {
return soc->vendor;
}
char* get_str_process(struct system_on_chip* soc) {
char* str;
if(soc->process == UNKNOWN) {
str = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
}
else {
int max_process_len = 5 + 1;
str = ecalloc(max_process_len, sizeof(char));
snprintf(str, max_process_len, "%dnm", soc->process);
}
return str;
}
char* get_soc_name(struct system_on_chip* soc) {
if(soc->model == SOC_MODEL_UNKNOWN)
return soc->raw_name;
return soc->name;
}
void fill_soc(struct system_on_chip* soc, char* soc_name, SOC soc_model, int32_t process) {
soc->model = soc_model;
soc->vendor = get_soc_vendor_from_soc(soc_model);
soc->process = process;
if(soc->vendor == SOC_VENDOR_UNKNOWN) {
printBug("fill_soc: soc->vendor == SOC_VENDOR_UNKOWN");
// If we fall here there is a bug in socs.h
// Reset everything to avoid segfault
soc->vendor = SOC_VENDOR_UNKNOWN;
soc->model = SOC_MODEL_UNKNOWN;
soc->process = UNKNOWN;
soc->raw_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
snprintf(soc->raw_name, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
}
else {
int len = strlen(soc_name) + strlen(soc_trademark_string[soc->vendor]) + 1;
soc->name = emalloc(sizeof(char) * len);
sprintf(soc->name, "%s%s", soc_trademark_string[soc->vendor], soc_name);
}
}
bool match_soc(struct system_on_chip* soc, char* raw_name, char* expected_name, char* soc_name, SOC soc_model, int32_t process) {
int len1 = strlen(raw_name);
int len2 = strlen(expected_name);
int len = min(len1, len2);
if(strncmp(raw_name, expected_name, len) != 0) {
return false;
}
else {
fill_soc(soc, soc_name, soc_model, process);
return true;
}
}

59
src/common/soc.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef __SOC__
#define __SOC__
// NOTE:
// soc.c/soc.h are used by
// ARM and RISC-V backends
#include "../common/cpu.h"
#include <stdint.h>
#define UNKNOWN -1
typedef int32_t SOC;
enum {
SOC_VENDOR_UNKNOWN,
// ARM
SOC_VENDOR_SNAPDRAGON,
SOC_VENDOR_MEDIATEK,
SOC_VENDOR_EXYNOS,
SOC_VENDOR_KIRIN,
SOC_VENDOR_KUNPENG,
SOC_VENDOR_BROADCOM,
SOC_VENDOR_APPLE,
SOC_VENDOR_ROCKCHIP,
SOC_VENDOR_GOOGLE,
SOC_VENDOR_NVIDIA,
SOC_VENDOR_AMPERE,
SOC_VENDOR_NXP,
SOC_VENDOR_AMLOGIC,
// RISC-V
SOC_VENDOR_SIFIVE,
SOC_VENDOR_STARFIVE,
SOC_VENDOR_SIPEED,
// ARM & RISC-V
SOC_VENDOR_ALLWINNER
};
struct system_on_chip {
SOC model;
VENDOR vendor;
int32_t process;
char* name;
char* raw_name;
};
struct system_on_chip* get_soc(struct cpuInfo* cpu);
char* get_soc_name(struct system_on_chip* soc);
VENDOR get_soc_vendor(struct system_on_chip* soc);
bool match_soc(struct system_on_chip* soc, char* raw_name, char* expected_name, char* soc_name, SOC soc_model, int32_t process);
char* get_str_process(struct system_on_chip* soc);
void fill_soc(struct system_on_chip* soc, char* soc_name, SOC soc_model, int32_t process);
#define SOC_START if (false) {}
#define SOC_EQ(raw_name, expected_name, soc_name, soc_model, soc, process) \
else if (match_soc(soc, raw_name, expected_name, soc_name, soc_model, process)) return true;
#define SOC_END else { return false; }
#endif

View File

@@ -4,8 +4,8 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "../common/global.h" #include "global.h"
#include "../common/cpu.h" #include "cpu.h"
uint32_t get_sys_info_by_name(char* name) { uint32_t get_sys_info_by_name(char* name) {
size_t size = 0; size_t size = 0;

56
src/common/sysctl.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef __SYSCTL__
#define __SYSCTL__
// From Linux kernel: arch/arm64/include/asm/cputype.h
#define MIDR_APPLE_M1_ICESTORM 0x610F0220
#define MIDR_APPLE_M1_FIRESTORM 0x610F0230
// Kernel does not include those, so I just assume that
// APPLE_CPU_PART_M2_BLIZZARD=0x30,M2_AVALANCHE=0x31
#define MIDR_APPLE_M2_BLIZZARD 0x610F0300
#define MIDR_APPLE_M2_AVALANCHE 0x610F0310
// https://github.com/AsahiLinux/m1n1/blob/main/src/chickens.c
#define MIDR_APPLE_M3_SAWTOOTH 0x610F0480
#define MIDR_APPLE_M3_EVEREST 0x610F0490
// M1 / A14
#ifndef CPUFAMILY_ARM_FIRESTORM_ICESTORM
#define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1B588BB3
#endif
// M2 / A15
#ifndef CPUFAMILY_ARM_AVALANCHE_BLIZZARD
#define CPUFAMILY_ARM_AVALANCHE_BLIZZARD 0xDA33D83D
#endif
// M3 / A16 / A17
// M3: https://ratfactor.com/zig/stdlib-browseable2/c/darwin.zig.html
// M3_2: https://github.com/Dr-Noob/cpufetch/issues/230
// PRO: https://github.com/Dr-Noob/cpufetch/issues/225
// MAX: https://github.com/Dr-Noob/cpufetch/issues/210
#define CPUFAMILY_ARM_EVEREST_SAWTOOTH 0x8765EDEA
#define CPUFAMILY_ARM_EVEREST_SAWTOOTH_2 0xFA33415E
#define CPUFAMILY_ARM_EVEREST_SAWTOOTH_PRO 0x5F4DEA93
#define CPUFAMILY_ARM_EVEREST_SAWTOOTH_MAX 0x72015832
// For detecting different M1 types
// NOTE: Could also be achieved detecting different
// MIDR values (e.g., APPLE_CPU_PART_M1_ICESTORM_PRO)
#ifndef CPUSUBFAMILY_ARM_HG
#define CPUSUBFAMILY_ARM_HG 2
#endif
#ifndef CPUSUBFAMILY_ARM_HS
#define CPUSUBFAMILY_ARM_HS 4
#endif
#ifndef CPUSUBFAMILY_ARM_HC_HD
#define CPUSUBFAMILY_ARM_HC_HD 5
#endif
// For alternative way to get CPU frequency on macOS and *BSD
#ifdef __APPLE__
#define CPUFREQUENCY_SYSCTL "hw.cpufrequency_max"
#else
// For FreeBSD, not sure about other *BSD
#define CPUFREQUENCY_SYSCTL "dev.cpu.0.freq"
#endif
uint32_t get_sys_info_by_name(char* name);
#endif

View File

@@ -1,7 +1,52 @@
#include "../common/global.h"
#include "udev.h" #include "udev.h"
#include "global.h" #include "global.h"
#include "cpu.h" #include "cpu.h"
#define _PATH_DEVTREE "/proc/device-tree/compatible"
// https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html
int get_ncores_from_cpuinfo(void) {
// Examples:
// 0-271
// 0-7
// 0
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUS_PRESENT, &filelen)) == NULL) {
printWarn("read_file: %s: %s\n", _PATH_CPUS_PRESENT, strerror(errno));
return -1;
}
int ncores;
char* tmp1;
if((tmp1 = strstr(buf, "-")) == NULL) {
// file contains no - character, we assume that it contains 0,
// which means that the CPU contains only one core
return 1;
}
else {
tmp1++;
}
char* tmp2 = strstr(buf, "\n");
char ncores_str[filelen];
memset(ncores_str, 0, sizeof(char) * filelen);
memcpy(ncores_str, tmp1, tmp2-tmp1);
char* end;
errno = 0;
ncores = strtol(ncores_str, &end, 10) + 1;
if(errno != 0) {
printWarn("strtol: %s:\n", strerror(errno));
return -1;
}
free(buf);
return ncores;
}
char* read_file(char* path, int* len) { char* read_file(char* path, int* len) {
int fd = open(path, O_RDONLY); int fd = open(path, O_RDONLY);
@@ -12,13 +57,18 @@ char* read_file(char* path, int* len) {
//File exists, read it //File exists, read it
int bytes_read = 0; int bytes_read = 0;
int offset = 0; int offset = 0;
int block = 128; int block = 1024;
char* buf = emalloc(sizeof(char)*DEFAULT_FILE_SIZE); int buf_size = block * 4;
memset(buf, 0, sizeof(char)*DEFAULT_FILE_SIZE); char* buf = emalloc(sizeof(char) * buf_size);
while ( (bytes_read = read(fd, buf+offset, block)) > 0 ) { while ((bytes_read = read(fd, buf+offset, block)) > 0) {
offset += bytes_read; offset += bytes_read;
if(offset + block > buf_size) {
buf = erealloc(buf, sizeof(char) * (buf_size + block));
buf_size += block;
}
} }
buf[offset] = '\0';
if (close(fd) == -1) { if (close(fd) == -1) {
return NULL; return NULL;
@@ -33,7 +83,7 @@ long get_freq_from_file(char* path) {
char* buf; char* buf;
if((buf = read_file(path, &filelen)) == NULL) { if((buf = read_file(path, &filelen)) == NULL) {
printWarn("Could not open '%s'", path); printWarn("Could not open '%s'", path);
return UNKNOWN_FREQ; return UNKNOWN_DATA;
} }
char* end; char* end;
@@ -42,7 +92,7 @@ long get_freq_from_file(char* path) {
if(errno != 0) { if(errno != 0) {
printBug("strtol: %s", strerror(errno)); printBug("strtol: %s", strerror(errno));
free(buf); free(buf);
return UNKNOWN_FREQ; return UNKNOWN_DATA;
} }
// We will be getting the frequency in KHz // We will be getting the frequency in KHz
@@ -50,7 +100,7 @@ long get_freq_from_file(char* path) {
// greater than 10 GHz or less than 100 MHz // greater than 10 GHz or less than 100 MHz
if(ret > 10000 * 1000 || ret < 100 * 1000) { if(ret > 10000 * 1000 || ret < 100 * 1000) {
printBug("Invalid data was read from file '%s': %ld\n", path, ret); printBug("Invalid data was read from file '%s': %ld\n", path, ret);
return UNKNOWN_FREQ; return UNKNOWN_DATA;
} }
free(buf); free(buf);
@@ -82,6 +132,26 @@ long get_cache_size_from_file(char* path) {
return ret * 1024; return ret * 1024;
} }
char* get_field_from_cpuinfo(char* CPUINFO_FIELD) {
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUINFO, &filelen)) == NULL) {
printWarn("read_file: %s: %s:\n", _PATH_CPUINFO, strerror(errno));
return NULL;
}
char* tmp1 = strstr(buf, CPUINFO_FIELD);
if(tmp1 == NULL) return NULL;
tmp1 = tmp1 + strlen(CPUINFO_FIELD);
char* tmp2 = strstr(tmp1, "\n");
int strlen = (1 + (tmp2-tmp1));
char* hardware = ecalloc(strlen, sizeof(char));
strncpy(hardware, tmp1, tmp2-tmp1);
return hardware;
}
long get_max_freq_from_file(uint32_t core) { long get_max_freq_from_file(uint32_t core) {
char path[_PATH_FREQUENCY_MAX_LEN]; char path[_PATH_FREQUENCY_MAX_LEN];
sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_FREQUENCY, _PATH_FREQUENCY_MAX); sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_FREQUENCY, _PATH_FREQUENCY_MAX);
@@ -118,54 +188,106 @@ long get_l3_cache_size(uint32_t core) {
return get_cache_size_from_file(path); return get_cache_size_from_file(path);
} }
int get_num_caches_from_files(char** paths, int num_paths) { void add_shared_map(uint32_t** src, int src_idx, uint32_t** dst, int dst_idx, int n) {
int SHARED_MAP_MAX_LEN = 8 + 1; for(int j=0; j < n; j++) {
dst[dst_idx][j] = src[src_idx][j];
}
}
bool maps_equal(uint32_t* map1, uint32_t* map2, int n) {
for(int i=0; i < n; i++) {
if(map1[i] != map2[i]) return false;
}
return true;
}
// Generic function to count the number of distinct
// elements in the list of files passed in char** paths.
// An element can be potentially anything.
// We use this function to count:
// - The number of caches
// - The number of sockets
int get_num_elements_from_files(char** paths, int num_paths) {
int filelen; int filelen;
char* buf; char* buf;
uint32_t* shared_maps = emalloc(sizeof(uint32_t *) * num_paths); char* tmpbuf;
// 1. Read cpu_shared_map from every core // 1. Count the number of bitmasks per file
if((buf = read_file(paths[0], &filelen)) == NULL) {
printWarn("Could not open '%s'", paths[0]);
return -1;
}
int num_bitmasks = 1;
for(int i=0; buf[i]; i++) {
num_bitmasks += (buf[i] == ',');
}
// 2. Read map from every core
uint32_t** maps = emalloc(sizeof(uint32_t *) * num_paths);
for(int i=0; i < num_paths; i++) { for(int i=0; i < num_paths; i++) {
maps[i] = emalloc(sizeof(uint32_t) * num_bitmasks);
if((buf = read_file(paths[i], &filelen)) == NULL) { if((buf = read_file(paths[i], &filelen)) == NULL) {
printWarn("Could not open '%s'", paths[i]); printWarn("Could not open '%s'", paths[i]);
return -1; return -1;
} }
if(filelen > SHARED_MAP_MAX_LEN) { for(int j=0; j < num_bitmasks; j++) {
printBug("Shared map length is %d while the max is be %d", filelen, SHARED_MAP_MAX_LEN); char* end;
return -1; tmpbuf = emalloc(sizeof(char) * (strlen(buf) + 1));
} memset(tmpbuf, 0, sizeof(char) * (strlen(buf) + 1));
char* commaend = strstr(buf, ",");
if(commaend == NULL) {
strcpy(tmpbuf, buf);
}
else {
strncpy(tmpbuf, buf, commaend-buf);
}
errno = 0;
long ret = strtol(tmpbuf, &end, 16);
if(errno != 0) {
printf("strtol: %s", strerror(errno));
free(buf);
return -1;
}
char* end; maps[i][j] = (uint32_t) ret;
errno = 0; buf = commaend + 1;
long ret = strtol(buf, &end, 16); free(tmpbuf);
if(errno != 0) {
printBug("strtol: %s", strerror(errno));
free(buf);
return -1;
} }
shared_maps[i] = (uint32_t) ret;
} }
// 2. Count number of different masks; this is the number of caches // 2. Count number of different masks; this is the number of elements
int num_caches = 0; int num_elements = 0;
bool found = false; bool found = false;
uint32_t* unique_shared_maps = emalloc(sizeof(uint32_t *) * num_paths); uint32_t** unique_maps = emalloc(sizeof(uint32_t *) * num_paths);
for(int i=0; i < num_paths; i++) unique_shared_maps[i] = 0; for(int i=0; i < num_paths; i++) {
unique_maps[i] = emalloc(sizeof(uint32_t) * num_bitmasks);
for(int j=0; j < num_bitmasks; j++) {
unique_maps[i][j] = 0;
}
}
for(int i=0; i < num_paths; i++) { for(int i=0; i < num_paths; i++) {
for(int j=0; j < num_paths && !found; j++) { for(int j=0; j < num_paths && !found; j++) {
if(shared_maps[i] == unique_shared_maps[j]) found = true; if(maps_equal(maps[i], unique_maps[j], num_bitmasks)) found = true;
} }
if(!found) { if(!found) {
unique_shared_maps[num_caches] = shared_maps[i]; add_shared_map(maps, i, unique_maps, num_elements, num_bitmasks);
num_caches++; num_elements++;
} }
found = false; found = false;
} }
return num_caches; return num_elements;
}
int get_num_caches_from_files(char** paths, int num_paths) {
return get_num_elements_from_files(paths, num_paths);
}
int get_num_sockets_from_files(char** paths, int num_paths) {
return get_num_elements_from_files(paths, num_paths);
} }
int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level) { int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level) {
@@ -194,3 +316,48 @@ int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level) {
return ret; return ret;
} }
int get_num_sockets_package_cpus(struct topology* topo) {
// Get number of sockets using
// /sys/devices/system/cpu/cpu*/topology/package_cpus
char** paths = emalloc(sizeof(char *) * topo->total_cores);
for(int i=0; i < topo->total_cores; i++) {
paths[i] = emalloc(sizeof(char) * _PATH_PACKAGE_MAX_LEN);
sprintf(paths[i], "%s%s/cpu%d%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, i, _PATH_TOPO_PACKAGE_CPUS);
}
int ret = get_num_sockets_from_files(paths, topo->total_cores);
for(int i=0; i < topo->total_cores; i++)
free(paths[i]);
free(paths);
return ret;
}
// Inspired in is_devtree_compatible from lscpu
bool is_devtree_compatible(char* str) {
int filelen;
char* buf;
if((buf = read_file("/proc/device-tree/compatible", &filelen)) == NULL) {
return false;
}
char* tmp;
if((tmp = strstr(buf, str)) == NULL) {
return false;
}
return true;
}
char* get_devtree_compatible(int *filelen) {
char* buf;
if ((buf = read_file(_PATH_DEVTREE, filelen)) == NULL) {
printWarn("read_file: %s: %s", _PATH_DEVTREE, strerror(errno));
}
return buf;
}

View File

@@ -12,6 +12,7 @@
#include "cpu.h" #include "cpu.h"
#define _PATH_CPUINFO "/proc/cpuinfo"
#define _PATH_SYS_SYSTEM "/sys/devices/system" #define _PATH_SYS_SYSTEM "/sys/devices/system"
#define _PATH_SYS_CPU "/cpu" #define _PATH_SYS_CPU "/cpu"
#define _PATH_FREQUENCY "/cpufreq" #define _PATH_FREQUENCY "/cpufreq"
@@ -23,10 +24,12 @@
#define _PATH_CACHE_L3 "/cache/index3" #define _PATH_CACHE_L3 "/cache/index3"
#define _PATH_CACHE_SIZE "/size" #define _PATH_CACHE_SIZE "/size"
#define _PATH_CACHE_SHARED_MAP "/shared_cpu_map" #define _PATH_CACHE_SHARED_MAP "/shared_cpu_map"
#define _PATH_CPUS_PRESENT _PATH_SYS_SYSTEM _PATH_SYS_CPU "/present"
#define _PATH_TOPO_PACKAGE_CPUS "/topology/package_cpus"
#define _PATH_FREQUENCY_MAX_LEN 100 #define _PATH_FREQUENCY_MAX_LEN 100
#define _PATH_CACHE_MAX_LEN 200 #define _PATH_CACHE_MAX_LEN 200
#define DEFAULT_FILE_SIZE 4096 #define _PATH_PACKAGE_MAX_LEN 200
char* read_file(char* path, int* len); char* read_file(char* path, int* len);
long get_max_freq_from_file(uint32_t core); long get_max_freq_from_file(uint32_t core);
@@ -36,5 +39,10 @@ long get_l1d_cache_size(uint32_t core);
long get_l2_cache_size(uint32_t core); long get_l2_cache_size(uint32_t core);
long get_l3_cache_size(uint32_t core); long get_l3_cache_size(uint32_t core);
int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level); int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level);
int get_num_sockets_package_cpus(struct topology* topo);
int get_ncores_from_cpuinfo(void);
char* get_field_from_cpuinfo(char* CPUINFO_FIELD);
bool is_devtree_compatible(char* str);
char* get_devtree_compatible(int *filelen);
#endif #endif

View File

@@ -11,6 +11,20 @@
#include "../common/udev.h" #include "../common/udev.h"
#include "../common/global.h" #include "../common/global.h"
static char *hv_vendors_name[] = {
[HV_VENDOR_KVM] = "KVM",
[HV_VENDOR_QEMU] = "QEMU",
[HV_VENDOR_VBOX] = "VirtualBox",
[HV_VENDOR_HYPERV] = "Microsoft Hyper-V",
[HV_VENDOR_VMWARE] = "VMware",
[HV_VENDOR_XEN] = "Xen",
[HV_VENDOR_PARALLELS] = "Parallels",
[HV_VENDOR_PHYP] = "pHyp",
[HV_VENDOR_BHYVE] = "bhyve",
[HV_VENDOR_APPLEVZ] = "Apple VZ",
[HV_VENDOR_INVALID] = STRING_UNKNOWN
};
struct cache* get_cache_info(struct cpuInfo* cpu) { struct cache* get_cache_info(struct cpuInfo* cpu) {
struct cache* cach = emalloc(sizeof(struct cache)); struct cache* cach = emalloc(sizeof(struct cache));
init_cache_struct(cach); init_cache_struct(cach);
@@ -63,24 +77,35 @@ struct topology* get_topology_info(struct cache* cach) {
printWarn("fill_core_ids_from_sys failed, output may be incomplete/invalid"); printWarn("fill_core_ids_from_sys failed, output may be incomplete/invalid");
for(int i=0; i < topo->total_cores; i++) core_ids[i] = 0; for(int i=0; i < topo->total_cores; i++) core_ids[i] = 0;
} }
if(!fill_package_ids_from_sys(package_ids, topo->total_cores)) { if(!fill_package_ids_from_sys(package_ids, topo->total_cores)) {
printWarn("fill_package_ids_from_sys failed, output may be incomplete/invalid"); printWarn("fill_package_ids_from_sys failed, output may be incomplete/invalid");
for(int i=0; i < topo->total_cores; i++) package_ids[i] = 0; for(int i=0; i < topo->total_cores; i++) package_ids[i] = 0;
} // fill_package_ids_from_sys failed, use udev to try
// to find the number of sockets
// 2. Socket detection topo->sockets = get_num_sockets_package_cpus(topo);
int *package_ids_count = emalloc(sizeof(int) * topo->total_cores); if (topo->sockets == UNKNOWN_DATA) {
for(int i=0; i < topo->total_cores; i++) { printWarn("get_num_sockets_package_cpus failed: assuming 1 socket");
package_ids_count[i] = 0; topo->sockets = 1;
}
for(int i=0; i < topo->total_cores; i++) {
package_ids_count[package_ids[i]]++;
}
for(int i=0; i < topo->total_cores; i++) {
if(package_ids_count[i] != 0) {
topo->sockets++;
} }
} }
else {
// fill_package_ids_from_sys succeeded, use the
// traditional socket detection algorithm
int *package_ids_count = emalloc(sizeof(int) * topo->total_cores);
for(int i=0; i < topo->total_cores; i++) {
package_ids_count[i] = 0;
}
for(int i=0; i < topo->total_cores; i++) {
package_ids_count[package_ids[i]]++;
}
for(int i=0; i < topo->total_cores; i++) {
if(package_ids_count[i] != 0) {
topo->sockets++;
}
}
free(package_ids_count);
}
// 3. Physical cores detection // 3. Physical cores detection
int *core_ids_unified = emalloc(sizeof(int) * topo->total_cores); int *core_ids_unified = emalloc(sizeof(int) * topo->total_cores);
@@ -105,13 +130,12 @@ struct topology* get_topology_info(struct cache* cach) {
free(core_ids); free(core_ids);
free(package_ids); free(package_ids);
free(package_ids_count);
free(core_ids_unified); free(core_ids_unified);
return topo; return topo;
} }
static inline uint32_t mfpvr() { static inline uint32_t mfpvr(void) {
uint32_t pvr; uint32_t pvr;
asm ("mfpvr %0" asm ("mfpvr %0"
@@ -123,12 +147,19 @@ struct uarch* get_cpu_uarch(struct cpuInfo* cpu) {
return get_uarch_from_pvr(cpu->pvr); return get_uarch_from_pvr(cpu->pvr);
} }
struct frequency* get_frequency_info() { struct frequency* get_frequency_info(void) {
struct frequency* freq = emalloc(sizeof(struct frequency)); struct frequency* freq = emalloc(sizeof(struct frequency));
freq->measured = false;
freq->max = get_max_freq_from_file(0); freq->max = get_max_freq_from_file(0);
freq->base = get_min_freq_from_file(0); freq->base = get_min_freq_from_file(0);
if(freq->max == UNKNOWN_DATA) {
// If we are unable to find it in the
// standard path, try /proc/cpuinfo
freq->max = get_frequency_from_cpuinfo();
}
return freq; return freq;
} }
@@ -139,7 +170,7 @@ int64_t get_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t
*/ */
//First check we have consistent data //First check we have consistent data
if(freq == UNKNOWN_FREQ) { if(freq == UNKNOWN_DATA) {
return -1; return -1;
} }
@@ -158,7 +189,29 @@ int64_t get_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t
return flops; return flops;
} }
struct cpuInfo* get_cpu_info() { struct hypervisor* get_hp_info(void) {
struct hypervisor* hv = emalloc(sizeof(struct hypervisor));
hv->present = false;
// Weird heuristic found in lscpu:
// https://github.com/util-linux/util-linux/blob/master/sys-utils/lscpu-virt.c
if(access("/proc" _PATH_DT_IBM_PARTIT_NAME, F_OK) == 0 &&
access("/proc" _PATH_DT_HMC_MANAGED, F_OK) == 0 &&
access("/proc" _PATH_DT_QEMU_WIDTH, F_OK) != 0) {
hv->present = true;
hv->hv_vendor = HV_VENDOR_PHYP;
}
else if(is_devtree_compatible("qemu,pseries")) {
hv->present = true;
hv->hv_vendor = HV_VENDOR_QEMU;
}
hv->hv_name = hv_vendors_name[hv->hv_vendor];
return hv;
}
struct cpuInfo* get_cpu_info(void) {
struct cpuInfo* cpu = emalloc(sizeof(struct cpuInfo)); struct cpuInfo* cpu = emalloc(sizeof(struct cpuInfo));
struct features* feat = emalloc(sizeof(struct features)); struct features* feat = emalloc(sizeof(struct features));
cpu->feat = feat; cpu->feat = feat;
@@ -172,8 +225,11 @@ struct cpuInfo* get_cpu_info() {
char* path = emalloc(sizeof(char) * (strlen(_PATH_DT) + strlen(_PATH_DT_PART) + 1)); char* path = emalloc(sizeof(char) * (strlen(_PATH_DT) + strlen(_PATH_DT_PART) + 1));
sprintf(path, "%s%s", _PATH_DT, _PATH_DT_PART); sprintf(path, "%s%s", _PATH_DT, _PATH_DT_PART);
cpu->cpu_name = read_file(path, &len); if((cpu->cpu_name = read_file(path, &len)) == NULL) {
printWarn("Could not open '%s'", path);
}
cpu->pvr = mfpvr(); cpu->pvr = mfpvr();
cpu->hv = get_hp_info();
cpu->arch = get_cpu_uarch(cpu); cpu->arch = get_cpu_uarch(cpu);
cpu->freq = get_frequency_info(); cpu->freq = get_frequency_info();
cpu->topo = get_topology_info(cpu->cach); cpu->topo = get_topology_info(cpu->cach);
@@ -181,9 +237,6 @@ struct cpuInfo* get_cpu_info() {
feat->altivec = has_altivec(cpu->arch); feat->altivec = has_altivec(cpu->arch);
cpu->peak_performance = get_peak_performance(cpu, cpu->topo, get_freq(cpu->freq)); cpu->peak_performance = get_peak_performance(cpu, cpu->topo, get_freq(cpu->freq));
if(cpu->cach == NULL || cpu->topo == NULL) {
return NULL;
}
return cpu; return cpu;
} }

View File

@@ -1,9 +1,9 @@
#ifndef __POWERPC__ #ifndef __CPUFETCH_POWERPC__
#define __POWERPC__ #define __CPUFETCH_POWERPC__
#include "../common/cpu.h" #include "../common/cpu.h"
struct cpuInfo* get_cpu_info(); struct cpuInfo* get_cpu_info(void);
char* get_str_altivec(struct cpuInfo* cpu); char* get_str_altivec(struct cpuInfo* cpu);
char* get_str_topology(struct topology* topo, bool dual_socket); char* get_str_topology(struct topology* topo, bool dual_socket);
void print_debug(struct cpuInfo* cpu); void print_debug(struct cpuInfo* cpu);

View File

@@ -3,7 +3,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/auxv.h>
#include <errno.h> #include <errno.h>
#include "uarch.h" #include "uarch.h"
@@ -26,6 +25,7 @@ enum {
UARCH_PPC603, UARCH_PPC603,
UARCH_PPC440, UARCH_PPC440,
UARCH_PPC470, UARCH_PPC470,
UARCH_ESPRESSO, // Not exactly an uarch, but the codename of Wii U
UARCH_PPC970, UARCH_PPC970,
UARCH_PPC970FX, UARCH_PPC970FX,
UARCH_PPC970MP, UARCH_PPC970MP,
@@ -36,6 +36,7 @@ enum {
UARCH_POWER7, UARCH_POWER7,
UARCH_POWER7PLUS, UARCH_POWER7PLUS,
UARCH_POWER8, UARCH_POWER8,
UARCH_POWER8_DD21,
UARCH_POWER9, UARCH_POWER9,
UARCH_POWER9_DD20, UARCH_POWER9_DD20,
UARCH_POWER9_DD21, UARCH_POWER9_DD21,
@@ -75,6 +76,7 @@ void fill_uarch(struct uarch* arch, MICROARCH u) {
FILL_UARCH(arch->uarch, UARCH_PPC603, "PowerPC 603", UNK) // varies FILL_UARCH(arch->uarch, UARCH_PPC603, "PowerPC 603", UNK) // varies
FILL_UARCH(arch->uarch, UARCH_PPC440, "PowerPC 440", UNK) FILL_UARCH(arch->uarch, UARCH_PPC440, "PowerPC 440", UNK)
FILL_UARCH(arch->uarch, UARCH_PPC470, "PowerPC 470", 45) // strange... FILL_UARCH(arch->uarch, UARCH_PPC470, "PowerPC 470", 45) // strange...
FILL_UARCH(arch->uarch, UARCH_ESPRESSO, "Espresso", 45) // https://en.wikipedia.org/wiki/PowerPC_7xx#Espresso, https://en.wikipedia.org/wiki/Espresso_(processor), https://github.com/Dr-Noob/cpufetch/issues/231
FILL_UARCH(arch->uarch, UARCH_PPC970, "PowerPC 970", 130) FILL_UARCH(arch->uarch, UARCH_PPC970, "PowerPC 970", 130)
FILL_UARCH(arch->uarch, UARCH_PPC970FX, "PowerPC 970FX", 90) FILL_UARCH(arch->uarch, UARCH_PPC970FX, "PowerPC 970FX", 90)
FILL_UARCH(arch->uarch, UARCH_PPC970MP, "PowerPC 970MP", 90) FILL_UARCH(arch->uarch, UARCH_PPC970MP, "PowerPC 970MP", 90)
@@ -85,6 +87,7 @@ void fill_uarch(struct uarch* arch, MICROARCH u) {
FILL_UARCH(arch->uarch, UARCH_POWER7, "POWER7", 45) FILL_UARCH(arch->uarch, UARCH_POWER7, "POWER7", 45)
FILL_UARCH(arch->uarch, UARCH_POWER7PLUS, "POWER7+", 32) FILL_UARCH(arch->uarch, UARCH_POWER7PLUS, "POWER7+", 32)
FILL_UARCH(arch->uarch, UARCH_POWER8, "POWER8", 22) FILL_UARCH(arch->uarch, UARCH_POWER8, "POWER8", 22)
FILL_UARCH(arch->uarch, UARCH_POWER8_DD21, "POWER8 (DD2.1)", 22)
FILL_UARCH(arch->uarch, UARCH_POWER9, "POWER9", 14) FILL_UARCH(arch->uarch, UARCH_POWER9, "POWER9", 14)
FILL_UARCH(arch->uarch, UARCH_POWER9_DD20, "POWER9 (DD2.0)", 14) FILL_UARCH(arch->uarch, UARCH_POWER9_DD20, "POWER9 (DD2.0)", 14)
FILL_UARCH(arch->uarch, UARCH_POWER9_DD21, "POWER9 (DD2.1)", 14) FILL_UARCH(arch->uarch, UARCH_POWER9_DD21, "POWER9 (DD2.1)", 14)
@@ -101,7 +104,19 @@ void fill_uarch(struct uarch* arch, MICROARCH u) {
} }
/* /*
* PVR masks/values from arch/powerpc/kernel/cputable.c (Linux kernel) * PVR masks/values from Linux kernel:
* - arch/powerpc/kernel/cputable.c (kernel <= 6.0)
* - arch/powerpc/kernel/cpu_specs_book3s_64.h (kernel >= 6.1)
*
* In the kernel, there is a POWER8E identifier. In
* https://wiki.raptorcs.com/wiki/POWER8E it says it is
* actually DD2.1, while other POWER8 should be DD2.0.
* The last assumption does not seem to be correct according
* to https://openbenchmarking.org/s/POWER8NVL, which shows a
* POWER8NVL where kernel says it is DD1.0. We implement this
* to show only the uarch, not the revision, since it seems a bit
* redundant?
*
* This list may be incorrect, incomplete or overly simplified, * This list may be incorrect, incomplete or overly simplified,
* specially in the case of 32 bit entries * specially in the case of 32 bit entries
*/ */
@@ -126,7 +141,7 @@ struct uarch* get_uarch_from_pvr(uint32_t pvr) {
CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000006, UARCH_POWER10) CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000006, UARCH_POWER10)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x003f0000, UARCH_POWER7) CHECK_UARCH(arch, pvr, 0xffff0000, 0x003f0000, UARCH_POWER7)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004A0000, UARCH_POWER7PLUS) CHECK_UARCH(arch, pvr, 0xffff0000, 0x004A0000, UARCH_POWER7PLUS)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004b0000, UARCH_POWER8) CHECK_UARCH(arch, pvr, 0xffff0000, 0x004b0000, UARCH_POWER8_DD21)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004c0000, UARCH_POWER8) CHECK_UARCH(arch, pvr, 0xffff0000, 0x004c0000, UARCH_POWER8)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004d0000, UARCH_POWER8) CHECK_UARCH(arch, pvr, 0xffff0000, 0x004d0000, UARCH_POWER8)
CHECK_UARCH(arch, pvr, 0xffffefff, 0x004e0200, UARCH_POWER9_DD20) CHECK_UARCH(arch, pvr, 0xffffefff, 0x004e0200, UARCH_POWER9_DD20)
@@ -221,6 +236,7 @@ struct uarch* get_uarch_from_pvr(uint32_t pvr) {
CHECK_UARCH(arch, pvr, 0xffff0000, 0x7ff50000, UARCH_PPC470) CHECK_UARCH(arch, pvr, 0xffff0000, 0x7ff50000, UARCH_PPC470)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00050000, UARCH_PPC470) CHECK_UARCH(arch, pvr, 0xffff0000, 0x00050000, UARCH_PPC470)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x11a50000, UARCH_PPC470) CHECK_UARCH(arch, pvr, 0xffff0000, 0x11a50000, UARCH_PPC470)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x70010201, UARCH_ESPRESSO)
UARCH_END UARCH_END
return arch; return arch;
@@ -235,6 +251,7 @@ bool has_altivec(struct uarch* arch) {
case UARCH_POWER7: case UARCH_POWER7:
case UARCH_POWER7PLUS: case UARCH_POWER7PLUS:
case UARCH_POWER8: case UARCH_POWER8:
case UARCH_POWER8_DD21:
case UARCH_POWER9: case UARCH_POWER9:
case UARCH_POWER9_DD20: case UARCH_POWER9_DD20:
case UARCH_POWER9_DD21: case UARCH_POWER9_DD21:
@@ -266,9 +283,6 @@ char* get_str_process(struct cpuInfo* cpu) {
if(process == UNK) { if(process == UNK) {
snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN); snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
} }
else if(process > 100) {
sprintf(str, "%.2fum", (double)process/100);
}
else if(process > 0){ else if(process > 0){
sprintf(str, "%dnm", process); sprintf(str, "%dnm", process);
} }

View File

@@ -1,16 +1,19 @@
#include <errno.h> #include <errno.h>
#include "../common/udev.h"
#include "../common/global.h" #include "../common/global.h"
#include "udev.h" #include "udev.h"
#define _PATH_TOPO_CORE_ID "topology/core_id" #define _PATH_TOPO_CORE_ID "topology/core_id"
#define _PATH_TOPO_PACKAGE_ID "topology/physical_package_id" #define _PATH_TOPO_PACKAGE_ID "topology/physical_package_id"
#define CPUINFO_FREQUENCY_STR "clock\t\t: "
bool fill_array_from_sys(int *core_ids, int total_cores, char* SYS_PATH) { bool fill_array_from_sys(int *core_ids, int total_cores, char* SYS_PATH) {
int filelen; int filelen;
char* buf; char* buf;
char* end; char* end;
char path[128]; char path[128];
memset(name, 0, sizeof(char) * 128);
for(int i=0; i < total_cores; i++) { for(int i=0; i < total_cores; i++) {
sprintf(path, "%s%s/cpu%d/%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, i, SYS_PATH); sprintf(path, "%s%s/cpu%d/%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, i, SYS_PATH);
@@ -36,5 +39,52 @@ bool fill_core_ids_from_sys(int *core_ids, int total_cores) {
} }
bool fill_package_ids_from_sys(int* package_ids, int total_cores) { bool fill_package_ids_from_sys(int* package_ids, int total_cores) {
return fill_array_from_sys(package_ids, total_cores, _PATH_TOPO_PACKAGE_ID); bool status = fill_array_from_sys(package_ids, total_cores, _PATH_TOPO_PACKAGE_ID);
if(status) {
// fill_array_from_sys completed successfully, but we
// must to check the integrity of the package_ids array
for(int i=0; i < total_cores; i++) {
if(package_ids[i] == -1) {
printWarn("fill_package_ids_from_sys: package_ids[%d] = -1", i);
return false;
}
else if(package_ids[i] >= total_cores || package_ids[i] < 0) {
printBug("fill_package_ids_from_sys: package_ids[%d] = %d", i, package_ids[i]);
return false;
}
}
return true;
}
return false;
}
long get_frequency_from_cpuinfo(void) {
char* freq_str = get_field_from_cpuinfo(CPUINFO_FREQUENCY_STR);
if(freq_str == NULL) {
return UNKNOWN_DATA;
}
else {
// freq_str should be in the form XXXX.YYYYYYMHz
char* dot = strstr(freq_str, ".");
freq_str[dot-freq_str] = '\0';
char* end;
errno = 0;
long ret = strtol(freq_str, &end, 10);
if(errno != 0) {
printBug("strtol: %s", strerror(errno));
free(freq_str);
return UNKNOWN_DATA;
}
// We consider it an error if frequency is
// greater than 10 GHz or less than 100 MHz
if(ret > 10000 || ret < 100) {
printBug("Invalid data was read from file '%s': %ld\n", CPUINFO_FREQUENCY_STR, ret);
return UNKNOWN_DATA;
}
return ret;
}
} }

View File

@@ -2,10 +2,15 @@
#define __UDEV_PPC__ #define __UDEV_PPC__
#include "../common/udev.h" #include "../common/udev.h"
#define _PATH_DT "/proc/device-tree/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/processor@1000" #define _PATH_DT "/proc/device-tree/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/processor@1000"
#define _PATH_DT_PART "/part-number" #define _PATH_DT_PART "/part-number"
#define _PATH_DT_IBM_PARTIT_NAME "/device-tree/ibm,partition-name"
#define _PATH_DT_HMC_MANAGED "/device-tree/hmc-managed?"
#define _PATH_DT_QEMU_WIDTH "/device-tree/chosen/qemu,graphic-width"
bool fill_core_ids_from_sys(int *core_ids, int total_cores); bool fill_core_ids_from_sys(int *core_ids, int total_cores);
bool fill_package_ids_from_sys(int* package_ids, int total_cores); bool fill_package_ids_from_sys(int* package_ids, int total_cores);
int get_num_sockets_package_cpus(struct topology* topo);
long get_frequency_from_cpuinfo(void);
#endif #endif

206
src/riscv/riscv.c Normal file
View File

@@ -0,0 +1,206 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "../common/global.h"
#include "../common/udev.h"
#include "udev.h"
#include "uarch.h"
#include "soc.h"
#define SET_ISA_EXT_MAP(name, bit) \
if(strncmp(multi_letter_extension, name, \
multi_letter_extension_len) == 0) { \
ext->mask |= 1UL << bit; \
maskset = true; \
} \
struct frequency* get_frequency_info(uint32_t core) {
struct frequency* freq = emalloc(sizeof(struct frequency));
freq->measured = false;
freq->base = UNKNOWN_DATA;
freq->max = get_max_freq_from_file(core);
return freq;
}
int64_t get_peak_performance(struct cpuInfo* cpu) {
//First check we have consistent data
if(get_freq(cpu->freq) == UNKNOWN_DATA) {
return -1;
}
int64_t flops = cpu->topo->total_cores * (get_freq(cpu->freq) * 1000000);
return flops;
}
// Returns the length of the multi-letter
// extension, or -1 if an error occurs
int parse_multi_letter_extension(struct extensions* ext, char* e) {
if(*e != '_') return -1;
char* multi_letter_extension_end = strstr(e+1, "_");
if(multi_letter_extension_end == NULL) {
// This is the last extension, find the end
// of the string
multi_letter_extension_end = e + strlen(e);
}
int multi_letter_extension_len = multi_letter_extension_end-(e+1);
bool maskset = false;
char* multi_letter_extension = emalloc(multi_letter_extension_len);
strncpy(multi_letter_extension, e+1, multi_letter_extension_len);
// This should be up-to-date with
// https://elixir.bootlin.com/linux/latest/source/arch/riscv/kernel/cpufeature.c
// which should represent the list of extensions available in real chips
SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF)
SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC)
SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL)
SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT)
SET_ISA_EXT_MAP("zbb", RISCV_ISA_EXT_ZBB)
SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM)
SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE)
SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT)
SET_ISA_EXT_MAP("zicboz", RISCV_ISA_EXT_ZICBOZ)
SET_ISA_EXT_MAP("smaia", RISCV_ISA_EXT_SMAIA)
SET_ISA_EXT_MAP("ssaia", RISCV_ISA_EXT_SSAIA)
SET_ISA_EXT_MAP("zba", RISCV_ISA_EXT_ZBA)
SET_ISA_EXT_MAP("zbs", RISCV_ISA_EXT_ZBS)
SET_ISA_EXT_MAP("zicntr", RISCV_ISA_EXT_ZICNTR)
SET_ISA_EXT_MAP("zicsr", RISCV_ISA_EXT_ZICSR)
SET_ISA_EXT_MAP("zifencei", RISCV_ISA_EXT_ZIFENCEI)
SET_ISA_EXT_MAP("zihpm", RISCV_ISA_EXT_ZIHPM)
if(!maskset) {
printBug("parse_multi_letter_extension: Unknown multi-letter extension: %s", multi_letter_extension);
return -1;
}
return multi_letter_extension_len;
}
bool valid_extension(char ext) {
bool found = false;
uint64_t idx = 0;
while(idx < sizeof(extension_list)/sizeof(extension_list[0]) && !found) {
found = (extension_list[idx].id == (ext - 'a'));
if(!found) idx++;
}
return found;
}
struct extensions* get_extensions_from_str(char* str) {
struct extensions* ext = emalloc(sizeof(struct extensions));
ext->mask = 0;
ext->str = NULL;
if(str == NULL) {
return ext;
}
int len = strlen(str);
ext->str = ecalloc(len+1, sizeof(char));
strncpy(ext->str, str, sizeof(char) * len);
// Code inspired in Linux kernel (riscv_fill_hwcap):
// https://elixir.bootlin.com/linux/v6.2.10/source/arch/riscv/kernel/cpufeature.c
char* isa = str;
if (!strncmp(isa, "rv32", 4))
isa += 4;
else if (!strncmp(isa, "rv64", 4))
isa += 4;
else {
printBug("get_extensions_from_str: ISA string must start with rv64 or rv32");
return ext;
}
for(char* e = isa; *e != '\0'; e++) {
if(*e == '_') {
// Multi-letter extension
int multi_letter_extension_len = parse_multi_letter_extension(ext, e);
if(multi_letter_extension_len == -1) {
return ext;
}
e += multi_letter_extension_len;
}
else {
// Single-letter extensions 's' and 'u' are invalid
// according to Linux kernel (arch/riscv/kernel/cpufeature.c:
// riscv_fill_hwcap). Optionally, we could opt for using
// hwcap instead of cpuinfo to avoid this
if (*e == 's' || *e == 'u') {
continue;
}
// Make sure that the extension is valid before
// adding it to the mask
if(valid_extension(*e)) {
int n = *e - 'a';
ext->mask |= 1UL << n;
}
else {
printBug("get_extensions_from_str: Invalid extension: '%c'", *e);
}
}
}
return ext;
}
struct cpuInfo* get_cpu_info(void) {
struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo));
//init_cpu_info(cpu);
struct topology* topo = emalloc(sizeof(struct topology));
topo->total_cores = get_ncores_from_cpuinfo();
topo->cach = NULL;
cpu->topo = topo;
char* cpuinfo_str = get_uarch_from_cpuinfo();
char* ext_str = get_extensions_from_cpuinfo();
cpu->hv = emalloc(sizeof(struct hypervisor));
cpu->hv->present = false;
cpu->ext = get_extensions_from_str(ext_str);
if(cpu->ext->str != NULL && cpu->ext->mask == 0) return NULL;
cpu->arch = get_uarch_from_cpuinfo_str(cpuinfo_str, cpu);
cpu->soc = get_soc(cpu);
cpu->freq = get_frequency_info(0);
cpu->peak_performance = get_peak_performance(cpu);
return cpu;
}
//TODO: Might be worth refactoring with other archs
char* get_str_topology(struct cpuInfo* cpu, struct topology* topo) {
uint32_t size = 3+7+1;
char* string = emalloc(sizeof(char)*size);
snprintf(string, size, "%d cores", topo->total_cores);
return string;
}
char* get_str_extensions(struct cpuInfo* cpu) {
if(cpu->ext != NULL) {
return cpu->ext->str;
}
return NULL;
}
void print_debug(struct cpuInfo* cpu) {
printf("- soc: ");
if(cpu->soc->raw_name == NULL) {
printf("NULL\n");
}
else {
printf("'%s'\n", cpu->soc->raw_name);
}
printf("- uarch: ");
char* arch_cpuinfo_str = get_arch_cpuinfo_str(cpu);
if(arch_cpuinfo_str == NULL) {
printf("NULL\n");
}
else {
printf("'%s'\n", arch_cpuinfo_str);
}
}

82
src/riscv/riscv.h Normal file
View File

@@ -0,0 +1,82 @@
#ifndef __RISCV__
#define __RISCV__
#include "../common/cpu.h"
struct extension {
int id;
char* str;
};
#define RISCV_ISA_EXT_NAME_LEN_MAX 32
#define RISCV_ISA_EXT_BASE 26
// https://elixir.bootlin.com/linux/latest/source/arch/riscv/include/asm/hwcap.h
// This enum represent the logical ID for multi-letter RISC-V ISA extensions.
// The logical ID should start from RISCV_ISA_EXT_BASE
enum riscv_isa_ext_id {
RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE,
RISCV_ISA_EXT_SSTC,
RISCV_ISA_EXT_SVINVAL,
RISCV_ISA_EXT_SVPBMT,
RISCV_ISA_EXT_ZBB,
RISCV_ISA_EXT_ZICBOM,
RISCV_ISA_EXT_ZIHINTPAUSE,
RISCV_ISA_EXT_SVNAPOT,
RISCV_ISA_EXT_ZICBOZ,
RISCV_ISA_EXT_SMAIA,
RISCV_ISA_EXT_SSAIA,
RISCV_ISA_EXT_ZBA,
RISCV_ISA_EXT_ZBS,
RISCV_ISA_EXT_ZICNTR,
RISCV_ISA_EXT_ZICSR,
RISCV_ISA_EXT_ZIFENCEI,
RISCV_ISA_EXT_ZIHPM,
RISCV_ISA_EXT_ID_MAX
};
// https://five-embeddev.com/riscv-isa-manual/latest/preface.html#preface
// https://en.wikichip.org/wiki/risc-v/standard_extensions
// Included all except for G
static const struct extension extension_list[] = {
{ 'i' - 'a', "(I) Integer Instruction Set" },
{ 'm' - 'a', "(M) Integer Multiplication and Division" },
{ 'a' - 'a', "(A) Atomic Instructions" },
{ 'f' - 'a', "(F) Single-Precision Floating-Point" },
{ 'd' - 'a', "(D) Double-Precision Floating-Point" },
{ 'q' - 'a', "(Q) Quad-Precision Floating-Point" },
{ 'l' - 'a', "(L) Decimal Floating-Point" },
{ 'c' - 'a', "(C) Compressed Instructions" },
{ 'b' - 'a', "(B) Double-Precision Floating-Point" },
{ 'j' - 'a', "(J) Dynamically Translated Languages" },
{ 't' - 'a', "(T) Transactional Memory" },
{ 'p' - 'a', "(P) Packed-SIMD Instructions" },
{ 'v' - 'a', "(V) Vector Operations" },
{ 'n' - 'a', "(N) User-Level Interrupts" },
{ 'h' - 'a', "(H) Hypervisor" },
// multi-letter extensions
{ RISCV_ISA_EXT_SSCOFPMF, "(Sscofpmf) Count OverFlow and Privilege Mode Filtering" },
{ RISCV_ISA_EXT_SSTC, "(Sstc) S and VS level Time Compare" },
{ RISCV_ISA_EXT_SVINVAL, "(Svinval) Fast TLB Invalidation" },
{ RISCV_ISA_EXT_SVPBMT, "(Svpbmt) Page-based Memory Types" },
{ RISCV_ISA_EXT_ZBB, "(Zbb) Basic bit-manipulation" },
{ RISCV_ISA_EXT_ZICBOM, "(Zicbom) Cache Block Management Operations" },
{ RISCV_ISA_EXT_ZIHINTPAUSE, "(Zihintpause) Pause Hint" },
{ RISCV_ISA_EXT_SVNAPOT, "(Svnapot) Naturally Aligned Power of Two Pages" },
{ RISCV_ISA_EXT_ZICBOZ, "(Zicboz) Cache Block Zero Operations" },
{ RISCV_ISA_EXT_SMAIA, "(Smaia) Advanced Interrupt Architecture" },
{ RISCV_ISA_EXT_SSAIA, "(Ssaia) Advanced Interrupt Architecture" },
{ RISCV_ISA_EXT_ZBA, "(Zba) Address Generation" },
{ RISCV_ISA_EXT_ZBS, "(Zbs) Single-bit Instructions" },
{ RISCV_ISA_EXT_ZICNTR, "(Zicntr) Base Counters and Timers" },
{ RISCV_ISA_EXT_ZICSR, "(Zicsr) Control and Status Register" },
{ RISCV_ISA_EXT_ZIFENCEI, "(Zifencei) Instruction-Fetch Fence" },
{ RISCV_ISA_EXT_ZIHPM, "(Zihpm) Hardware Performance Counters" }
};
struct cpuInfo* get_cpu_info(void);
char* get_str_topology(struct cpuInfo* cpu, struct topology* topo);
char* get_str_extensions(struct cpuInfo* cpu);
void print_debug(struct cpuInfo* cpu);
#endif

93
src/riscv/soc.c Normal file
View File

@@ -0,0 +1,93 @@
#include "soc.h"
#include "socs.h"
#include "udev.h"
#include "../common/global.h"
#include <string.h>
bool match_sifive(char* soc_name, struct system_on_chip* soc) {
char* tmp = soc_name;
// Dont know if it makes sense in RISC-V
/*if((tmp = strstr(soc_name, "???")) == NULL)
return false;*/
//soc->vendor = ???
SOC_START
SOC_EQ(tmp, "fu740", "Freedom U740", SOC_SIFIVE_U740, soc, 40)
SOC_END
}
bool match_starfive(char* soc_name, struct system_on_chip* soc) {
SOC_START
SOC_EQ(soc_name, "jh7110#", "VisionFive 2", SOC_STARFIVE_VF2, soc, 28) // https://blog.bitsofnetworks.org/benchmarking-risc-v-visionfive-2-vs-the-world.html
SOC_EQ(soc_name, "jh7110", "VisionFive 2", SOC_STARFIVE_VF2, soc, 28)
SOC_END
}
bool match_allwinner(char* soc_name, struct system_on_chip* soc) {
SOC_START
SOC_EQ(soc_name, "sun20i-d1", "D1-H", SOC_ALLWINNER_D1H, soc, 22)
SOC_END
}
bool match_sipeed(char* soc_name, struct system_on_chip* soc) {
SOC_START
SOC_EQ(soc_name, "light", "Lichee Pi 4A", SOC_SIPEED_LICHEEPI4A, soc, 12) // https://github.com/Dr-Noob/cpufetch/issues/200, https://sipeed.com/licheepi4a
SOC_END
}
struct system_on_chip* parse_soc_from_string(struct system_on_chip* soc) {
char* raw_name = soc->raw_name;
if(match_starfive(raw_name, soc))
return soc;
if(match_allwinner(raw_name, soc))
return soc;
if(match_sifive(raw_name, soc))
return soc;
match_sipeed(raw_name, soc);
return soc;
}
struct system_on_chip* guess_soc_from_devtree(struct system_on_chip* soc) {
char* tmp = get_hardware_from_devtree();
if(tmp != NULL) {
soc->raw_name = tmp;
return parse_soc_from_string(soc);
}
return soc;
}
struct system_on_chip* get_soc(struct cpuInfo* cpu) {
struct system_on_chip* soc = emalloc(sizeof(struct system_on_chip));
soc->raw_name = NULL;
soc->vendor = SOC_VENDOR_UNKNOWN;
soc->model = SOC_MODEL_UNKNOWN;
soc->process = UNKNOWN;
soc = guess_soc_from_devtree(soc);
if(soc->vendor == SOC_VENDOR_UNKNOWN) {
if(soc->raw_name != NULL) {
printWarn("SoC detection failed using device tree: Found '%s' string", soc->raw_name);
}
else {
printWarn("SoC detection failed using device tree");
}
}
if(soc->model == SOC_MODEL_UNKNOWN) {
// raw_name might not be NULL, but if we were unable to find
// the exact SoC, just print "Unkwnown"
soc->raw_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
snprintf(soc->raw_name, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
}
return soc;
}

10
src/riscv/soc.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef __SOC_RISCV__
#define __SOC_RISCV__
#include "../common/soc.h"
#include "../common/cpu.h"
#include <stdint.h>
struct system_on_chip* get_soc(struct cpuInfo* cpu);
#endif

28
src/riscv/socs.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef __SOCS__
#define __SOCS__
#include "soc.h"
// List of supported SOCs
enum {
// SIFIVE
SOC_SIFIVE_U740,
// STARFIVE
SOC_STARFIVE_VF2,
// ALLWINNER
SOC_ALLWINNER_D1H,
// SIPEED
SOC_SIPEED_LICHEEPI4A,
// UNKNOWN
SOC_MODEL_UNKNOWN
};
inline static VENDOR get_soc_vendor_from_soc(SOC soc) {
if(soc >= SOC_SIFIVE_U740 && soc <= SOC_SIFIVE_U740) return SOC_VENDOR_SIFIVE;
if(soc >= SOC_STARFIVE_VF2 && soc <= SOC_STARFIVE_VF2) return SOC_VENDOR_STARFIVE;
if(soc >= SOC_ALLWINNER_D1H && soc <= SOC_ALLWINNER_D1H) return SOC_VENDOR_ALLWINNER;
if(soc >= SOC_SIPEED_LICHEEPI4A && soc <= SOC_SIPEED_LICHEEPI4A) return SOC_VENDOR_SIPEED;
return SOC_VENDOR_UNKNOWN;
}
#endif

84
src/riscv/uarch.c Normal file
View File

@@ -0,0 +1,84 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uarch.h"
#include "../common/global.h"
typedef uint32_t MICROARCH;
struct uarch {
MICROARCH uarch;
char* uarch_str;
char* cpuinfo_str;
};
enum {
UARCH_UNKNOWN,
// SIFIVE
UARCH_U54,
UARCH_U74,
// THEAD
UARCH_C906,
UARCH_C910
};
#define UARCH_START if (false) {}
#define CHECK_UARCH(arch, cpu, cpuinfo_str, uarch_str, str, uarch, vendor) \
else if (strcmp(cpuinfo_str, uarch_str) == 0) fill_uarch(arch, cpu, str, uarch, vendor);
#define UARCH_END else { printBug("Unknown microarchitecture detected: uarch='%s'", cpuinfo_str); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u, VENDOR vendor) {
arch->uarch = u;
cpu->cpu_vendor = vendor;
arch->uarch_str = emalloc(sizeof(char) * (strlen(str)+1));
strcpy(arch->uarch_str, str);
}
// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml
// SiFive: https://www.sifive.com/risc-v-core-ip
// T-Head: https://www.t-head.cn/product/c906
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu) {
struct uarch* arch = emalloc(sizeof(struct uarch));
arch->cpuinfo_str = cpuinfo_str;
if(cpuinfo_str == NULL) {
printWarn("get_uarch_from_cpuinfo: Unable to detect microarchitecture, cpuinfo_str is NULL");
fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN);
return arch;
}
// U74/U74-MC:
// SiFive says that U74-MC is "Multicore: four U74 cores and one S76 core" while
// U74 is "High performance Linux-capable processor". It's like U74-MC is somehow a small SoC containing
// the U74 and the S76? Then U74-MC is not a microarchitecture per se...
UARCH_START
CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,bullet0", "U74", UARCH_U74, CPU_VENDOR_SIFIVE) // bullet0 is present in U740, which has U74
// CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,e5", "XXXXXX", UARCH_U74, CPU_VENDOR_SIFIVE)
// CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,e7", "XXXXXX", UARCH_U74, CPU_VENDOR_SIFIVE)
// CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,e71", "XXXXXX", UARCH_U74, CPU_VENDOR_SIFIVE)
// CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,rocket0", "XXXXXX", UARCH_U74, CPU_VENDOR_SIFIVE)
// CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,u5", "XXXXXX", UARCH_U74, CPU_VENDOR_SIFIVE)
CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,u54", "U54", UARCH_U54, CPU_VENDOR_SIFIVE)
// CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,u7", "XXXXXX", UARCH_U74, CPU_VENDOR_SIFIVE)
CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,u74", "U74", UARCH_U74, CPU_VENDOR_SIFIVE)
CHECK_UARCH(arch, cpu, cpuinfo_str, "sifive,u74-mc", "U74", UARCH_U74, CPU_VENDOR_SIFIVE)
CHECK_UARCH(arch, cpu, cpuinfo_str, "thead,c906", "T-Head C906", UARCH_C906, CPU_VENDOR_THEAD)
CHECK_UARCH(arch, cpu, cpuinfo_str, "thead,c910", "T-Head C910", UARCH_C910, CPU_VENDOR_THEAD)
UARCH_END
return arch;
}
char* get_str_uarch(struct cpuInfo* cpu) {
return cpu->arch->uarch_str;
}
char* get_arch_cpuinfo_str(struct cpuInfo* cpu) {
return cpu->arch->cpuinfo_str;
}
void free_uarch_struct(struct uarch* arch) {
free(arch->uarch_str);
free(arch);
}

14
src/riscv/uarch.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef __UARCH__
#define __UARCH__
#include <stdint.h>
#include "riscv.h"
struct uarch;
char* get_arch_cpuinfo_str(struct cpuInfo* cpu);
char* get_str_uarch(struct cpuInfo* cpu);
void free_uarch_struct(struct uarch* arch);
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu);
#endif

89
src/riscv/udev.c Normal file
View File

@@ -0,0 +1,89 @@
#include <errno.h>
#include <string.h>
#include "../common/global.h"
#include "udev.h"
#define _PATH_DEVTREE "/proc/device-tree/compatible"
#define CPUINFO_UARCH_STR "uarch\t\t: "
#define CPUINFO_EXTENSIONS_STR "isa\t\t: "
#define DEVTREE_HARDWARE_FIELD 0
char* get_field_from_devtree(int DEVTREE_FIELD) {
int filelen;
char* buf;
if((buf = read_file(_PATH_DEVTREE, &filelen)) == NULL) {
printWarn("read_file: %s: %s", _PATH_DEVTREE, strerror(errno));
return NULL;
}
// Here we would use strstr to find the comma.
// However, the device-tree file may contain NULL
// bytes in the middle of the string, which would
// cause strstr to return NULL even when there might
// be an occurence after the NULL byte
//
// We iterate the string backwards to find the field
// in position n-DEVTREE_HARDWARE_FIELD where n
// is the number of fields.
int i=0;
char* tmp1 = buf+filelen-1;
do {
tmp1--;
if(*tmp1 == ',') i++;
} while(tmp1 != buf && i <= DEVTREE_FIELD);
if(tmp1 == buf) {
printWarn("get_field_from_devtree: Unable to find field %d", DEVTREE_FIELD);
return NULL;
}
tmp1++;
int strlen = filelen-(tmp1-buf);
char* hardware = ecalloc(strlen, sizeof(char));
strncpy(hardware, tmp1, strlen-1);
return hardware;
}
char* parse_cpuinfo_field(char* field_str) {
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUINFO, &filelen)) == NULL) {
printWarn("read_file: %s: %s", _PATH_CPUINFO, strerror(errno));
return NULL;
}
char* tmp = strstr(buf, field_str);
if(tmp == NULL) {
printWarn("parse_cpuinfo_field: Unable to find field %s", field_str);
return NULL;
}
tmp += strlen(field_str);
char* end = strstr(tmp, "\n");
if(end == NULL) {
printWarn("parse_cpuinfo_field: Unable to find newline after field %s", field_str);
return NULL;
}
int ret_strlen = (end-tmp);
char* ret = ecalloc(ret_strlen+1, sizeof(char));
strncpy(ret, tmp, sizeof(char) * ret_strlen);
return ret;
}
char* get_hardware_from_devtree(void) {
return get_field_from_devtree(DEVTREE_HARDWARE_FIELD);
}
char* get_uarch_from_cpuinfo(void) {
return parse_cpuinfo_field(CPUINFO_UARCH_STR);
}
char* get_extensions_from_cpuinfo(void) {
return parse_cpuinfo_field(CPUINFO_EXTENSIONS_STR);
}

12
src/riscv/udev.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef __UDEV_RISCV__
#define __UDEV_RISCV__
#include "../common/udev.h"
#define UNKNOWN -1
char* get_hardware_from_devtree(void);
char* get_uarch_from_cpuinfo(void);
char* get_extensions_from_cpuinfo(void);
#endif

View File

@@ -7,8 +7,6 @@
#elif defined __FreeBSD__ #elif defined __FreeBSD__
#include <sys/param.h> #include <sys/param.h>
#include <sys/cpuset.h> #include <sys/cpuset.h>
#elif defined __APPLE__
#define UNUSED(x) (void)(x)
#endif #endif
#include <stdlib.h> #include <stdlib.h>
@@ -74,31 +72,58 @@ uint32_t get_apic_id(bool x2apic_id) {
} }
} }
#ifndef __APPLE__ #ifdef __linux__
bool bind_to_cpu(int cpu_id) { int get_total_cores_module(int total_cores, int module) {
#ifdef _WIN32 int total_modules = 2;
HANDLE process = GetCurrentProcess(); int32_t current_module_idx = -1;
DWORD_PTR processAffinityMask = 1 << cpu_id; bool end = false;
return SetProcessAffinityMask(process, processAffinityMask); int32_t* core_types = emalloc(sizeof(uint32_t) * total_modules);
#elif defined __linux__ for(int i=0; i < total_modules; i++) core_types[i] = -1;
cpu_set_t currentCPU; int cores_in_module = 0;
CPU_ZERO(&currentCPU); int i = 0;
CPU_SET(cpu_id, &currentCPU);
if (sched_setaffinity (0, sizeof(currentCPU), &currentCPU) == -1) { // Get the original mask to restore it later
printWarn("sched_setaffinity: %s", strerror(errno)); cpu_set_t original_mask;
return false; if(sched_getaffinity(0, sizeof(original_mask), &original_mask) == -1) {
printWarn("sched_getaffinity: %s", strerror(errno));
return false;
}
while(!end) {
if(!bind_to_cpu(i)) {
return -1;
} }
return true; uint32_t eax = 0x0000001A;
#elif defined __FreeBSD__ uint32_t ebx = 0;
cpuset_t currentCPU; uint32_t ecx = 0;
CPU_ZERO(&currentCPU); uint32_t edx = 0;
CPU_SET(cpu_id, &currentCPU); cpuid(&eax, &ebx, &ecx, &edx);
if(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &currentCPU) == -1) { int32_t core_type = eax >> 24 & 0xFF;
printWarn("cpuset_setaffinity: %s", strerror(errno)); bool found = false;
return false;
for(int j=0; j < total_modules && !found; j++) {
if(core_types[j] == core_type) found = true;
} }
return true; if(!found) {
#endif current_module_idx++;
core_types[current_module_idx] = core_type;
}
if(current_module_idx == module) {
cores_in_module++;
if(i+1 == total_cores) end = true;
}
else if(cores_in_module > 0) end = true;
i++;
}
// Reset the original affinity
if (sched_setaffinity (0, sizeof(original_mask), &original_mask) == -1) {
printWarn("sched_setaffinity: %s", strerror(errno));
return false;
}
//printf("Module %d has %d cores\n", module, cores_in_module);
return cores_in_module;
} }
#endif #endif
@@ -197,40 +222,36 @@ uint32_t max_apic_id_size(uint32_t** cache_id_apic, struct topology* topo) {
uint32_t max = 0; uint32_t max = 0;
for(int i=0; i < topo->cach->max_cache_level; i++) { for(int i=0; i < topo->cach->max_cache_level; i++) {
for(int j=0; j < topo->total_cores; j++) { for(int j=0; j < topo->total_cores_module; j++) {
if(cache_id_apic[j][i] > max) max = cache_id_apic[j][i]; if(cache_id_apic[j][i] > max) max = cache_id_apic[j][i];
} }
} }
max++; max++;
if(max > (uint32_t) topo->total_cores) return max; if(max > (uint32_t) topo->total_cores_module) return max;
return topo->total_cores; return topo->total_cores_module;
} }
bool build_topo_from_apic(uint32_t* apic_pkg, uint32_t* apic_smt, uint32_t** cache_id_apic, struct topology* topo) { bool build_topo_from_apic(uint32_t* apic_pkg, uint32_t* apic_smt, uint32_t** cache_id_apic, struct topology* topo) {
uint32_t size = max_apic_id_size(cache_id_apic, topo); uint32_t size = max_apic_id_size(cache_id_apic, topo);
uint32_t* sockets = emalloc(sizeof(uint32_t) * size); uint32_t* sockets = ecalloc(size, sizeof(uint32_t));
uint32_t* smt = emalloc(sizeof(uint32_t) * size); uint32_t* smt = ecalloc(size, sizeof(uint32_t));
uint32_t* apic_id = emalloc(sizeof(uint32_t) * size); uint32_t* apic_id = ecalloc(size, sizeof(uint32_t));
uint32_t num_caches = 0; uint32_t num_caches = 0;
memset(sockets, 0, sizeof(uint32_t) * size);
memset(smt, 0, sizeof(uint32_t) * size);
memset(apic_id, 0, sizeof(uint32_t) * size);
// System topology // System topology
for(int i=0; i < topo->total_cores; i++) { for(int i=0; i < topo->total_cores_module; i++) {
sockets[apic_pkg[i]] = 1; sockets[apic_pkg[i]] = 1;
smt[apic_smt[i]] = 1; smt[apic_smt[i]] = 1;
} }
for(int i=0; i < topo->total_cores; i++) { for(int i=0; i < topo->total_cores_module; i++) {
if(sockets[i] != 0) if(sockets[i] != 0)
topo->sockets++; topo->sockets++;
if(smt[i] != 0) if(smt[i] != 0)
topo->smt_available++; topo->smt_available++;
} }
topo->logical_cores = topo->total_cores / topo->sockets; topo->logical_cores = topo->total_cores_module / topo->sockets;
topo->physical_cores = topo->logical_cores / topo->smt_available; topo->physical_cores = topo->logical_cores / topo->smt_available;
// Cache topology // Cache topology
@@ -238,7 +259,7 @@ bool build_topo_from_apic(uint32_t* apic_pkg, uint32_t* apic_smt, uint32_t** cac
num_caches = 0; num_caches = 0;
memset(apic_id, 0, sizeof(uint32_t) * size); memset(apic_id, 0, sizeof(uint32_t) * size);
for(int c=0; c < topo->total_cores; c++) { for(int c=0; c < topo->total_cores_module; c++) {
apic_id[cache_id_apic[c][i]]++; apic_id[cache_id_apic[c][i]]++;
} }
for(uint32_t c=0; c < size; c++) { for(uint32_t c=0; c < size; c++) {
@@ -297,9 +318,10 @@ void add_apic_to_array(uint32_t apic, uint32_t* apic_ids, int n) {
} }
} }
bool fill_apic_ids(uint32_t* apic_ids, int n, bool x2apic_id) { bool fill_apic_ids(uint32_t* apic_ids, int first_core, int n, bool x2apic_id) {
#ifdef __APPLE__ #ifdef __APPLE__
// macOS extremely dirty approach... // macOS extremely dirty approach...
UNUSED(first_core);
printf("cpufetch is computing APIC IDs, please wait...\n"); printf("cpufetch is computing APIC IDs, please wait...\n");
bool end = false; bool end = false;
uint32_t apic; uint32_t apic;
@@ -313,25 +335,48 @@ bool fill_apic_ids(uint32_t* apic_ids, int n, bool x2apic_id) {
usleep(1000); usleep(1000);
} }
#else #else
for(int i=0; i < n; i++) { #ifdef __linux__
// In Linux we reset the affinity; first we get the original mask
cpu_set_t original_mask;
if(sched_getaffinity(0, sizeof(original_mask), &original_mask) == -1) {
printWarn("sched_getaffinity: %s", strerror(errno));
return false;
}
#endif
for(int i=first_core; i < first_core+n; i++) {
if(!bind_to_cpu(i)) { if(!bind_to_cpu(i)) {
printErr("Failed binding to CPU %d", i); printErr("Failed binding the process to CPU %d", i);
return false; return false;
} }
apic_ids[i] = get_apic_id(x2apic_id); apic_ids[i-first_core] = get_apic_id(x2apic_id);
} }
#ifdef __linux__
// With the original mask previosly retrieved, we reset the affinity
if (sched_setaffinity (0, sizeof(original_mask), &original_mask) == -1) {
printWarn("sched_setaffinity: %s", strerror(errno));
return false;
}
#endif
#endif #endif
return true; return true;
} }
bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) { bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
if (topo->cach == NULL) {
printWarn("get_topology_from_apic: cach is NULL");
return false;
}
uint32_t apic_id; uint32_t apic_id;
uint32_t* apic_ids = emalloc(sizeof(uint32_t) * topo->total_cores); uint32_t* apic_ids = emalloc(sizeof(uint32_t) * topo->total_cores_module);
uint32_t* apic_pkg = emalloc(sizeof(uint32_t) * topo->total_cores); uint32_t* apic_pkg = emalloc(sizeof(uint32_t) * topo->total_cores_module);
uint32_t* apic_core = emalloc(sizeof(uint32_t) * topo->total_cores); uint32_t* apic_core = emalloc(sizeof(uint32_t) * topo->total_cores_module);
uint32_t* apic_smt = emalloc(sizeof(uint32_t) * topo->total_cores); uint32_t* apic_smt = emalloc(sizeof(uint32_t) * topo->total_cores_module);
uint32_t** cache_smt_id_apic = emalloc(sizeof(uint32_t*) * topo->total_cores); uint32_t** cache_smt_id_apic = emalloc(sizeof(uint32_t*) * topo->total_cores_module);
uint32_t** cache_id_apic = emalloc(sizeof(uint32_t*) * topo->total_cores); uint32_t** cache_id_apic = emalloc(sizeof(uint32_t*) * topo->total_cores_module);
bool x2apic_id; bool x2apic_id;
if(cpu->maxLevels >= 0x0000000B) { if(cpu->maxLevels >= 0x0000000B) {
@@ -349,7 +394,7 @@ bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
x2apic_id = false; x2apic_id = false;
} }
for(int i=0; i < topo->total_cores; i++) { for(int i=0; i < topo->total_cores_module; i++) {
cache_smt_id_apic[i] = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level)); cache_smt_id_apic[i] = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
cache_id_apic[i] = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level)); cache_id_apic[i] = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
} }
@@ -367,10 +412,10 @@ bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
get_cache_topology_from_apic(topo); get_cache_topology_from_apic(topo);
if(!fill_apic_ids(apic_ids, topo->total_cores, x2apic_id)) if(!fill_apic_ids(apic_ids, cpu->first_core_id, topo->total_cores_module, x2apic_id))
return false; return false;
for(int i=0; i < topo->total_cores; i++) { for(int i=0; i < topo->total_cores_module; i++) {
apic_id = apic_ids[i]; apic_id = apic_ids[i];
apic_pkg[i] = (apic_id & topo->apic->pkg_mask) >> topo->apic->pkg_mask_shift; apic_pkg[i] = (apic_id & topo->apic->pkg_mask) >> topo->apic->pkg_mask_shift;
@@ -386,20 +431,19 @@ bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
/* DEBUG /* DEBUG
for(int i=0; i < topo->cach->max_cache_level; i++) { for(int i=0; i < topo->cach->max_cache_level; i++) {
printf("[CACH %1d]", i); printf("[CACH %1d]", i);
for(int j=0; j < topo->total_cores; j++) for(int j=0; j < topo->total_cores_module; j++)
printf("[%03d]", cache_id_apic[j][i]); printf("[%03d]", cache_id_apic[j][i]);
printf("\n"); printf("\n");
} }
for(int i=0; i < topo->total_cores; i++) for(int i=0; i < topo->total_cores_module; i++)
printf("[%2d] 0x%.8X\n", i, apic_pkg[i]); printf("[%2d] 0x%.8X\n", i, apic_pkg[i]);
printf("\n"); printf("\n");
for(int i=0; i < topo->total_cores; i++) for(int i=0; i < topo->total_cores_module; i++)
printf("[%2d] 0x%.8X\n", i, apic_core[i]); printf("[%2d] 0x%.8X\n", i, apic_core[i]);
printf("\n"); printf("\n");
for(int i=0; i < topo->total_cores; i++) for(int i=0; i < topo->total_cores_module; i++)
printf("[%2d] 0x%.8X\n", i, apic_smt[i]);*/ printf("[%2d] 0x%.8X\n", i, apic_smt[i]);*/
bool ret = build_topo_from_apic(apic_pkg, apic_smt, cache_id_apic, topo); bool ret = build_topo_from_apic(apic_pkg, apic_smt, cache_id_apic, topo);
// Assumption: If we cant get smt_available, we assume it is equal to smt_supported... // Assumption: If we cant get smt_available, we assume it is equal to smt_supported...
@@ -411,7 +455,7 @@ bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
free(apic_pkg); free(apic_pkg);
free(apic_core); free(apic_core);
free(apic_smt); free(apic_smt);
for(int i=0; i < topo->total_cores; i++) { for(int i=0; i < topo->total_cores_module; i++) {
free(cache_smt_id_apic[i]); free(cache_smt_id_apic[i]);
free(cache_id_apic[i]); free(cache_id_apic[i]);
} }

View File

@@ -17,8 +17,8 @@ struct apic {
bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo); bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo);
uint32_t is_smt_enabled_amd(struct topology* topo); uint32_t is_smt_enabled_amd(struct topology* topo);
#ifndef __APPLE__ #ifdef __linux__
bool bind_to_cpu(int cpu_id); int get_total_cores_module(int total_cores, int module);
#endif #endif
#endif #endif

View File

@@ -5,6 +5,13 @@
#include "../common/udev.h" #include "../common/udev.h"
#include <unistd.h> #include <unistd.h>
#endif #endif
#if defined (__FreeBSD__) || defined (__APPLE__)
#include "../common/sysctl.h"
#endif
#ifdef __linux__
#include "../common/freq.h"
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -15,33 +22,42 @@
#include "cpuid.h" #include "cpuid.h"
#include "cpuid_asm.h" #include "cpuid_asm.h"
#include "../common/global.h" #include "../common/global.h"
#include "../common/args.h"
#include "apic.h" #include "apic.h"
#include "uarch.h" #include "uarch.h"
#include "freq/freq.h"
#define CPU_VENDOR_INTEL_STRING "GenuineIntel" #define CPU_VENDOR_INTEL_STRING "GenuineIntel"
#define CPU_VENDOR_AMD_STRING "AuthenticAMD" #define CPU_VENDOR_AMD_STRING "AuthenticAMD"
#define CPU_VENDOR_HYGON_STRING "HygonGenuine"
static const char *hv_vendors_string[] = { static const char *hv_vendors_string[] = {
[HV_VENDOR_KVM] = "KVMKVMKVM", [HV_VENDOR_KVM] = "KVMKVMKVM",
[HV_VENDOR_QEMU] = "TCGTCGTCGTCG", [HV_VENDOR_QEMU] = "TCGTCGTCGTCG",
[HV_VENDOR_VBOX] = "VBoxVBoxVBox",
[HV_VENDOR_HYPERV] = "Microsoft Hv", [HV_VENDOR_HYPERV] = "Microsoft Hv",
[HV_VENDOR_VMWARE] = "VMwareVMware", [HV_VENDOR_VMWARE] = "VMwareVMware",
[HV_VENDOR_XEN] = "XenVMMXenVMM", [HV_VENDOR_XEN] = "XenVMMXenVMM",
[HV_VENDOR_PARALLELS] = "lrpepyh vr", [HV_VENDOR_PARALLELS] = "lrpepyh vr",
[HV_VENDOR_PHYP] = NULL,
[HV_VENDOR_BHYVE] = "bhyve bhyve ",
[HV_VENDOR_APPLEVZ] = "Apple VZ"
}; };
static char *hv_vendors_name[] = { static char *hv_vendors_name[] = {
[HV_VENDOR_KVM] = "KVM", [HV_VENDOR_KVM] = "KVM",
[HV_VENDOR_QEMU] = "QEMU", [HV_VENDOR_QEMU] = "QEMU",
[HV_VENDOR_VBOX] = "VirtualBox",
[HV_VENDOR_HYPERV] = "Microsoft Hyper-V", [HV_VENDOR_HYPERV] = "Microsoft Hyper-V",
[HV_VENDOR_VMWARE] = "VMware", [HV_VENDOR_VMWARE] = "VMware",
[HV_VENDOR_XEN] = "Xen", [HV_VENDOR_XEN] = "Xen",
[HV_VENDOR_PARALLELS] = "Parallels", [HV_VENDOR_PARALLELS] = "Parallels",
[HV_VENDOR_PHYP] = "pHyp",
[HV_VENDOR_BHYVE] = "bhyve",
[HV_VENDOR_APPLEVZ] = "Apple VZ",
[HV_VENDOR_INVALID] = STRING_UNKNOWN [HV_VENDOR_INVALID] = STRING_UNKNOWN
}; };
#define HYPERVISOR_NAME_MAX_LENGTH 17
#define MASK 0xFF #define MASK 0xFF
/* /*
@@ -68,15 +84,14 @@ void get_name_cpuid(char* name, uint32_t reg1, uint32_t reg2, uint32_t reg3) {
name[c++] = (reg3>>24) & MASK; name[c++] = (reg3>>24) & MASK;
} }
char* get_str_cpu_name_internal() { char* get_str_cpu_name_internal(void) {
uint32_t eax = 0; uint32_t eax = 0;
uint32_t ebx = 0; uint32_t ebx = 0;
uint32_t ecx = 0; uint32_t ecx = 0;
uint32_t edx = 0; uint32_t edx = 0;
uint32_t c = 0; uint32_t c = 0;
char * name = emalloc(sizeof(char) * CPU_NAME_MAX_LENGTH); char * name = ecalloc(CPU_NAME_MAX_LENGTH, sizeof(char));
memset(name, 0, CPU_NAME_MAX_LENGTH);
for(int i=0; i < 3; i++) { for(int i=0; i < 3; i++) {
eax = 0x80000002 + i; eax = 0x80000002 + i;
@@ -174,10 +189,10 @@ struct uarch* get_cpu_uarch(struct cpuInfo* cpu) {
uint32_t family = (eax >> 8) & 0xF; uint32_t family = (eax >> 8) & 0xF;
uint32_t efamily = (eax >> 20) & 0xFF; uint32_t efamily = (eax >> 20) & 0xFF;
return get_uarch_from_cpuid(cpu, efamily, family, emodel, model, (int)stepping); return get_uarch_from_cpuid(cpu, eax, efamily, family, emodel, model, (int)stepping);
} }
int64_t get_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq) { int64_t get_peak_performance(struct cpuInfo* cpu, bool accurate_pp) {
/* /*
* PP = PeakPerformance * PP = PeakPerformance
* SP = SinglePrecision * SP = SinglePrecision
@@ -190,34 +205,57 @@ int64_t get_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t
* 16(If AVX512), 8(If AVX), 4(If SSE) * * 16(If AVX512), 8(If AVX), 4(If SSE) *
*/ */
//First, check we have consistent data struct cpuInfo* ptr = cpu;
if(freq == UNKNOWN_FREQ) { int64_t total_flops = 0;
return -1;
for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
struct topology* topo = ptr->topo;
int64_t max_freq = get_freq(ptr->freq);
int64_t freq;
#ifdef __linux__
if(accurate_pp)
freq = measure_frequency(ptr);
else
freq = max_freq;
#else
// Silence compiler warning
(void)(accurate_pp);
freq = max_freq;
#endif
//First, check we have consistent data
if(freq == UNKNOWN_DATA || topo == NULL || topo->logical_cores == UNKNOWN_DATA) {
return -1;
}
struct features* feat = ptr->feat;
int vpus = get_number_of_vpus(ptr);
int64_t flops = topo->physical_cores * topo->sockets * (freq*1000000) * vpus;
if(feat->FMA3 || feat->FMA4)
flops = flops*2;
// NOTE:
// Some CPUs (Ice Lake, Zen 4) have AVX512, but they have only
// 1 VPU for AVX512, while they have 2 for AVX2. In such cases,
// we are computing the peak performance supposing AVX2, not AVX512
if(feat->AVX512 && vpus_are_AVX512(ptr))
flops = flops*16;
else if(feat->AVX || feat->AVX2)
flops = flops*8;
else if(feat->SSE)
flops = flops*4;
// See https://sites.utexas.edu/jdm4372/2018/01/22/a-peculiar-
// throughput-limitation-on-intels-xeon-phi-x200-knights-landing/
if(is_knights_landing(ptr))
flops = flops * 6 / 7;
total_flops += flops;
} }
struct features* feat = cpu->feat; return total_flops;
int vpus = get_number_of_vpus(cpu);
int64_t flops = topo->physical_cores * topo->sockets * (freq*1000000) * vpus;
if(feat->FMA3 || feat->FMA4)
flops = flops*2;
// Ice Lake has AVX512, but it has 1 VPU for AVX512, while
// it has 2 for AVX2. If this is a Ice Lake CPU, we are computing
// the peak performance supposing AVX2, not AVX512
if(feat->AVX512 && vpus_are_AVX512(cpu))
flops = flops*16;
else if(feat->AVX || feat->AVX2)
flops = flops*8;
else if(feat->SSE)
flops = flops*4;
// See https://sites.utexas.edu/jdm4372/2018/01/22/a-peculiar-
// throughput-limitation-on-intels-xeon-phi-x200-knights-landing/
if(is_knights_landing(cpu))
flops = flops * 6 / 7;
return flops;
} }
struct hypervisor* get_hp_info(bool hv_present) { struct hypervisor* get_hp_info(bool hv_present) {
@@ -236,23 +274,29 @@ struct hypervisor* get_hp_info(bool hv_present) {
cpuid(&eax, &ebx, &ecx, &edx); cpuid(&eax, &ebx, &ecx, &edx);
char name[13]; if(ebx == 0x0 && ecx == 0x0 && edx == 0x0) {
memset(name, 0, 13);
get_name_cpuid(name, ebx, ecx, edx);
bool found = false;
uint8_t len = sizeof(hv_vendors_string) / sizeof(hv_vendors_string[0]);
for(uint8_t v=0; v < len && !found; v++) {
if(strcmp(hv_vendors_string[v], name) == 0) {
hv->hv_vendor = v;
found = true;
}
}
if(!found) {
hv->hv_vendor = HV_VENDOR_INVALID; hv->hv_vendor = HV_VENDOR_INVALID;
printWarn("Unknown hypervisor vendor: %s", name); printWarn("Hypervisor vendor is empty");
}
else {
char name[13];
memset(name, 0, sizeof(char) * 13);
get_name_cpuid(name, ebx, ecx, edx);
bool found = false;
uint8_t len = sizeof(hv_vendors_string) / sizeof(hv_vendors_string[0]);
for(uint8_t v=0; v < len && !found; v++) {
if(hv_vendors_string[v] != NULL && strcmp(hv_vendors_string[v], name) == 0) {
hv->hv_vendor = v;
found = true;
}
}
if(!found) {
hv->hv_vendor = HV_VENDOR_INVALID;
printBug("Unknown hypervisor vendor: '%s'", name);
}
} }
hv->hv_name = hv_vendors_name[hv->hv_vendor]; hv->hv_name = hv_vendors_name[hv->hv_vendor];
@@ -260,48 +304,19 @@ struct hypervisor* get_hp_info(bool hv_present) {
return hv; return hv;
} }
struct cpuInfo* get_cpu_info() { struct features* get_features_info(struct cpuInfo* cpu) {
struct cpuInfo* cpu = emalloc(sizeof(struct cpuInfo));
struct features* feat = emalloc(sizeof(struct features));
cpu->feat = feat;
bool *ptr = &(feat->AES);
for(uint32_t i = 0; i < sizeof(struct features)/sizeof(bool); i++, ptr++) {
*ptr = false;
}
uint32_t eax = 0; uint32_t eax = 0;
uint32_t ebx = 0; uint32_t ebx = 0;
uint32_t ecx = 0; uint32_t ecx = 0;
uint32_t edx = 0; uint32_t edx = 0;
//Get max cpuid level struct features* feat = emalloc(sizeof(struct features));
cpuid(&eax, &ebx, &ecx, &edx);
cpu->maxLevels = eax;
//Fill vendor bool *ptr = &(feat->AES);
char name[13]; for(uint32_t i = 0; i < sizeof(struct features)/sizeof(bool); i++, ptr++) {
memset(name,0,13); *ptr = false;
get_name_cpuid(name, ebx, edx, ecx);
if(strcmp(CPU_VENDOR_INTEL_STRING,name) == 0)
cpu->cpu_vendor = CPU_VENDOR_INTEL;
else if (strcmp(CPU_VENDOR_AMD_STRING,name) == 0)
cpu->cpu_vendor = CPU_VENDOR_AMD;
else {
cpu->cpu_vendor = CPU_VENDOR_INVALID;
printErr("Unknown CPU vendor: %s", name);
return NULL;
} }
//Get max extended level
eax = 0x80000000;
ebx = 0;
ecx = 0;
edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
cpu->maxExtendedLevels = eax;
//Fill instructions support //Fill instructions support
if (cpu->maxLevels >= 0x00000001){ if (cpu->maxLevels >= 0x00000001){
eax = 0x00000001; eax = 0x00000001;
@@ -356,13 +371,134 @@ struct cpuInfo* get_cpu_info() {
printWarn("Can't read features information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000001, cpu->maxExtendedLevels); printWarn("Can't read features information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000001, cpu->maxExtendedLevels);
} }
return feat;
}
bool set_cpu_module(int m, int total_modules, int32_t* first_core) {
if(total_modules > 1) {
#ifdef __APPLE__
UNUSED(m);
printBug("Hybrid architectures are not supported under macOS");
return false;
#else
// We have a hybrid architecture.
// 1. Find the first core from module m
int32_t core_id = -1;
int32_t currrent_module_idx = -1;
int32_t* core_types = emalloc(sizeof(uint32_t) * total_modules);
for(int i=0; i < total_modules; i++) core_types[i] = -1;
int i = 0;
while(core_id == -1) {
if(!bind_to_cpu(i)) {
return false;
}
uint32_t eax = 0x0000001A;
uint32_t ebx = 0;
uint32_t ecx = 0;
uint32_t edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
int32_t core_type = eax >> 24 & 0xFF;
bool found = false;
for(int j=0; j < total_modules && !found; j++) {
if(core_types[j] == core_type) found = true;
}
if(!found) {
currrent_module_idx++;
core_types[currrent_module_idx] = core_type;
if(currrent_module_idx == m) {
core_id = i;
}
}
i++;
}
*first_core = core_id;
//printf("Module %d: Core %d\n", m, core_id);
// 2. Now bind to that core
if(!bind_to_cpu(core_id)) {
return false;
}
#endif
}
else {
// This is a normal architecture
*first_core = 0;
}
return true;
}
int32_t get_core_type(void) {
uint32_t eax = 0x0000001A;
uint32_t ebx = 0;
uint32_t ecx = 0;
uint32_t edx = 0;
eax = 0x0000001A;
cpuid(&eax, &ebx, &ecx, &edx);
int32_t type = eax >> 24 & 0xFF;
if(type == 0x20) return CORE_TYPE_EFFICIENCY;
else if(type == 0x40) return CORE_TYPE_PERFORMANCE;
else {
printErr("Found invalid core type: 0x%.8X\n", type);
return CORE_TYPE_UNKNOWN;
}
}
struct cpuInfo* get_cpu_info(void) {
struct cpuInfo* cpu = emalloc(sizeof(struct cpuInfo));
cpu->peak_performance = -1;
cpu->next_cpu = NULL;
cpu->topo = NULL;
cpu->cach = NULL;
cpu->feat = NULL;
cpu->num_cpus = 1;
uint32_t eax = 0;
uint32_t ebx = 0;
uint32_t ecx = 0;
uint32_t edx = 0;
//Get max cpuid level
cpuid(&eax, &ebx, &ecx, &edx);
cpu->maxLevels = eax;
//Fill vendor
char name[13];
memset(name, 0, sizeof(char) * 13);
get_name_cpuid(name, ebx, edx, ecx);
if(strcmp(CPU_VENDOR_INTEL_STRING,name) == 0)
cpu->cpu_vendor = CPU_VENDOR_INTEL;
else if (strcmp(CPU_VENDOR_AMD_STRING,name) == 0)
cpu->cpu_vendor = CPU_VENDOR_AMD;
else if (strcmp(CPU_VENDOR_HYGON_STRING,name) == 0)
cpu->cpu_vendor = CPU_VENDOR_HYGON;
else {
cpu->cpu_vendor = CPU_VENDOR_INVALID;
printErr("Unknown CPU vendor: %s", name);
return NULL;
}
//Get max extended level
eax = 0x80000000;
ebx = 0;
ecx = 0;
edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
cpu->maxExtendedLevels = eax;
if (cpu->maxExtendedLevels >= 0x80000004){ if (cpu->maxExtendedLevels >= 0x80000004){
cpu->cpu_name = get_str_cpu_name_internal(); cpu->cpu_name = get_str_cpu_name_internal();
} }
else { else {
cpu->cpu_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN) + 1)); cpu->cpu_name = NULL;
strcpy(cpu->cpu_name, STRING_UNKNOWN); printWarn("Can't read CPU name from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000004, cpu->maxExtendedLevels);
printWarn("Can't read cpu name from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000004, cpu->maxExtendedLevels);
} }
cpu->topology_extensions = false; cpu->topology_extensions = false;
@@ -372,19 +508,79 @@ struct cpuInfo* get_cpu_info() {
cpu->topology_extensions = (ecx >> 22) & 1; cpu->topology_extensions = (ecx >> 22) & 1;
} }
cpu->arch = get_cpu_uarch(cpu); cpu->hybrid_flag = false;
cpu->freq = get_frequency_info(cpu); if(cpu->cpu_vendor == CPU_VENDOR_INTEL && cpu->maxLevels >= 0x00000007) {
cpu->cach = get_cache_info(cpu); eax = 0x00000007;
cpu->topo = get_topology_info(cpu, cpu->cach); ecx = 0x00000000;
cpu->peak_performance = get_peak_performance(cpu, cpu->topo, get_freq(cpu->freq)); cpuid(&eax, &ebx, &ecx, &edx);
cpu->hybrid_flag = (edx >> 15) & 0x1;
if(cpu->cach == NULL || cpu->topo == NULL) {
return NULL;
} }
if(cpu->hybrid_flag) cpu->num_cpus = 2;
struct cpuInfo* ptr = cpu;
for(uint32_t i=0; i < cpu->num_cpus; i++) {
int32_t first_core;
set_cpu_module(i, cpu->num_cpus, &first_core);
if(i > 0) {
ptr->next_cpu = emalloc(sizeof(struct cpuInfo));
ptr = ptr->next_cpu;
ptr->next_cpu = NULL;
ptr->peak_performance = -1;
ptr->topo = NULL;
ptr->cach = NULL;
ptr->feat = NULL;
// We assume that this cores have the
// same cpuid capabilities
ptr->cpu_vendor = cpu->cpu_vendor;
ptr->maxLevels = cpu->maxLevels;
ptr->maxExtendedLevels = cpu->maxExtendedLevels;
ptr->hybrid_flag = cpu->hybrid_flag;
}
if(cpu->hybrid_flag) {
// Detect core type
eax = 0x0000001A;
cpuid(&eax, &ebx, &ecx, &edx);
ptr->core_type = get_core_type();
}
ptr->first_core_id = first_core;
ptr->feat = get_features_info(ptr);
ptr->arch = get_cpu_uarch(ptr);
ptr->freq = get_frequency_info(ptr);
if (cpu->cpu_name == NULL && ptr == cpu) {
// If we couldnt read CPU name from cpuid, infer it now
cpu->cpu_name = infer_cpu_name_from_uarch(cpu->arch);
}
ptr->cach = get_cache_info(ptr);
if(cpu->hybrid_flag) {
ptr->topo = get_topology_info(ptr, ptr->cach, i);
}
else {
ptr->topo = get_topology_info(ptr, ptr->cach, -1);
}
// If topo is NULL, return early, as get_peak_performance
// requries non-NULL topology.
if(ptr->topo == NULL) return cpu;
}
cpu->peak_performance = get_peak_performance(cpu, accurate_pp());
return cpu; return cpu;
} }
bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) { bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
if (topo->cach == NULL) {
printWarn("get_cache_topology_amd: cach is NULL");
return false;
}
if(cpu->maxExtendedLevels >= 0x8000001D && cpu->topology_extensions) { if(cpu->maxExtendedLevels >= 0x8000001D && cpu->topology_extensions) {
uint32_t i, eax, ebx, ecx, edx, num_sharing_cache, cache_type, cache_level; uint32_t i, eax, ebx, ecx, edx, num_sharing_cache, cache_type, cache_level;
@@ -458,9 +654,28 @@ bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
return true; return true;
} }
#ifdef __linux__
void get_topology_from_udev(struct topology* topo) {
topo->total_cores = get_ncores_from_cpuinfo();
// TODO: To be improved in the future
if (topo->total_cores == 1) {
// We can assume it's a single core CPU
topo->logical_cores = topo->total_cores;
topo->physical_cores = topo->total_cores;
}
else {
topo->logical_cores = UNKNOWN_DATA;
topo->physical_cores = UNKNOWN_DATA;
}
topo->smt_available = 1;
topo->smt_supported = 1;
topo->sockets = 1;
}
#endif
// Main reference: https://software.intel.com/content/www/us/en/develop/articles/intel-64-architecture-processor-topology-enumeration.html // Main reference: https://software.intel.com/content/www/us/en/develop/articles/intel-64-architecture-processor-topology-enumeration.html
// Very interesting resource: https://wiki.osdev.org/Detecting_CPU_Topology_(80x86) // Very interesting resource: https://wiki.osdev.org/Detecting_CPU_Topology_(80x86)
struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) { struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, int module) {
struct topology* topo = emalloc(sizeof(struct topology)); struct topology* topo = emalloc(sizeof(struct topology));
init_topology_struct(topo, cach); init_topology_struct(topo, cach);
@@ -484,20 +699,43 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) {
} }
#endif #endif
if(cpu->hybrid_flag) {
#ifdef __linux__
topo->total_cores_module = get_total_cores_module(topo->total_cores, module);
#else
UNUSED(module);
topo->total_cores_module = topo->total_cores;
#endif
}
else {
topo->total_cores_module = topo->total_cores;
}
bool toporet = false;
switch(cpu->cpu_vendor) { switch(cpu->cpu_vendor) {
case CPU_VENDOR_INTEL: case CPU_VENDOR_INTEL:
if (cpu->maxLevels >= 0x00000004) { if (cpu->maxLevels >= 0x00000004) {
get_topology_from_apic(cpu, topo); toporet = get_topology_from_apic(cpu, topo);
} }
else { else {
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels); printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000004, cpu->maxLevels);
topo->physical_cores = 1; }
topo->logical_cores = 1; if(!toporet) {
topo->smt_available = 1; #ifdef __linux__
topo->smt_supported = 1; printWarn("Failed to retrieve topology from APIC, using udev...");
get_topology_from_udev(topo);
#else
if (cpu->maxLevels >= 0x00000004)
printErr("Failed to retrieve topology from APIC, assumming default values...");
topo->logical_cores = UNKNOWN_DATA;
topo->physical_cores = UNKNOWN_DATA;
topo->smt_available = 1;
topo->smt_supported = 1;
#endif
} }
break; break;
case CPU_VENDOR_AMD: case CPU_VENDOR_AMD:
case CPU_VENDOR_HYGON:
if (cpu->maxExtendedLevels >= 0x80000008) { if (cpu->maxExtendedLevels >= 0x80000008) {
eax = 0x80000008; eax = 0x80000008;
cpuid(&eax, &ebx, &ecx, &edx); cpuid(&eax, &ebx, &ecx, &edx);
@@ -514,10 +752,15 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) {
} }
} }
else { else {
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxExtendedLevels); #ifdef __linux__
topo->physical_cores = 1; printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X), using udev...", 0x80000008, cpu->maxExtendedLevels);
topo->logical_cores = 1; get_topology_from_udev(topo);
topo->smt_supported = 1; #else
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxExtendedLevels);
topo->physical_cores = 1;
topo->logical_cores = 1;
topo->smt_supported = 1;
#endif
} }
if (cpu->maxLevels >= 0x00000001) { if (cpu->maxLevels >= 0x00000001) {
@@ -694,20 +937,31 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
struct frequency* get_frequency_info(struct cpuInfo* cpu) { struct frequency* get_frequency_info(struct cpuInfo* cpu) {
struct frequency* freq = emalloc(sizeof(struct frequency)); struct frequency* freq = emalloc(sizeof(struct frequency));
freq->measured = false;
if(cpu->maxLevels < 0x00000016) { if(cpu->maxLevels < 0x00000016) {
#if defined (_WIN32) || defined (__APPLE__) #if defined (_WIN32)
printWarn("Can't read frequency information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000016, cpu->maxLevels); printWarn("Can't read frequency information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000016, cpu->maxLevels);
freq->base = UNKNOWN_FREQ; freq->base = UNKNOWN_DATA;
freq->max = UNKNOWN_FREQ; freq->max = UNKNOWN_DATA;
#elif defined (__FreeBSD__) || defined (__APPLE__)
printWarn("Can't read frequency information from cpuid (needed level is 0x%.8X, max is 0x%.8X). Using sysctl", 0x00000016, cpu->maxLevels);
uint32_t freq_hz = get_sys_info_by_name(CPUFREQUENCY_SYSCTL);
if (freq_hz == 0) {
printWarn("Read max CPU frequency from sysctl and got 0 MHz");
freq->max = UNKNOWN_DATA;
}
freq->base = UNKNOWN_DATA;
freq->max = freq_hz;
#else #else
printWarn("Can't read frequency information from cpuid (needed level is 0x%.8X, max is 0x%.8X). Using udev", 0x00000016, cpu->maxLevels); printWarn("Can't read frequency information from cpuid (needed level is 0x%.8X, max is 0x%.8X). Using udev", 0x00000016, cpu->maxLevels);
freq->base = UNKNOWN_FREQ; freq->base = UNKNOWN_DATA;
freq->max = get_max_freq_from_file(0); freq->max = get_max_freq_from_file(cpu->first_core_id);
if(freq->max == 0) { if(freq->max == 0) {
printWarn("Read max CPU frequency from udev and got 0 MHz"); printWarn("Read max CPU frequency from udev and got 0 MHz");
freq->max = UNKNOWN_FREQ; freq->max = UNKNOWN_DATA;
} }
#endif #endif
} }
@@ -724,24 +978,33 @@ struct frequency* get_frequency_info(struct cpuInfo* cpu) {
if(freq->base == 0) { if(freq->base == 0) {
printWarn("Read base CPU frequency from CPUID and got 0 MHz"); printWarn("Read base CPU frequency from CPUID and got 0 MHz");
freq->base = UNKNOWN_FREQ; freq->base = UNKNOWN_DATA;
} }
if(freq->max == 0) { if(freq->max == 0) {
printWarn("Read max CPU frequency from CPUID and got 0 MHz"); printWarn("Read max CPU frequency from CPUID and got 0 MHz");
#ifdef __linux__ #ifdef __linux__
printWarn("Using udev to detect frequency"); printWarn("Using udev to detect frequency");
freq->max = get_max_freq_from_file(0); freq->max = get_max_freq_from_file(cpu->first_core_id);
if(freq->max == 0) { if(freq->max == 0) {
printWarn("Read max CPU frequency from udev and got 0 MHz"); printWarn("Read max CPU frequency from udev and got 0 MHz");
freq->max = UNKNOWN_FREQ; freq->max = UNKNOWN_DATA;
} }
#else #else
freq->max = UNKNOWN_FREQ; freq->max = UNKNOWN_DATA;
#endif #endif
} }
} }
#ifdef __linux__
if (freq->max == UNKNOWN_DATA || measure_max_frequency_flag()) {
if (freq->max == UNKNOWN_DATA)
printWarn("All previous methods failed, measuring CPU frequency");
freq->max = measure_max_frequency(cpu->first_core_id);
freq->measured = true;
}
#endif
return freq; return freq;
} }
@@ -759,24 +1022,37 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc
int topo_sockets = dual_socket ? topo->sockets : 1; int topo_sockets = dual_socket ? topo->sockets : 1;
char* string; char* string;
if(topo->smt_supported > 1) { if(topo->logical_cores == UNKNOWN_DATA) {
// 4 for digits, 21 for ' cores (SMT disabled)' which is the longest possible output string = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN) + 1));
uint32_t max_size = 4+21+1; strcpy(string, STRING_UNKNOWN);
string = emalloc(sizeof(char) * max_size);
if(topo->smt_available > 1)
snprintf(string, max_size, "%d cores (%d threads)", topo->physical_cores * topo_sockets, topo->logical_cores * topo_sockets);
else {
if(cpu->cpu_vendor == CPU_VENDOR_AMD)
snprintf(string, max_size, "%d cores (SMT disabled)", topo->physical_cores * topo_sockets);
else
snprintf(string, max_size, "%d cores (HT disabled)", topo->physical_cores * topo_sockets);
}
} }
else { else {
uint32_t max_size = 4+7+1; char cores_str[6];
string = emalloc(sizeof(char) * max_size); memset(cores_str, 0, sizeof(char) * 6);
snprintf(string, max_size, "%d cores",topo->physical_cores * topo_sockets); if (topo->physical_cores * topo_sockets > 1)
strcpy(cores_str, "cores");
else
strcpy(cores_str, "core");
if(topo->smt_supported > 1) {
// 4 for digits, 21 for ' cores (SMT disabled)' which is the longest possible output
uint32_t max_size = 4+21+1;
string = emalloc(sizeof(char) * max_size);
if(topo->smt_available > 1)
snprintf(string, max_size, "%d %s (%d threads)", topo->physical_cores * topo_sockets, cores_str, topo->logical_cores * topo_sockets);
else {
if(cpu->cpu_vendor == CPU_VENDOR_AMD)
snprintf(string, max_size, "%d %s (SMT disabled)", topo->physical_cores * topo_sockets, cores_str);
else
snprintf(string, max_size, "%d %s (HT disabled)", topo->physical_cores * topo_sockets, cores_str);
}
}
else {
uint32_t max_size = 4+7+1;
string = emalloc(sizeof(char) * max_size);
snprintf(string, max_size, "%d %s",topo->physical_cores * topo_sockets, cores_str);
}
} }
return string; return string;
@@ -837,8 +1113,14 @@ char* get_str_sse(struct cpuInfo* cpu) {
last+=SSE4_2_sl; last+=SSE4_2_sl;
} }
//Purge last comma if (last == 0) {
string[last-1] = '\0'; snprintf(string, 2+1, "No");
}
else {
//Purge last comma
string[last-1] = '\0';
}
return string; return string;
} }
@@ -871,17 +1153,37 @@ void print_debug(struct cpuInfo* cpu) {
if(cpu->cpu_vendor == CPU_VENDOR_AMD) { if(cpu->cpu_vendor == CPU_VENDOR_AMD) {
printf("- AMD topology extensions: %d\n", cpu->topology_extensions); printf("- AMD topology extensions: %d\n", cpu->topology_extensions);
} }
if(cpu->cpu_vendor == CPU_VENDOR_INTEL) {
printf("- Hybrid Flag: %d\n", cpu->hybrid_flag);
}
printf("- CPUID dump: 0x%.8X\n", eax); printf("- CPUID dump: 0x%.8X\n", eax);
free_cpuinfo_struct(cpu); free_cpuinfo_struct(cpu);
} }
// TODO: Query HV and Xeon Phi levels void print_raw_level(uint32_t reg) {
uint32_t eax = reg;
uint32_t ebx = 0;
uint32_t ecx = 0;
uint32_t edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, 0x00, eax, ebx, ecx, edx);
}
void print_raw_sublevel(uint32_t reg, uint32_t reg2) {
uint32_t eax = reg;
uint32_t ebx = 0;
uint32_t ecx = reg2;
uint32_t edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, reg2, eax, ebx, ecx, edx);
}
void print_raw(struct cpuInfo* cpu) { void print_raw(struct cpuInfo* cpu) {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
printf("%s\n\n", cpu->cpu_name); printf("%s\n\n", cpu->cpu_name);
printf(" CPUID leaf sub EAX EBX ECX EDX \n"); printf(" CPUID leaf sub EAX EBX ECX EDX \n");
printf("--------------------------------------------------------------\n"); printf("--------------------------------------------------------------\n");
@@ -896,66 +1198,40 @@ void print_raw(struct cpuInfo* cpu) {
printf("CPU %d:\n", c); printf("CPU %d:\n", c);
// Standard levels
for(uint32_t reg=0x00000000; reg <= cpu->maxLevels; reg++) { for(uint32_t reg=0x00000000; reg <= cpu->maxLevels; reg++) {
if(reg == 0x00000004) { if(reg == 0x00000004) {
for(uint32_t reg2=0x00000000; reg2 < cpu->cach->max_cache_level; reg2++) { for(uint32_t reg2=0x00000000; reg2 < cpu->cach->max_cache_level; reg2++) {
eax = reg; print_raw_sublevel(reg, reg2);
ebx = 0;
ecx = reg2;
edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, reg2, eax, ebx, ecx, edx);
} }
} }
else if(reg == 0x0000000B) { else if(reg == 0x0000000B) {
for(uint32_t reg2=0x00000000; reg2 < cpu->topo->smt_supported; reg2++) { for(uint32_t reg2=0x00000000; reg2 < cpu->topo->smt_supported; reg2++) {
eax = reg; print_raw_sublevel(reg, reg2);
ebx = 0;
ecx = reg2;
edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, reg2, eax, ebx, ecx, edx);
} }
} }
else { else {
eax = reg; print_raw_level(reg);
ebx = 0;
ecx = 0;
edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, 0x00, eax, ebx, ecx, edx);
} }
} }
// Hypervisor levels
for(uint32_t reg=0x40000000; reg <= 0x40000006; reg++) {
print_raw_level(reg);
}
// Extended levels
for(uint32_t reg=0x80000000; reg <= cpu->maxExtendedLevels; reg++) { for(uint32_t reg=0x80000000; reg <= cpu->maxExtendedLevels; reg++) {
if(reg == 0x8000001D) { if(reg == 0x8000001D) {
for(uint32_t reg2=0x00000000; reg2 < cpu->cach->max_cache_level; reg2++) { for(uint32_t reg2=0x00000000; reg2 < cpu->cach->max_cache_level; reg2++) {
eax = reg; print_raw_sublevel(reg, reg2);
ebx = 0;
ecx = reg2;
edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, reg2, eax, ebx, ecx, edx);
} }
} }
else { else {
eax = reg; print_raw_level(reg);
ebx = 0;
ecx = 0;
edx = 0;
cpuid(&eax, &ebx, &ecx, &edx);
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, 0x00, eax, ebx, ecx, edx);
} }
} }
} }
} }

View File

@@ -3,10 +3,10 @@
#include "../common/cpu.h" #include "../common/cpu.h"
struct cpuInfo* get_cpu_info(); struct cpuInfo* get_cpu_info(void);
struct cache* get_cache_info(struct cpuInfo* cpu); struct cache* get_cache_info(struct cpuInfo* cpu);
struct frequency* get_frequency_info(struct cpuInfo* cpu); struct frequency* get_frequency_info(struct cpuInfo* cpu);
struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach); struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, int module);
char* get_str_avx(struct cpuInfo* cpu); char* get_str_avx(struct cpuInfo* cpu);
char* get_str_sse(struct cpuInfo* cpu); char* get_str_sse(struct cpuInfo* cpu);

163
src/x86/freq/freq.c Normal file
View File

@@ -0,0 +1,163 @@
#define _GNU_SOURCE
#include <stdio.h>
#include "../../common/global.h"
#include "../uarch.h"
#include "freq.h"
#include "freq_nov.h"
#include "freq_avx.h"
#include "freq_avx512.h"
#include <immintrin.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#define MAX_NUMBER_THREADS 512
#define FREQ_VECTOR_SIZE 1<<16
struct freq_thread {
bool end;
bool measure;
double freq;
};
double vector_average_harmonic(double* v, int len) {
double acc = 0.0;
for(int i=0; i < len; i++) {
acc += 1 / v[i];
}
return len / acc;
}
void sleep_ms(int64_t ms) {
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&ts, &ts);
}
void* measure_freq(void *freq_ptr) {
struct freq_thread* freq = (struct freq_thread*) freq_ptr;
char* end = NULL;
char* line = NULL;
size_t len = 0;
ssize_t read;
int v = 0;
double* freq_vector = malloc(sizeof(double) * FREQ_VECTOR_SIZE);
while(!freq->end) {
if(!freq->measure) continue;
FILE* fp = fopen("/proc/cpuinfo", "r");
if(fp == NULL) return NULL;
while ((read = getline(&line, &len, fp)) != -1) {
if((line = strstr(line, "cpu MHz")) != NULL) {
line = strstr(line, "\t: ");
if(line == NULL) return NULL;
line += sizeof("\t: ") - 1;
double f = strtold(line, &end);
if(errno != 0) {
printf("strtol: %s", strerror(errno));
return NULL;
}
freq_vector[v] = f;
v++;
}
}
fclose(fp);
sleep_ms(500);
}
freq->freq = vector_average_harmonic(freq_vector, v);
printWarn("AVX2 measured freq=%f\n", freq->freq);
return NULL;
}
int64_t measure_frequency(struct cpuInfo* cpu) {
int ret;
int num_spaces;
struct freq_thread* freq_struct = malloc(sizeof(struct freq_thread));
freq_struct->end = false;
freq_struct->measure = false;
void* (*compute_function)(void*);
if(cpu->feat->AVX512 && vpus_are_AVX512(cpu)) {
printf("cpufetch is measuring the AVX512 frequency...");
compute_function = compute_avx512;
num_spaces = 45;
}
else if(cpu->feat->AVX || cpu->feat->AVX2) {
printf("cpufetch is measuring the AVX frequency...");
compute_function = compute_avx;
num_spaces = 42;
}
else {
printf("cpufetch is measuring the frequency (no vector instructions)...");
compute_function = compute_nov;
num_spaces = 63;
}
fflush(stdout);
pthread_t freq_t;
if(pthread_create(&freq_t, NULL, measure_freq, freq_struct)) {
fprintf(stderr, "Error creating thread\n");
return -1;
}
pthread_t* compute_th = malloc(sizeof(pthread_t) * cpu->topo->total_cores);
cpu_set_t cpus;
pthread_attr_t attr;
if ((ret = pthread_attr_init(&attr)) != 0) {
printErr("pthread_attr_init: %s", strerror(ret));
return -1;
}
for(int i=0; i < cpu->topo->total_cores; i++) {
// We might have called bind_to_cpu previously, binding the threads
// to a specific core, so now we must make sure we run the new thread
// on the correct core.
CPU_ZERO(&cpus);
CPU_SET(i, &cpus);
if ((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus)) != 0) {
printErr("pthread_attr_setaffinity_np: %s", strerror(ret));
return -1;
}
ret = pthread_create(&compute_th[i], &attr, compute_function, NULL);
if(ret != 0) {
fprintf(stderr, "Error creating thread\n");
return -1;
}
}
sleep_ms(500);
freq_struct->measure = true;
for(int i=0; i < cpu->topo->total_cores; i++) {
if(pthread_join(compute_th[i], NULL)) {
fprintf(stderr, "Error joining thread\n");
return -1;
}
freq_struct->end = true;
}
if(pthread_join(freq_t, NULL)) {
fprintf(stderr, "Error joining thread\n");
return -1;
}
printf("\r%*c", num_spaces, ' ');
return freq_struct->freq;
}

13
src/x86/freq/freq.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef __FREQ__
#define __FREQ__
#include <stdint.h>
#include "../../common/cpu.h"
#include "../../common/global.h"
#define MEASURE_TIME_SECONDS 5
#define LOOP_ITERS 100000000
int64_t measure_frequency(struct cpuInfo* cpu);
#endif

57
src/x86/freq/freq_avx.c Normal file
View File

@@ -0,0 +1,57 @@
#include <stdio.h>
#include <immintrin.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include "freq.h"
void* compute_avx(void * pthread_arg) {
UNUSED(pthread_arg);
bool end = false;
struct timeval begin, now;
__m256 a[8];
__m256 b[8];
for(int i=0; i < 8; i++) {
a[i] = _mm256_set1_ps(1.5);
b[i] = _mm256_set1_ps(1.2);
}
gettimeofday(&begin, NULL);
while(!end) {
for(uint64_t i=0; i < LOOP_ITERS; i++) {
a[0] = _mm256_add_ps(a[0], b[0]);
a[1] = _mm256_add_ps(a[1], b[1]);
a[2] = _mm256_add_ps(a[2], b[2]);
a[3] = _mm256_add_ps(a[3], b[3]);
a[4] = _mm256_add_ps(a[4], b[4]);
a[5] = _mm256_add_ps(a[5], b[5]);
a[6] = _mm256_add_ps(a[6], b[6]);
a[7] = _mm256_add_ps(a[7], b[7]);
}
gettimeofday(&now, NULL);
double elapsed = (now.tv_sec - begin.tv_sec) + ((now.tv_usec - begin.tv_usec)/1000000.0);
end = elapsed >= (double) MEASURE_TIME_SECONDS;
}
FILE* fp = fopen("/dev/null", "w");
if(fp == NULL) {
printf("fopen: %s", strerror(errno));
}
else {
for(int i=0; i < 8; i++)
fprintf(fp, "%f", a[i][0]);
fclose(fp);
}
return NULL;
}

6
src/x86/freq/freq_avx.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __FREQ_AVX__
#define __FREQ_AVX__
void* compute_avx(void * pthread_arg);
#endif

View File

@@ -0,0 +1,57 @@
#include <stdio.h>
#include <immintrin.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include "freq.h"
void* compute_avx512(void * pthread_arg) {
UNUSED(pthread_arg);
bool end = false;
struct timeval begin, now;
__m512 a[8];
__m512 b[8];
for(int i=0; i < 8; i++) {
a[i] = _mm512_set1_ps(1.5);
b[i] = _mm512_set1_ps(1.2);
}
gettimeofday(&begin, NULL);
while(!end) {
for(uint64_t i=0; i < LOOP_ITERS; i++) {
a[0] = _mm512_add_ps(a[0], b[0]);
a[1] = _mm512_add_ps(a[1], b[1]);
a[2] = _mm512_add_ps(a[2], b[2]);
a[3] = _mm512_add_ps(a[3], b[3]);
a[4] = _mm512_add_ps(a[4], b[4]);
a[5] = _mm512_add_ps(a[5], b[5]);
a[6] = _mm512_add_ps(a[6], b[6]);
a[7] = _mm512_add_ps(a[7], b[7]);
}
gettimeofday(&now, NULL);
double elapsed = (now.tv_sec - begin.tv_sec) + ((now.tv_usec - begin.tv_usec)/1000000.0);
end = elapsed >= (double) MEASURE_TIME_SECONDS;
}
FILE* fp = fopen("/dev/null", "w");
if(fp == NULL) {
printf("fopen: %s", strerror(errno));
}
else {
for(int i=0; i < 8; i++)
fprintf(fp, "%f", a[i][0]);
fclose(fp);
}
return NULL;
}

View File

@@ -0,0 +1,6 @@
#ifndef __FREQ_AVX512__
#define __FREQ_AVX512__
void* compute_avx512(void * pthread_arg);
#endif

45
src/x86/freq/freq_nov.c Normal file
View File

@@ -0,0 +1,45 @@
#include <stdio.h>
#include <immintrin.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include "freq.h"
void* compute_nov(void * pthread_arg) {
UNUSED(pthread_arg);
bool end = false;
struct timeval begin, now;
float a = 1.5;
float b = 1.2;
float c = 0.0;
gettimeofday(&begin, NULL);
while(!end) {
for(uint64_t i=0; i < LOOP_ITERS; i++) {
c = a * b;
}
gettimeofday(&now, NULL);
double elapsed = (now.tv_sec - begin.tv_sec) + ((now.tv_usec - begin.tv_usec)/1000000.0);
end = elapsed >= (double) MEASURE_TIME_SECONDS;
}
FILE* fp = fopen("/dev/null", "w");
if(fp == NULL) {
printf("fopen: %s", strerror(errno));
}
else {
fprintf(fp, "%f", c);
fclose(fp);
}
return NULL;
}

6
src/x86/freq/freq_nov.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __FREQ_NO_VECTOR__
#define __FREQ_NO_VECTOR__
void* compute_nov(void * pthread_arg);
#endif

View File

@@ -47,8 +47,12 @@ typedef uint32_t MICROARCH;
enum { enum {
UARCH_UNKNOWN, UARCH_UNKNOWN,
// INTEL // // INTEL //
UARCH_I486,
UARCH_P5, UARCH_P5,
UARCH_P6, UARCH_P5_MMX,
UARCH_P6_PRO,
UARCH_P6_PENTIUM_II,
UARCH_P6_PENTIUM_III,
UARCH_DOTHAN, UARCH_DOTHAN,
UARCH_YONAH, UARCH_YONAH,
UARCH_MEROM, UARCH_MEROM,
@@ -78,8 +82,8 @@ enum {
UARCH_SUNNY_COVE, UARCH_SUNNY_COVE,
UARCH_GOLDMONT_PLUS, UARCH_GOLDMONT_PLUS,
UARCH_TREMONT, UARCH_TREMONT,
UARCH_WILLOW_COVE, UARCH_LAKEMONT,
UARCH_COFFE_LAKE, UARCH_COFFEE_LAKE,
UARCH_ITANIUM, UARCH_ITANIUM,
UARCH_KNIGHTS_FERRY, UARCH_KNIGHTS_FERRY,
UARCH_KNIGHTS_CORNER, UARCH_KNIGHTS_CORNER,
@@ -89,9 +93,14 @@ enum {
UARCH_CEDAR_MILL, UARCH_CEDAR_MILL,
UARCH_ITANIUM2, UARCH_ITANIUM2,
UARCH_ICE_LAKE, UARCH_ICE_LAKE,
UARCH_TIGER_LAKE,
UARCH_ALDER_LAKE,
UARCH_RAPTOR_LAKE,
// AMD // // AMD //
UARCH_AM486, UARCH_AM486,
UARCH_AM5X86, UARCH_AM5X86,
UARCH_SSA5,
UARCH_K5,
UARCH_K6, UARCH_K6,
UARCH_K7, UARCH_K7,
UARCH_K8, UARCH_K8,
@@ -107,7 +116,12 @@ enum {
UARCH_ZEN, UARCH_ZEN,
UARCH_ZEN_PLUS, UARCH_ZEN_PLUS,
UARCH_ZEN2, UARCH_ZEN2,
UARCH_ZEN3 UARCH_ZEN3,
UARCH_ZEN3_PLUS,
UARCH_ZEN4,
UARCH_ZEN4C,
UARCH_ZEN5,
UARCH_ZEN5C,
}; };
struct uarch { struct uarch {
@@ -119,7 +133,8 @@ struct uarch {
#define UARCH_START if (false) {} #define UARCH_START if (false) {}
#define CHECK_UARCH(arch, ef_, f_, em_, m_, s_, str, uarch, process) \ #define CHECK_UARCH(arch, ef_, f_, em_, m_, s_, str, uarch, process) \
else if (ef_ == ef && f_ == f && (em_ == NA || em_ == em) && (m_ == NA || m_ == m) && (s_ == NA || s_ == s)) fill_uarch(arch, str, uarch, process); else if (ef_ == ef && f_ == f && (em_ == NA || em_ == em) && (m_ == NA || m_ == m) && (s_ == NA || s_ == s)) fill_uarch(arch, str, uarch, process);
#define UARCH_END else { printBug("Unknown microarchitecture detected: M=0x%.8X EM=0x%.8X F=0x%.8X EF=0x%.8X S=0x%.8X", m, em, f, ef, s); fill_uarch(arch, STRING_UNKNOWN, UARCH_UNKNOWN, 0); } #define UARCH_END else { printBugCheckRelease("Unknown microarchitecture detected: M=0x%X EM=0x%X F=0x%X EF=0x%X S=0x%X", m, em, f, ef, s); \
fill_uarch(arch, STRING_UNKNOWN, UARCH_UNKNOWN, UNK); }
void fill_uarch(struct uarch* arch, char* str, MICROARCH u, uint32_t process) { void fill_uarch(struct uarch* arch, char* str, MICROARCH u, uint32_t process) {
arch->uarch_str = emalloc(sizeof(char) * (strlen(str)+1)); arch->uarch_str = emalloc(sizeof(char) * (strlen(str)+1));
@@ -132,126 +147,147 @@ void fill_uarch(struct uarch* arch, char* str, MICROARCH u, uint32_t process) {
struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) { struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
struct uarch* arch = emalloc(sizeof(struct uarch)); struct uarch* arch = emalloc(sizeof(struct uarch));
// EF: Extended Family // // EF: Extended Family //
// F: Family // // F: Family //
// EM: Extended Model // // EM: Extended Model //
// M: Model // // M: Model //
// S: Stepping // // S: Stepping //
// ----------------------------------------------------------------------------- // // ------------------------------------------------------------------------------- //
// EF F EM M S // // EF F EM M S //
UARCH_START UARCH_START
CHECK_UARCH(arch, 0, 5, 0, 0, NA, "P5", UARCH_P5, 800) CHECK_UARCH(arch, 0, 4, 0, 0, NA, "i80486DX", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 1, NA, "P5", UARCH_P5, 800) CHECK_UARCH(arch, 0, 4, 0, 1, NA, "i80486DX-50", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 2, NA, "P5", UARCH_P5, UNK) CHECK_UARCH(arch, 0, 4, 0, 2, NA, "i80486SX", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 3, NA, "P5", UARCH_P5, 600) CHECK_UARCH(arch, 0, 4, 0, 3, NA, "i80486DX2", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 4, NA, "P5 MMX", UARCH_P5, UNK) CHECK_UARCH(arch, 0, 4, 0, 4, NA, "i80486SL", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 7, NA, "P5 MMX", UARCH_P5, UNK) CHECK_UARCH(arch, 0, 4, 0, 5, NA, "i80486SX2", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 8, NA, "P5 MMX", UARCH_P5, 250) CHECK_UARCH(arch, 0, 4, 0, 7, NA, "i80486DX2WB", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 9, NA, "P5 MMX", UARCH_P5, UNK) CHECK_UARCH(arch, 0, 4, 0, 8, NA, "i80486DX4", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 6, 0, 0, NA, "P6 Pentium II", UARCH_P6, UNK) CHECK_UARCH(arch, 0, 4, 0, 9, NA, "i80486DX4WB", UARCH_I486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 6, 0, 1, NA, "P6 Pentium II", UARCH_P6, UNK) // process depends on core CHECK_UARCH(arch, 0, 5, 0, 0, NA, "P5", UARCH_P5, 800)
CHECK_UARCH(arch, 0, 6, 0, 2, NA, "P6 Pentium II", UARCH_P6, UNK) CHECK_UARCH(arch, 0, 5, 0, 1, NA, "P5", UARCH_P5, 800)
CHECK_UARCH(arch, 0, 6, 0, 3, NA, "P6 Pentium II", UARCH_P6, 350) CHECK_UARCH(arch, 0, 5, 0, 2, NA, "P54C", UARCH_P5, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 6, 0, 4, NA, "P6 Pentium II", UARCH_P6, UNK) CHECK_UARCH(arch, 0, 5, 0, 3, NA, "P24T (Overdrive)", UARCH_P5, 600) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 6, 0, 5, NA, "P6 Pentium II", UARCH_P6, 250) CHECK_UARCH(arch, 0, 5, 0, 4, NA, "P55C (MMX)", UARCH_P5_MMX, 350) // https://www.cpu-world.com/CPUs/Pentium/TYPE-Pentium%20MMX.html
CHECK_UARCH(arch, 0, 6, 0, 6, NA, "P6 Pentium II", UARCH_P6, UNK) CHECK_UARCH(arch, 0, 5, 0, 7, NA, "P54C", UARCH_P5, 350) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 6, 0, 7, NA, "P6 Pentium III", UARCH_P6, 250) CHECK_UARCH(arch, 0, 5, 0, 8, NA, "Tillamook", UARCH_P5_MMX, 250) // http://instlatx64.atw.hu./
CHECK_UARCH(arch, 0, 6, 0, 8, NA, "P6 Pentium III", UARCH_P6, 180) CHECK_UARCH(arch, 0, 5, 0, 9, 0, "Lakemont", UARCH_LAKEMONT, 32)
CHECK_UARCH(arch, 0, 6, 0, 9, NA, "P6 Pentium M", UARCH_P6, 130) CHECK_UARCH(arch, 0, 5, 0, 9, NA, "P5 (MMX)", UARCH_P5_MMX, UNK)
CHECK_UARCH(arch, 0, 6, 0, 10, NA, "P6 Pentium III", UARCH_P6, 180) CHECK_UARCH(arch, 0, 5, 0, 10, 0, "Lakemont", UARCH_LAKEMONT, 32)
CHECK_UARCH(arch, 0, 6, 0, 11, NA, "P6 Pentium III", UARCH_P6, 130) CHECK_UARCH(arch, 0, 6, 0, 1, 1, "P6", UARCH_P6_PRO, UNK)
CHECK_UARCH(arch, 0, 6, 0, 13, NA, "Dothan", UARCH_DOTHAN, UNK) // process depends on core CHECK_UARCH(arch, 0, 6, 0, 1, 2, "P6", UARCH_P6_PRO, UNK)
CHECK_UARCH(arch, 0, 6, 0, 14, NA, "Yonah", UARCH_YONAH, 65) CHECK_UARCH(arch, 0, 6, 0, 1, 6, "P6", UARCH_P6_PRO, 350)
CHECK_UARCH(arch, 0, 6, 0, 15, NA, "Merom", UARCH_MEROM, 65) CHECK_UARCH(arch, 0, 6, 0, 1, 7, "P6", UARCH_P6_PRO, 350)
CHECK_UARCH(arch, 0, 6, 1, 5, NA, "Dothan", UARCH_DOTHAN, 90) CHECK_UARCH(arch, 0, 6, 0, 1, 9, "P6", UARCH_P6_PRO, 350)
CHECK_UARCH(arch, 0, 6, 1, 6, NA, "Merom", UARCH_MEROM, 65) CHECK_UARCH(arch, 0, 6, 0, 0, NA, "P6 (Pentium II)", UARCH_P6_PENTIUM_II, UNK)
CHECK_UARCH(arch, 0, 6, 1, 7, NA, "Penryn", UARCH_PENYR, 45) CHECK_UARCH(arch, 0, 6, 0, 1, NA, "P6 (Pentium II)", UARCH_P6_PENTIUM_II, UNK) // process depends on core
CHECK_UARCH(arch, 0, 6, 1, 10, NA, "Nehalem", UARCH_NEHALEM, 45) CHECK_UARCH(arch, 0, 6, 0, 2, NA, "P6 (Pentium II)", UARCH_P6_PENTIUM_II, UNK)
CHECK_UARCH(arch, 0, 6, 1, 12, NA, "Bonnell", UARCH_BONNELL, 45) CHECK_UARCH(arch, 0, 6, 0, 3, NA, "P6 (Klamath)", UARCH_P6_PENTIUM_II, 350) // http://instlatx64.atw.hu.
CHECK_UARCH(arch, 0, 6, 1, 13, NA, "Penryn", UARCH_PENYR, 45) CHECK_UARCH(arch, 0, 6, 0, 4, NA, "P6 (Pentium II)", UARCH_P6_PENTIUM_II, UNK)
CHECK_UARCH(arch, 0, 6, 1, 14, NA, "Nehalem", UARCH_NEHALEM, 45) CHECK_UARCH(arch, 0, 6, 0, 5, NA, "P6 (Deschutes)", UARCH_P6_PENTIUM_II, 250) // http://instlatx64.atw.hu.
CHECK_UARCH(arch, 0, 6, 1, 15, NA, "Nehalem", UARCH_NEHALEM, 45) CHECK_UARCH(arch, 0, 6, 0, 6, NA, "P6 (Dixon)", UARCH_P6_PENTIUM_II, UNK) // http://instlatx64.atw.hu.
CHECK_UARCH(arch, 0, 6, 2, 5, NA, "Westmere", UARCH_WESTMERE, 32) CHECK_UARCH(arch, 0, 6, 0, 7, NA, "P6 (Katmai)", UARCH_P6_PENTIUM_III, 250) // Core names from: https://en.wikichip.org/wiki/intel/cpuid. NOTE: Xeon core names are different! https://www.techpowerup.com/cpu-specs/?generation=Intel+Pentium+III+Xeon
CHECK_UARCH(arch, 0, 6, 2 , 6, NA, "Bonnell", UARCH_BONNELL, 45) CHECK_UARCH(arch, 0, 6, 0, 8, NA, "P6 (Coppermine)", UARCH_P6_PENTIUM_III, 180) // Also: https://en.wikipedia.org/wiki/Pentium_III
CHECK_UARCH(arch, 0, 6, 2, 7, NA, "Saltwell", UARCH_SALTWELL, 32) CHECK_UARCH(arch, 0, 6, 0, 9, NA, "P6 (Pentium M)", UARCH_P6_PENTIUM_III, 130)
CHECK_UARCH(arch, 0, 6, 2, 10, NA, "Sandy Bridge", UARCH_SANDY_BRIDGE, 32) CHECK_UARCH(arch, 0, 6, 0, 10, NA, "P6 (Coppermine T)", UARCH_P6_PENTIUM_III, 180)
CHECK_UARCH(arch, 0, 6, 2, 12, NA, "Westmere", UARCH_WESTMERE, 32) CHECK_UARCH(arch, 0, 6, 0, 11, NA, "P6 (Tualatin)", UARCH_P6_PENTIUM_III, 130)
CHECK_UARCH(arch, 0, 6, 2, 13, NA, "Sandy Bridge", UARCH_SANDY_BRIDGE, 32) CHECK_UARCH(arch, 0, 6, 0, 13, NA, "Dothan", UARCH_DOTHAN, UNK) // process depends on core
CHECK_UARCH(arch, 0, 6, 2, 14, NA, "Nehalem", UARCH_NEHALEM, 45) CHECK_UARCH(arch, 0, 6, 0, 14, NA, "Yonah", UARCH_YONAH, 65)
CHECK_UARCH(arch, 0, 6, 2, 15, NA, "Westmere", UARCH_WESTMERE, 32) CHECK_UARCH(arch, 0, 6, 0, 15, NA, "Merom", UARCH_MEROM, 65)
CHECK_UARCH(arch, 0, 6, 3, 5, NA, "Saltwell", UARCH_SALTWELL, 14) CHECK_UARCH(arch, 0, 6, 1, 5, NA, "Dothan", UARCH_DOTHAN, 90)
CHECK_UARCH(arch, 0, 6, 3, 6, NA, "Saltwell", UARCH_SALTWELL, 32) CHECK_UARCH(arch, 0, 6, 1, 6, NA, "Merom", UARCH_MEROM, 65)
CHECK_UARCH(arch, 0, 6, 3, 7, NA, "Silvermont", UARCH_SILVERMONT, 22) CHECK_UARCH(arch, 0, 6, 1, 7, NA, "Penryn", UARCH_PENYR, 45)
CHECK_UARCH(arch, 0, 6, 3, 10, NA, "Ivy Bridge", UARCH_IVY_BRIDGE, 22) CHECK_UARCH(arch, 0, 6, 1, 10, NA, "Nehalem", UARCH_NEHALEM, 45)
CHECK_UARCH(arch, 0, 6, 3, 12, NA, "Haswell", UARCH_HASWELL, 22) CHECK_UARCH(arch, 0, 6, 1, 12, NA, "Bonnell", UARCH_BONNELL, 45)
CHECK_UARCH(arch, 0, 6, 3, 13, NA, "Broadwell", UARCH_BROADWELL, 14) CHECK_UARCH(arch, 0, 6, 1, 13, NA, "Penryn", UARCH_PENYR, 45)
CHECK_UARCH(arch, 0, 6, 3, 14, NA, "Ivy Bridge", UARCH_IVY_BRIDGE, 22) CHECK_UARCH(arch, 0, 6, 1, 14, NA, "Nehalem", UARCH_NEHALEM, 45)
CHECK_UARCH(arch, 0, 6, 3, 15, NA, "Haswell", UARCH_HASWELL, 22) CHECK_UARCH(arch, 0, 6, 1, 15, NA, "Nehalem", UARCH_NEHALEM, 45)
CHECK_UARCH(arch, 0, 6, 4, 5, NA, "Haswell", UARCH_HASWELL, 22) CHECK_UARCH(arch, 0, 6, 2, 5, NA, "Westmere", UARCH_WESTMERE, 32)
CHECK_UARCH(arch, 0, 6, 4, 6, NA, "Haswell", UARCH_HASWELL, 22) CHECK_UARCH(arch, 0, 6, 2 , 6, NA, "Bonnell", UARCH_BONNELL, 45)
CHECK_UARCH(arch, 0, 6, 4, 7, NA, "Broadwell", UARCH_BROADWELL, 14) CHECK_UARCH(arch, 0, 6, 2, 7, NA, "Saltwell", UARCH_SALTWELL, 32)
CHECK_UARCH(arch, 0, 6, 4, 10, NA, "Silvermont", UARCH_SILVERMONT, 22) // no docs, but /proc/cpuinfo seen in wild CHECK_UARCH(arch, 0, 6, 2, 10, NA, "Sandy Bridge", UARCH_SANDY_BRIDGE, 32)
CHECK_UARCH(arch, 0, 6, 4, 12, NA, "Airmont", UARCH_AIRMONT, 14) CHECK_UARCH(arch, 0, 6, 2, 12, NA, "Westmere", UARCH_WESTMERE, 32)
CHECK_UARCH(arch, 0, 6, 4, 13, NA, "Silvermont", UARCH_SILVERMONT, 22) CHECK_UARCH(arch, 0, 6, 2, 13, NA, "Sandy Bridge", UARCH_SANDY_BRIDGE, 32)
CHECK_UARCH(arch, 0, 6, 4, 14, 8, "Kaby Lake", UARCH_KABY_LAKE, 14) CHECK_UARCH(arch, 0, 6, 2, 14, NA, "Nehalem", UARCH_NEHALEM, 45)
CHECK_UARCH(arch, 0, 6, 4, 14, NA, "Skylake", UARCH_SKYLAKE, 14) CHECK_UARCH(arch, 0, 6, 2, 15, NA, "Westmere", UARCH_WESTMERE, 32)
CHECK_UARCH(arch, 0, 6, 4, 15, NA, "Broadwell", UARCH_BROADWELL, 14) CHECK_UARCH(arch, 0, 6, 3, 5, NA, "Saltwell", UARCH_SALTWELL, 14)
CHECK_UARCH(arch, 0, 6, 5, 5, 6, "Cascade Lake", UARCH_CASCADE_LAKE, 14) // no docs, but example from Greg Stewart CHECK_UARCH(arch, 0, 6, 3, 6, NA, "Saltwell", UARCH_SALTWELL, 32)
CHECK_UARCH(arch, 0, 6, 5, 5, 7, "Cascade Lake", UARCH_CASCADE_LAKE, 14) CHECK_UARCH(arch, 0, 6, 3, 7, NA, "Silvermont", UARCH_SILVERMONT, 22)
CHECK_UARCH(arch, 0, 6, 5, 5, 10, "Cooper Lake", UARCH_COOPER_LAKE, 14) CHECK_UARCH(arch, 0, 6, 3, 10, NA, "Ivy Bridge", UARCH_IVY_BRIDGE, 22)
CHECK_UARCH(arch, 0, 6, 5, 5, NA, "Skylake", UARCH_SKYLAKE, 14) CHECK_UARCH(arch, 0, 6, 3, 12, NA, "Haswell", UARCH_HASWELL, 22)
CHECK_UARCH(arch, 0, 6, 5, 6, NA, "Broadwell", UARCH_BROADWELL, 14) CHECK_UARCH(arch, 0, 6, 3, 13, NA, "Broadwell", UARCH_BROADWELL, 14)
CHECK_UARCH(arch, 0, 6, 5, 7, NA, "Knights Landing", UARCH_KNIGHTS_LANDING, 14) CHECK_UARCH(arch, 0, 6, 3, 14, NA, "Ivy Bridge", UARCH_IVY_BRIDGE, 22)
CHECK_UARCH(arch, 0, 6, 5, 10, NA, "Silvermont", UARCH_SILVERMONT, 22) // no spec update; only MSR_CPUID_table* so far CHECK_UARCH(arch, 0, 6, 3, 15, NA, "Haswell", UARCH_HASWELL, 22)
CHECK_UARCH(arch, 0, 6, 5, 12, NA, "Goldmont", UARCH_GOLDMONT, 14) CHECK_UARCH(arch, 0, 6, 4, 5, NA, "Haswell", UARCH_HASWELL, 22)
CHECK_UARCH(arch, 0, 6, 5, 13, NA, "Silvermont", UARCH_SILVERMONT, 22) // no spec update; only MSR_CPUID_table* so far CHECK_UARCH(arch, 0, 6, 4, 6, NA, "Haswell", UARCH_HASWELL, 22)
CHECK_UARCH(arch, 0, 6, 5, 14, 8, "Kaby Lake", UARCH_KABY_LAKE, 14) CHECK_UARCH(arch, 0, 6, 4, 7, NA, "Broadwell", UARCH_BROADWELL, 14)
CHECK_UARCH(arch, 0, 6, 5, 14, NA, "Skylake", UARCH_SKYLAKE, 14) CHECK_UARCH(arch, 0, 6, 4, 10, NA, "Silvermont", UARCH_SILVERMONT, 22) // no docs, but /proc/cpuinfo seen in wild
CHECK_UARCH(arch, 0, 6, 5, 15, NA, "Goldmont", UARCH_GOLDMONT, 14) CHECK_UARCH(arch, 0, 6, 4, 12, NA, "Airmont", UARCH_AIRMONT, 14)
CHECK_UARCH(arch, 0, 6, 6, 6, NA, "Palm Cove", UARCH_PALM_COVE, 10) // no spec update; only MSR_CPUID_table* so far CHECK_UARCH(arch, 0, 6, 4, 13, NA, "Silvermont", UARCH_SILVERMONT, 22)
CHECK_UARCH(arch, 0, 6, 6, 10, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far CHECK_UARCH(arch, 0, 6, 4, 14, 8, "Kaby Lake", UARCH_KABY_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 6, 12, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far CHECK_UARCH(arch, 0, 6, 4, 14, NA, "Skylake", UARCH_SKYLAKE, 14)
CHECK_UARCH(arch, 0, 6, 7, 5, NA, "Airmont", UARCH_AIRMONT, 14) // no spec update; whispers & rumors CHECK_UARCH(arch, 0, 6, 4, 15, NA, "Broadwell", UARCH_BROADWELL, 14)
CHECK_UARCH(arch, 0, 6, 7, 10, NA, "Goldmont Plus", UARCH_GOLDMONT_PLUS, 14) CHECK_UARCH(arch, 0, 6, 5, 5, 6, "Cascade Lake", UARCH_CASCADE_LAKE, 14) // no docs, but example from Greg Stewart
CHECK_UARCH(arch, 0, 6, 7, 13, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far CHECK_UARCH(arch, 0, 6, 5, 5, 7, "Cascade Lake", UARCH_CASCADE_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 7, 14, NA, "Ice Lake", UARCH_ICE_LAKE, 10) CHECK_UARCH(arch, 0, 6, 5, 5, 10, "Cooper Lake", UARCH_COOPER_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 8, 5, NA, "Knights Mill", UARCH_KNIGHTS_MILL, 14) // no spec update; only MSR_CPUID_table* so far CHECK_UARCH(arch, 0, 6, 5, 5, NA, "Skylake", UARCH_SKYLAKE, 14)
CHECK_UARCH(arch, 0, 6, 8, 6, NA, "Tremont", UARCH_TREMONT, 10) // LX* CHECK_UARCH(arch, 0, 6, 5, 6, NA, "Broadwell", UARCH_BROADWELL, 14)
CHECK_UARCH(arch, 0, 6, 8, 10, NA, "Tremont", UARCH_TREMONT, 10) // no spec update; only geekbench.com example CHECK_UARCH(arch, 0, 6, 5, 7, NA, "Knights Landing", UARCH_KNIGHTS_LANDING, 14)
CHECK_UARCH(arch, 0, 6, 8, 12, NA, "Willow Cove", UARCH_WILLOW_COVE, 10) // found only on en.wikichip.org CHECK_UARCH(arch, 0, 6, 5, 10, NA, "Silvermont", UARCH_SILVERMONT, 22) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 8, 13, NA, "Willow Cove", UARCH_WILLOW_COVE, 10) // LX* CHECK_UARCH(arch, 0, 6, 5, 12, NA, "Goldmont", UARCH_GOLDMONT, 14)
CHECK_UARCH(arch, 0, 6, 8, 14, 9, "Amber Lake", UARCH_AMBER_LAKE, 14) // wikichip CHECK_UARCH(arch, 0, 6, 5, 13, NA, "Silvermont", UARCH_SILVERMONT, 22) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 8, 14, 10, "Kaby Lake", UARCH_KABY_LAKE, 14) // wikichip CHECK_UARCH(arch, 0, 6, 5, 14, 8, "Kaby Lake", UARCH_KABY_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 8, 14, 11, "Whiskey Lake", UARCH_WHISKEY_LAKE, 14) // wikichip CHECK_UARCH(arch, 0, 6, 5, 14, NA, "Skylake", UARCH_SKYLAKE, 14)
CHECK_UARCH(arch, 0, 6, 8, 14, 12, "Comet Lake", UARCH_COMET_LAKE, 14) // wikichip CHECK_UARCH(arch, 0, 6, 5, 15, NA, "Goldmont", UARCH_GOLDMONT, 14)
CHECK_UARCH(arch, 0, 6, 9, 6, NA, "Tremont", UARCH_TREMONT, 10) // LX* CHECK_UARCH(arch, 0, 6, 6, 6, NA, "Palm Cove", UARCH_PALM_COVE, 10) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 9, 12, NA, "Tremont", UARCH_TREMONT, 10) // LX* CHECK_UARCH(arch, 0, 6, 6, 10, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 9, 13, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // LX* CHECK_UARCH(arch, 0, 6, 6, 12, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 9, 14, 9, "Kaby Lake", UARCH_KABY_LAKE, 14) CHECK_UARCH(arch, 0, 6, 7, 5, NA, "Airmont", UARCH_AIRMONT, 14) // no spec update; whispers & rumors
CHECK_UARCH(arch, 0, 6, 9, 14, 10, "Coffee Lake", UARCH_COFFE_LAKE, 14) CHECK_UARCH(arch, 0, 6, 7, 10, NA, "Goldmont Plus", UARCH_GOLDMONT_PLUS, 14)
CHECK_UARCH(arch, 0, 6, 9, 14, 11, "Coffee Lake", UARCH_COFFE_LAKE, 14) CHECK_UARCH(arch, 0, 6, 7, 13, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 9, 14, 12, "Coffee Lake", UARCH_COFFE_LAKE, 14) CHECK_UARCH(arch, 0, 6, 7, 14, NA, "Ice Lake", UARCH_ICE_LAKE, 10)
CHECK_UARCH(arch, 0, 6, 9, 14, 13, "Coffee Lake", UARCH_COFFE_LAKE, 14) CHECK_UARCH(arch, 0, 6, 8, 5, NA, "Knights Mill", UARCH_KNIGHTS_MILL, 14) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 10, 5, NA, "Comet Lake", UARCH_COMET_LAKE, 14) // wikichip CHECK_UARCH(arch, 0, 6, 8, 6, NA, "Tremont", UARCH_TREMONT, 10) // LX*
CHECK_UARCH(arch, 0, 6, 10, 6, NA, "Comet Lake", UARCH_COMET_LAKE, 14) // instlatx64.atw.hu (i7-10710U) CHECK_UARCH(arch, 0, 6, 8, 10, NA, "Tremont", UARCH_TREMONT, 10) // no spec update; only geekbench.com example
CHECK_UARCH(arch, 0, 6, 10, 7, NA, "Rocket Lake", UARCH_ROCKET_LAKE, 14) // instlatx64.atw.hu (i7-11700K) CHECK_UARCH(arch, 0, 6, 8, 12, NA, "Tiger Lake", UARCH_TIGER_LAKE, 10) // instlatx64
CHECK_UARCH(arch, 0, 11, 0, 0, NA, "Knights Ferry", UARCH_KNIGHTS_FERRY, 45) // found only on en.wikichip.org CHECK_UARCH(arch, 0, 6, 8, 13, NA, "Tiger Lake", UARCH_TIGER_LAKE, 10) // instlatx64
CHECK_UARCH(arch, 0, 11, 0, 1, NA, "Knights Corner", UARCH_KNIGHTS_CORNER, 22) // CHECK_UARCH(arch, 0, 6, 8, 14, 9, ...) It is not possible to determine uarch only from CPUID dump (can be Kaby Lake or Amber Lake)
CHECK_UARCH(arch, 0, 15, 0, 0, NA, "Willamette", UARCH_WILLAMETTE, 180) // CHECK_UARCH(arch, 0, 6, 8, 14, 10, ...) It is not possible to determine uarch only from CPUID dump (can be Kaby Lake R or Coffee Lake U)
CHECK_UARCH(arch, 0, 15, 0, 1, NA, "Willamette", UARCH_WILLAMETTE, 180) CHECK_UARCH(arch, 0, 6, 8, 14, 11, "Whiskey Lake", UARCH_WHISKEY_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 15, 0, 2, NA, "Northwood", UARCH_NORTHWOOD, 130) CHECK_UARCH(arch, 0, 6, 8, 14, 12, "Comet Lake", UARCH_COMET_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 15, 0, 3, NA, "Prescott", UARCH_PRESCOTT, 90) CHECK_UARCH(arch, 0, 6, 9, 6, NA, "Tremont", UARCH_TREMONT, 10) // LX*
CHECK_UARCH(arch, 0, 15, 0, 4, NA, "Prescott", UARCH_PRESCOTT, 90) CHECK_UARCH(arch, 0, 6, 9, 7, NA, "Alder Lake", UARCH_ALDER_LAKE, 10) // instlatx64 (Alder Lake-S)
CHECK_UARCH(arch, 0, 15, 0, 6, NA, "Cedar Mill", UARCH_CEDAR_MILL, 65) CHECK_UARCH(arch, 0, 6, 9, 10, NA, "Alder Lake", UARCH_ALDER_LAKE, 10) // instlatx64 (Alder Lake-P)
CHECK_UARCH(arch, 1, 15, 0, 0, NA, "Itanium2", UARCH_ITANIUM2, 180) CHECK_UARCH(arch, 0, 6, 9, 12, NA, "Tremont", UARCH_TREMONT, 10) // LX*
CHECK_UARCH(arch, 1, 15, 0, 1, NA, "Itanium2", UARCH_ITANIUM2, 130) CHECK_UARCH(arch, 0, 6, 9, 13, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // LX*
CHECK_UARCH(arch, 1, 15, 0, 2, NA, "Itanium2", UARCH_ITANIUM2, 130) CHECK_UARCH(arch, 0, 6, 9, 14, 9, "Kaby Lake", UARCH_KABY_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 9, 14, 10, "Coffee Lake", UARCH_COFFEE_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 9, 14, 11, "Coffee Lake", UARCH_COFFEE_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 9, 14, 12, "Coffee Lake", UARCH_COFFEE_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 9, 14, 13, "Coffee Lake", UARCH_COFFEE_LAKE, 14)
CHECK_UARCH(arch, 0, 6, 10, 5, NA, "Comet Lake", UARCH_COMET_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 6, 10, 6, NA, "Comet Lake", UARCH_COMET_LAKE, 14) // instlatx64.atw.hu (i7-10710U)
CHECK_UARCH(arch, 0, 6, 10, 7, NA, "Rocket Lake", UARCH_ROCKET_LAKE, 14) // instlatx64.atw.hu (i7-11700K)
CHECK_UARCH(arch, 0, 6, 11, 7, NA, "Raptor Lake", UARCH_RAPTOR_LAKE, 10) // instlatx64.atw.hu (i5-13600K)
CHECK_UARCH(arch, 0, 6, 11, 10, NA, "Raptor Lake", UARCH_RAPTOR_LAKE, 10) // instlatx64.atw.hu (i7-1370P)
CHECK_UARCH(arch, 0, 6, 11, 14, NA, "Alder Lake", UARCH_ALDER_LAKE, 10) // instlatx64.atw.hu (Alder Lake-N)
CHECK_UARCH(arch, 0, 6, 11, 15, NA, "Raptor Lake", UARCH_RAPTOR_LAKE, 10) // instlatx64.atw.hu (i5-13500)
CHECK_UARCH(arch, 0, 11, 0, 0, NA, "Knights Ferry", UARCH_KNIGHTS_FERRY, 45) // found only on en.wikichip.org
CHECK_UARCH(arch, 0, 11, 0, 1, NA, "Knights Corner", UARCH_KNIGHTS_CORNER, 22)
CHECK_UARCH(arch, 0, 15, 0, 0, NA, "Willamette", UARCH_WILLAMETTE, 180)
CHECK_UARCH(arch, 0, 15, 0, 1, NA, "Willamette", UARCH_WILLAMETTE, 180)
CHECK_UARCH(arch, 0, 15, 0, 2, NA, "Northwood", UARCH_NORTHWOOD, 130)
CHECK_UARCH(arch, 0, 15, 0, 3, NA, "Prescott", UARCH_PRESCOTT, 90)
CHECK_UARCH(arch, 0, 15, 0, 4, NA, "Prescott", UARCH_PRESCOTT, 90)
CHECK_UARCH(arch, 0, 15, 0, 6, NA, "Cedar Mill", UARCH_CEDAR_MILL, 65)
CHECK_UARCH(arch, 1, 15, 0, 0, NA, "Itanium2", UARCH_ITANIUM2, 180)
CHECK_UARCH(arch, 1, 15, 0, 1, NA, "Itanium2", UARCH_ITANIUM2, 130)
CHECK_UARCH(arch, 1, 15, 0, 2, NA, "Itanium2", UARCH_ITANIUM2, 130)
UARCH_END UARCH_END
return arch; return arch;
} }
// iNApired in Todd Allen's decode_uarch_amd // Inspired in Todd Allen's decode_uarch_amd
struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) { struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
struct uarch* arch = emalloc(sizeof(struct uarch)); struct uarch* arch = emalloc(sizeof(struct uarch));
@@ -263,14 +299,20 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- //
// EF F EM M S // // EF F EM M S //
UARCH_START UARCH_START
CHECK_UARCH(arch, 0, 4, 0, 3, NA, "Am486", UARCH_AM486, UNK) CHECK_UARCH(arch, 0, 4, 0, 3, NA, "Am486DX2", UARCH_AM486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 4, 0, 7, NA, "Am486", UARCH_AM486, UNK) CHECK_UARCH(arch, 0, 4, 0, 7, NA, "Am486DX2WB", UARCH_AM486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 4, 0, 8, NA, "Am486", UARCH_AM486, UNK) CHECK_UARCH(arch, 0, 4, 0, 8, NA, "Am486DX4", UARCH_AM486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 4, 0, 9, NA, "Am486", UARCH_AM486, UNK) CHECK_UARCH(arch, 0, 4, 0, 9, NA, "Am486DX4WB", UARCH_AM486, UNK) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 4, NA, NA, NA, "Am5x86", UARCH_AM5X86, UNK) CHECK_UARCH(arch, 0, 4, 0, 14, NA, "Am5x86", UARCH_AM5X86, 350) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 4, 0, 15, NA, "Am5x86WB", UARCH_AM5X86, 350) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 0, NA, "SSA5 (K5)", UARCH_SSA5, 350) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 1, NA, "K5", UARCH_K5, 350) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 2, NA, "K5", UARCH_K5, 350) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 3, NA, "K5", UARCH_K5, 350) // https://sandpile.org/x86/cpuid.htm#level_0000_0001h
CHECK_UARCH(arch, 0, 5, 0, 6, NA, "K6", UARCH_K6, 300) CHECK_UARCH(arch, 0, 5, 0, 6, NA, "K6", UARCH_K6, 300)
CHECK_UARCH(arch, 0, 5, 0, 7, NA, "K6", UARCH_K6, 250) // *p from sandpile.org CHECK_UARCH(arch, 0, 5, 0, 7, NA, "K6", UARCH_K6, 250) // *p from sandpile.org
CHECK_UARCH(arch, 0, 5, 0, 13, NA, "K6", UARCH_K6, 80) // *p from sandpile.org CHECK_UARCH(arch, 0, 5, 0, 10, NA, "K7", UARCH_K7, 130) // Geode NX
CHECK_UARCH(arch, 0, 5, 0, 13, NA, "K6", UARCH_K6, 80) // *p from sandpile.org
CHECK_UARCH(arch, 0, 5, NA, NA, NA, "K6", UARCH_K6, UNK) CHECK_UARCH(arch, 0, 5, NA, NA, NA, "K6", UARCH_K6, UNK)
CHECK_UARCH(arch, 0, 6, 0, 1, NA, "K7", UARCH_K7, 250) CHECK_UARCH(arch, 0, 6, 0, 1, NA, "K7", UARCH_K7, 250)
CHECK_UARCH(arch, 0, 6, 0, 2, NA, "K7", UARCH_K7, 180) CHECK_UARCH(arch, 0, 6, 0, 2, NA, "K7", UARCH_K7, 180)
@@ -325,7 +367,7 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
CHECK_UARCH(arch, 2, 15, NA, NA, NA, "Puma 2008", UARCH_PUMA_2008, 65) CHECK_UARCH(arch, 2, 15, NA, NA, NA, "Puma 2008", UARCH_PUMA_2008, 65)
CHECK_UARCH(arch, 3, 15, NA, NA, NA, "K10", UARCH_K10, 32) CHECK_UARCH(arch, 3, 15, NA, NA, NA, "K10", UARCH_K10, 32)
CHECK_UARCH(arch, 5, 15, NA, NA, NA, "Bobcat", UARCH_BOBCAT, 40) CHECK_UARCH(arch, 5, 15, NA, NA, NA, "Bobcat", UARCH_BOBCAT, 40)
CHECK_UARCH(arch, 6, 15, 0, 0, NA, "Bulldozer", UARCH_BULLDOZER, 32) // iNAtlatx64 engr sample CHECK_UARCH(arch, 6, 15, 0, 0, NA, "Bulldozer", UARCH_BULLDOZER, 32) // instlatx64 engr sample
CHECK_UARCH(arch, 6, 15, 0, 1, NA, "Bulldozer", UARCH_BULLDOZER, 32) CHECK_UARCH(arch, 6, 15, 0, 1, NA, "Bulldozer", UARCH_BULLDOZER, 32)
CHECK_UARCH(arch, 6, 15, 0, 2, NA, "Piledriver", UARCH_PILEDRIVER, 32) CHECK_UARCH(arch, 6, 15, 0, 2, NA, "Piledriver", UARCH_PILEDRIVER, 32)
CHECK_UARCH(arch, 6, 15, 1, 0, NA, "Piledriver", UARCH_PILEDRIVER, 32) CHECK_UARCH(arch, 6, 15, 1, 0, NA, "Piledriver", UARCH_PILEDRIVER, 32)
@@ -333,36 +375,197 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
CHECK_UARCH(arch, 6, 15, 3, 0, NA, "Steamroller", UARCH_STEAMROLLER, 28) CHECK_UARCH(arch, 6, 15, 3, 0, NA, "Steamroller", UARCH_STEAMROLLER, 28)
CHECK_UARCH(arch, 6, 15, 3, 8, NA, "Steamroller", UARCH_STEAMROLLER, 28) CHECK_UARCH(arch, 6, 15, 3, 8, NA, "Steamroller", UARCH_STEAMROLLER, 28)
CHECK_UARCH(arch, 6, 15, 4, 0, NA, "Steamroller", UARCH_STEAMROLLER, 28) // Software Optimization Guide (15h) says it has the same iNAt latencies as (6,15),(3,x). CHECK_UARCH(arch, 6, 15, 4, 0, NA, "Steamroller", UARCH_STEAMROLLER, 28) // Software Optimization Guide (15h) says it has the same iNAt latencies as (6,15),(3,x).
CHECK_UARCH(arch, 6, 15, 6, 0, NA, "Excavator", UARCH_EXCAVATOR, 28) // undocumented, but iNAtlatx64 samples CHECK_UARCH(arch, 6, 15, 6, 0, NA, "Excavator", UARCH_EXCAVATOR, 28) // undocumented, but instlatx64 samples
CHECK_UARCH(arch, 6, 15, 6, 5, NA, "Excavator", UARCH_EXCAVATOR, 28) // undocumented, but sample from Alexandros Couloumbis CHECK_UARCH(arch, 6, 15, 6, 5, NA, "Excavator", UARCH_EXCAVATOR, 28) // undocumented, but sample from Alexandros Couloumbis
CHECK_UARCH(arch, 6, 15, 7, 0, NA, "Excavator", UARCH_EXCAVATOR, 28) CHECK_UARCH(arch, 6, 15, 7, 0, NA, "Excavator", UARCH_EXCAVATOR, 28)
CHECK_UARCH(arch, 7, 15, 0, 0, NA, "Jaguar", UARCH_JAGUAR, 28) CHECK_UARCH(arch, 7, 15, 0, 0, NA, "Jaguar", UARCH_JAGUAR, 28)
CHECK_UARCH(arch, 7, 15, 1, NA, NA, "Jaguar", UARCH_JAGUAR, 14) // instlatx64 (PS4) Normal PS4 is 28nm, Slim and Pro are 16nm
CHECK_UARCH(arch, 7, 15, 2, 6, NA, "Jaguar", UARCH_JAGUAR, 28) // AMD Cato (Xbox One?)
CHECK_UARCH(arch, 7, 15, 3, 0, NA, "Puma 2014", UARCH_PUMA_2014, 28) CHECK_UARCH(arch, 7, 15, 3, 0, NA, "Puma 2014", UARCH_PUMA_2014, 28)
CHECK_UARCH(arch, 8, 15, 0, 0, NA, "Zen", UARCH_ZEN, 14) // iNAtlatx64 engr sample CHECK_UARCH(arch, 8, 15, 0, 0, NA, "Zen", UARCH_ZEN, 14) // instlatx64 engr sample
CHECK_UARCH(arch, 8, 15, 0, 1, NA, "Zen", UARCH_ZEN, 14) CHECK_UARCH(arch, 8, 15, 0, 1, NA, "Zen", UARCH_ZEN, 14)
CHECK_UARCH(arch, 8, 15, 0, 8, NA, "Zen+", UARCH_ZEN_PLUS, 12) CHECK_UARCH(arch, 8, 15, 0, 8, NA, "Zen+", UARCH_ZEN_PLUS, 12)
CHECK_UARCH(arch, 8, 15, 1, 1, NA, "Zen", UARCH_ZEN, 14) // found only on en.wikichip.org & iNAtlatx64 examples CHECK_UARCH(arch, 8, 15, 1, 1, NA, "Zen", UARCH_ZEN, 14) // found only on en.wikichip.org & instlatx64 examples
CHECK_UARCH(arch, 8, 15, 1, 8, NA, "Zen+", UARCH_ZEN_PLUS, 12) // found only on en.wikichip.org CHECK_UARCH(arch, 8, 15, 1, 8, NA, "Zen+", UARCH_ZEN_PLUS, 12) // found only on en.wikichip.org
CHECK_UARCH(arch, 8, 15, 2, 0, NA, "Zen", UARCH_ZEN, 14) // Dali, found on instlatx64 and en.wikichip.org
CHECK_UARCH(arch, 8, 15, 3, 1, NA, "Zen 2", UARCH_ZEN2, 7) // found only on en.wikichip.org CHECK_UARCH(arch, 8, 15, 3, 1, NA, "Zen 2", UARCH_ZEN2, 7) // found only on en.wikichip.org
CHECK_UARCH(arch, 8, 15, 4, 7, NA, "Zen 2", UARCH_ZEN2, 7) // instlatx64 example (AMD 4700S)
CHECK_UARCH(arch, 8, 15, 5, 0, NA, "Zen", UARCH_ZEN, 14) // instlatx64 example (Subor Z+)
CHECK_UARCH(arch, 8, 15, 6, 0, NA, "Zen 2", UARCH_ZEN2, 7) // undocumented, geekbench.com example CHECK_UARCH(arch, 8, 15, 6, 0, NA, "Zen 2", UARCH_ZEN2, 7) // undocumented, geekbench.com example
CHECK_UARCH(arch, 8, 15, 6, 8, NA, "Zen 2", UARCH_ZEN2, 7) // found on instlatx64 CHECK_UARCH(arch, 8, 15, 6, 8, NA, "Zen 2", UARCH_ZEN2, 7) // found on instlatx64
CHECK_UARCH(arch, 8, 15, 7, 1, NA, "Zen 2", UARCH_ZEN2, 7) // samples from Steven Noonan and instlatx64 CHECK_UARCH(arch, 8, 15, 7, 1, NA, "Zen 2", UARCH_ZEN2, 7) // samples from Steven Noonan and instlatx64
CHECK_UARCH(arch, 8, 15, 8, 4, NA, "Zen 2", UARCH_ZEN2, 7) // instlatx64 (Xbox Series X?)
CHECK_UARCH(arch, 8, 15, 9, 0, 2, "Zen 2", UARCH_ZEN2, 7) // Steam Deck (instlatx64)
CHECK_UARCH(arch, 8, 15, 10, 0, NA, "Zen 2", UARCH_ZEN2, 6) // instlatx64
CHECK_UARCH(arch, 10, 15, 0, 1, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
CHECK_UARCH(arch, 10, 15, 0, 8, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
CHECK_UARCH(arch, 10, 15, 1, 1, NA, "Zen 4", UARCH_ZEN4, 5) // instlatx64
CHECK_UARCH(arch, 10, 15, 1, 8, NA, "Zen 4", UARCH_ZEN4, 5) // instlatx64
CHECK_UARCH(arch, 10, 15, 2, 1, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64 CHECK_UARCH(arch, 10, 15, 2, 1, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
CHECK_UARCH(arch, 10, 15, 3, NA, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
CHECK_UARCH(arch, 10, 15, 4, 4, NA, "Zen 3+", UARCH_ZEN3_PLUS, 6) // instlatx64 (they say it is Zen3...)
CHECK_UARCH(arch, 10, 15, 5, 0, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64 CHECK_UARCH(arch, 10, 15, 5, 0, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
CHECK_UARCH(arch, 10, 15, 6, 1, 2, "Zen 4", UARCH_ZEN4, 5) // instlatx64
CHECK_UARCH(arch, 10, 15, 7, 4, 1, "Zen 4", UARCH_ZEN4, 4) // instlatx64
CHECK_UARCH(arch, 10, 15, 7, 5, 2, "Zen 4", UARCH_ZEN4, 4) // instlatx64
CHECK_UARCH(arch, 10, 15, 7, 8, 0, "Zen 4", UARCH_ZEN4, 4) // instlatx64
CHECK_UARCH(arch, 10, 15, 8, NA, NA, "Zen 4", UARCH_ZEN4, 5) // instlatx64 (AMD MI300C)
CHECK_UARCH(arch, 10, 15, 9, NA, NA, "Zen 4", UARCH_ZEN4, 5) // instlatx64 (AMD MI300A)
CHECK_UARCH(arch, 10, 15, 10, NA, NA, "Zen 4c", UARCH_ZEN4C, 5) // instlatx64
CHECK_UARCH(arch, 11, 15, 0, NA, NA, "Zen 5", UARCH_ZEN5, 4) // Turin/EPYC (instlatx64)
CHECK_UARCH(arch, 11, 15, 1, NA, NA, "Zen 5c", UARCH_ZEN5C, 3) // Zen5c EPYC (instlatx64, https://en.wikipedia.org/wiki/Zen_5#cite_note-10)
CHECK_UARCH(arch, 11, 15, 2, NA, NA, "Zen 5", UARCH_ZEN5, 4) // Strix Point (instlatx64)
CHECK_UARCH(arch, 11, 15, 4, NA, NA, "Zen 5", UARCH_ZEN5, 4) // Granite Ridge (instlatx64)
CHECK_UARCH(arch, 11, 15, 6, NA, NA, "Zen 5", UARCH_ZEN5, 4) // Krackan Point (instlatx64)
CHECK_UARCH(arch, 11, 15, 7, NA, NA, "Zen 5", UARCH_ZEN5, 4) // Strix Halo (instlatx64)
UARCH_END UARCH_END
return arch; return arch;
} }
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) { struct uarch* get_uarch_from_cpuid_hygon(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
if(cpu->cpu_vendor == CPU_VENDOR_INTEL) struct uarch* arch = emalloc(sizeof(struct uarch));
// EF: Extended Family //
// F: Family //
// EM: Extended Model //
// M: Model //
// S: Stepping //
// ----------------------------------------------------------------------------- //
// EF F EM M S //
UARCH_START
// https://www.phoronix.com/news/Hygon-Dhyana-AMD-China-CPUs
CHECK_UARCH(arch, 9, 15, 0, 1, NA, "Zen", UARCH_ZEN, UNK) // https://github.com/Dr-Noob/cpufetch/issues/244
// CHECK_UARCH(arch, 9, 15, 0, 2, NA, "???", ?????????, UNK) // http://instlatx64.atw.hu/
UARCH_END
return arch;
}
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t dump, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
if(cpu->cpu_vendor == CPU_VENDOR_INTEL) {
struct uarch* arch = emalloc(sizeof(struct uarch));
if(dump == 0x000806E9) {
if (cpu->cpu_name == NULL) {
printErr("Unable to find uarch without CPU name");
fill_uarch(arch, STRING_UNKNOWN, UARCH_UNKNOWN, UNK);
return arch;
}
// It is not possible to determine uarch only from CPUID dump (can be Kaby Lake or Amber Lake)
// See issue https://github.com/Dr-Noob/cpufetch/issues/122
if(strstr(cpu->cpu_name, "Y") != NULL) {
fill_uarch(arch, "Amber Lake", UARCH_AMBER_LAKE, 14);
}
else {
fill_uarch(arch, "Kaby Lake", UARCH_KABY_LAKE, 14);
}
return arch;
}
else if (dump == 0x000806EA) {
if (cpu->cpu_name == NULL) {
printErr("Unable to find uarch without CPU name");
fill_uarch(arch, STRING_UNKNOWN, UARCH_UNKNOWN, UNK);
return arch;
}
// It is not possible to determine uarch only from CPUID dump (can be Kaby Lake R or Coffee Lake U)
// See issue https://github.com/Dr-Noob/cpufetch/issues/149
if(strstr(cpu->cpu_name, "i5-8250U") != NULL ||
strstr(cpu->cpu_name, "i5-8350U") != NULL ||
strstr(cpu->cpu_name, "i7-8550U") != NULL ||
strstr(cpu->cpu_name, "i7-8650U") != NULL) {
fill_uarch(arch, "Kaby Lake", UARCH_KABY_LAKE, 14);
}
else {
fill_uarch(arch, "Coffee Lake", UARCH_COFFEE_LAKE, 14);
}
return arch;
}
return get_uarch_from_cpuid_intel(ef, f, em, m, s); return get_uarch_from_cpuid_intel(ef, f, em, m, s);
else }
else if(cpu->cpu_vendor == CPU_VENDOR_AMD) {
return get_uarch_from_cpuid_amd(ef, f, em, m, s); return get_uarch_from_cpuid_amd(ef, f, em, m, s);
}
else if(cpu->cpu_vendor == CPU_VENDOR_HYGON) {
return get_uarch_from_cpuid_hygon(ef, f, em, m, s);
}
else {
printBug("Invalid CPU vendor: %d", cpu->cpu_vendor);
return NULL;
}
}
// If we cannot get the CPU name from CPUID, try to infer it from uarch
char* infer_cpu_name_from_uarch(struct uarch* arch) {
char* cpu_name = NULL;
if (arch == NULL) {
printErr("infer_cpu_name_from_uarch: Unable to find CPU name");
cpu_name = ecalloc(strlen(STRING_UNKNOWN) + 1, sizeof(char));
strcpy(cpu_name, STRING_UNKNOWN);
return cpu_name;
}
char *str = NULL;
switch (arch->uarch) {
// Intel
case UARCH_I486:
str = "Intel 486";
break;
case UARCH_P5:
str = "Intel Pentium";
break;
case UARCH_P5_MMX:
str = "Intel Pentium MMX";
break;
case UARCH_P6_PRO:
str = "Intel Pentium Pro";
break;
case UARCH_P6_PENTIUM_II:
str = "Intel Pentium II";
break;
case UARCH_P6_PENTIUM_III:
str = "Intel Pentium III";
break;
// AMD
case UARCH_AM486:
str = "AMD 486";
break;
case UARCH_AM5X86:
str = "AMD 5x86";
break;
case UARCH_SSA5:
str = "AMD 5k86";
break;
default:
printErr("Unable to find name from uarch: %d", arch->uarch);
break;
}
if (str == NULL) {
cpu_name = ecalloc(strlen(STRING_UNKNOWN) + 1, sizeof(char));
strcpy(cpu_name, STRING_UNKNOWN);
}
else {
cpu_name = ecalloc(strlen(str) + 1, sizeof(char));
strcpy(cpu_name, str);
}
return cpu_name;
} }
bool vpus_are_AVX512(struct cpuInfo* cpu) { bool vpus_are_AVX512(struct cpuInfo* cpu) {
return cpu->arch->uarch != UARCH_ICE_LAKE; // Zen5 actually has 2 x AVX512 units
// https://www.anandtech.com/show/21469/amd-details-ryzen-ai-300-series-for-mobile-strix-point-with-rdna-35-igpu-xdna-2-npu
return cpu->arch->uarch != UARCH_ICE_LAKE &&
cpu->arch->uarch != UARCH_TIGER_LAKE &&
cpu->arch->uarch != UARCH_ZEN4 &&
cpu->arch->uarch != UARCH_ZEN4C;
} }
bool is_knights_landing(struct cpuInfo* cpu) { bool is_knights_landing(struct cpuInfo* cpu) {
@@ -382,17 +585,25 @@ int get_number_of_vpus(struct cpuInfo* cpu) {
case UARCH_ROCKET_LAKE: case UARCH_ROCKET_LAKE:
case UARCH_AMBER_LAKE: case UARCH_AMBER_LAKE:
case UARCH_WHISKEY_LAKE: case UARCH_WHISKEY_LAKE:
case UARCH_COFFE_LAKE: case UARCH_COFFEE_LAKE:
case UARCH_PALM_COVE: case UARCH_PALM_COVE:
case UARCH_KNIGHTS_LANDING: case UARCH_KNIGHTS_LANDING:
case UARCH_KNIGHTS_MILL: case UARCH_KNIGHTS_MILL:
case UARCH_ICE_LAKE: case UARCH_ICE_LAKE:
case UARCH_TIGER_LAKE:
case UARCH_ALDER_LAKE:
case UARCH_RAPTOR_LAKE:
// AMD // AMD
case UARCH_ZEN2: case UARCH_ZEN2:
case UARCH_ZEN3: case UARCH_ZEN3:
case UARCH_ZEN3_PLUS:
case UARCH_ZEN4:
case UARCH_ZEN4C:
case UARCH_ZEN5:
case UARCH_ZEN5C:
return 2; return 2;
default: default:
return 1; return 1;
@@ -401,8 +612,10 @@ int get_number_of_vpus(struct cpuInfo* cpu) {
bool choose_new_intel_logo_uarch(struct cpuInfo* cpu) { bool choose_new_intel_logo_uarch(struct cpuInfo* cpu) {
switch(cpu->arch->uarch) { switch(cpu->arch->uarch) {
case UARCH_ALDER_LAKE:
case UARCH_ROCKET_LAKE: case UARCH_ROCKET_LAKE:
// TODO: case UARCH_TIGER_LAKE: missing? case UARCH_TIGER_LAKE:
case UARCH_RAPTOR_LAKE:
return true; return true;
default: default:
return false; return false;
@@ -420,9 +633,6 @@ char* get_str_process(struct cpuInfo* cpu) {
if(process == UNK) { if(process == UNK) {
snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN); snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
} }
else if(process > 100) {
sprintf(str, "%.2fum", (double)process/100);
}
else if(process > 0){ else if(process > 0){
sprintf(str, "%dnm", process); sprintf(str, "%dnm", process);
} }

View File

@@ -7,7 +7,8 @@
struct uarch; struct uarch;
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s); struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t dump, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s);
char* infer_cpu_name_from_uarch(struct uarch* arch);
bool vpus_are_AVX512(struct cpuInfo* cpu); bool vpus_are_AVX512(struct cpuInfo* cpu);
bool is_knights_landing(struct cpuInfo* cpu); bool is_knights_landing(struct cpuInfo* cpu);
int get_number_of_vpus(struct cpuInfo* cpu); int get_number_of_vpus(struct cpuInfo* cpu);