mirror of
https://github.com/Dr-Noob/cpufetch.git
synced 2026-03-25 07:50:40 +01:00
Compare commits
27 Commits
measure-fr
...
i255
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64ef0d889c | ||
|
|
d297878a51 | ||
|
|
ac308204c7 | ||
|
|
260f9ec3b8 | ||
|
|
79013d0ec9 | ||
|
|
e4227388b9 | ||
|
|
8fca4cb250 | ||
|
|
7c947bdf64 | ||
|
|
1ed3a0f2bf | ||
|
|
0fe6fc3f4d | ||
|
|
96c784026b | ||
|
|
59cd2dd128 | ||
|
|
da1981b97c | ||
|
|
8506c91e00 | ||
|
|
ece28cbdee | ||
|
|
7b46c78249 | ||
|
|
e0095c303d | ||
|
|
65378aaed9 | ||
|
|
946729dd06 | ||
|
|
9212f19de1 | ||
|
|
b019256515 | ||
|
|
d4cadbd807 | ||
|
|
4f081ef1a2 | ||
|
|
1b746bc67d | ||
|
|
dfa2b773d1 | ||
|
|
59efbf4e08 | ||
|
|
29768e841d |
35
Makefile
35
Makefile
@@ -7,23 +7,29 @@ PREFIX ?= /usr
|
||||
|
||||
SRC_COMMON=src/common/
|
||||
|
||||
COMMON_SRC = $(SRC_COMMON)main.c $(SRC_COMMON)cpu.c $(SRC_COMMON)udev.c $(SRC_COMMON)printer.c $(SRC_COMMON)args.c $(SRC_COMMON)global.c $(SRC_COMMON)freq.c
|
||||
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 $(SRC_COMMON)freq.h
|
||||
COMMON_SRC = $(SRC_COMMON)main.c $(SRC_COMMON)cpu.c $(SRC_COMMON)udev.c $(SRC_COMMON)printer.c $(SRC_COMMON)args.c $(SRC_COMMON)global.c
|
||||
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)
|
||||
GIT_VERSION := "$(shell git describe --abbrev=4 --dirty --always --tags)"
|
||||
arch := $(shell uname -m)
|
||||
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/
|
||||
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 $(SRC_DIR)freq/freq.h
|
||||
|
||||
os := $(shell uname -s)
|
||||
ifeq ($(os), Linux)
|
||||
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
|
||||
endif
|
||||
CFLAGS += -DARCH_X86 -std=c99 -fstack-protector-all
|
||||
else ifeq ($(arch), $(filter $(arch), ppc64le ppc64 ppcle ppc))
|
||||
SRC_DIR=src/ppc/
|
||||
@@ -32,20 +38,19 @@ ifneq ($(OS),Windows_NT)
|
||||
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))
|
||||
SRC_DIR=src/arm/
|
||||
SOURCE += $(COMMON_SRC) $(SRC_DIR)midr.c $(SRC_DIR)uarch.c $(SRC_COMMON)soc.c $(SRC_DIR)soc.c $(SRC_DIR)udev.c
|
||||
HEADERS += $(COMMON_HDR) $(SRC_DIR)midr.h $(SRC_DIR)uarch.h $(SRC_COMMON)soc.h $(SRC_DIR)soc.h $(SRC_DIR)udev.c $(SRC_DIR)socs.h
|
||||
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
|
||||
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
|
||||
|
||||
os := $(shell uname -s)
|
||||
ifeq ($(os), Darwin)
|
||||
SOURCE += $(SRC_DIR)sysctl.c
|
||||
HEADERS += $(SRC_DIR)sysctl.h
|
||||
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 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
|
||||
# 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)
|
||||
|
||||
@@ -175,6 +175,7 @@ Thanks to the fellow contributors and interested people in the project. Special
|
||||
- [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)
|
||||
See [gpufetch](https://github.com/Dr-Noob/gpufetch) project!
|
||||
|
||||
@@ -8,13 +8,14 @@
|
||||
#ifdef __linux__
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#include "../common/freq.h"
|
||||
#elif defined __APPLE__ || __MACH__
|
||||
#include "sysctl.h"
|
||||
#include "../common/sysctl.h"
|
||||
#endif
|
||||
|
||||
#include "../common/global.h"
|
||||
#include "../common/soc.h"
|
||||
#include "../common/freq.h"
|
||||
#include "../common/args.h"
|
||||
#include "udev.h"
|
||||
#include "midr.h"
|
||||
#include "uarch.h"
|
||||
@@ -40,12 +41,15 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
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);
|
||||
#ifdef __linux__
|
||||
if (freq->max == UNKNOWN_DATA) {
|
||||
printWarn("Unable to find max frequency from udev, measuring CPU frequency");
|
||||
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
|
||||
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
#include "udev.h"
|
||||
#include "uarch.h"
|
||||
#include "../common/global.h"
|
||||
#include "../common/pci.h"
|
||||
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
#include "sysctl.h"
|
||||
#include "../common/sysctl.h"
|
||||
#endif
|
||||
|
||||
#define NA -1
|
||||
@@ -577,6 +578,14 @@ bool match_qualcomm(char* soc_name, struct system_on_chip* soc) {
|
||||
SOC_EQ(tmp, "SM8250-AB", "865+", SOC_SNAPD_SM8250_AB, soc, 7)
|
||||
SOC_EQ(tmp, "SM8350", "888", SOC_SNAPD_SM8350, soc, 5)
|
||||
SOC_EQ(tmp, "SM8350-AC", "888+", SOC_SNAPD_SM8350, soc, 5)
|
||||
// Snapdragon Gen //
|
||||
SOC_EQ(tmp, "SM4450", "4 Gen 2", SOC_SNAPD_SM4450, soc, 4)
|
||||
SOC_EQ(tmp, "SM6450", "6 Gen 1", SOC_SNAPD_SM6450, soc, 4)
|
||||
SOC_EQ(tmp, "SM7435-AB", "7s Gen 2", SOC_SNAPD_SM7435_AB, soc, 4)
|
||||
SOC_EQ(tmp, "SM7450", "7 Gen 1", SOC_SNAPD_SM7450, soc, 4)
|
||||
SOC_EQ(tmp, "SM7475", "7+ Gen 2", SOC_SNAPD_SM7475, soc, 4)
|
||||
SOC_EQ(tmp, "SM8450", "8 Gen 1", SOC_SNAPD_SM8450, soc, 4)
|
||||
SOC_EQ(tmp, "SM8475", "8+ Gen 1", SOC_SNAPD_SM8475, soc, 4)
|
||||
SOC_END
|
||||
}
|
||||
|
||||
@@ -623,12 +632,37 @@ bool match_special(char* soc_name, struct system_on_chip* soc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Snapdragon 8 Gen 1 reported as "taro"
|
||||
// New Snapdragon SoCs codenames
|
||||
// https://github.com/sm8450-mainline/fdt?tab=readme-ov-file#chipsets
|
||||
// https://github.com/Dr-Noob/cpufetch/issues/253
|
||||
if (strcmp(soc_name, "cape") == 0) {
|
||||
fill_soc(soc, "8+ Gen 1", SOC_SNAPD_SM8475, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(strcmp(soc_name, "taro") == 0) {
|
||||
fill_soc(soc, "8 Gen 1", SOC_SNAPD_SM8450, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(strcmp(soc_name, "ukee") == 0) {
|
||||
fill_soc(soc, "7+ Gen 2", SOC_SNAPD_SM7475, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(strcmp(soc_name, "diwali") == 0) {
|
||||
fill_soc(soc, "7 Gen 1", SOC_SNAPD_SM7450, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
// parrot can be either SM7435 or SM6450, we need more data
|
||||
// to distingish between those two
|
||||
|
||||
if(strcmp(soc_name, "ravelin") == 0) {
|
||||
fill_soc(soc, "4 Gen 2", SOC_SNAPD_SM4450, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Google Pixel 6
|
||||
// https://github.com/Dr-Noob/cpufetch/issues/134
|
||||
if(strcmp(soc_name, "oriole") == 0) {
|
||||
@@ -701,6 +735,16 @@ struct system_on_chip* guess_soc_from_android(struct system_on_chip* soc) {
|
||||
else return soc;
|
||||
}
|
||||
|
||||
// https://github.com/Dr-Noob/cpufetch/issues/253
|
||||
// ro.soc.model might be more reliable than ro.product.board or
|
||||
// ro.board.platform, so try with it first
|
||||
property_len = android_property_get("ro.soc.model", (char *) &tmp);
|
||||
if(property_len > 0) {
|
||||
try_parse_soc_from_string(soc, property_len, tmp);
|
||||
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) printWarn("SoC detection failed using Android property ro.soc.model: %s", tmp);
|
||||
else return soc;
|
||||
}
|
||||
|
||||
property_len = android_property_get("ro.product.board", (char *) &tmp);
|
||||
if(property_len > 0) {
|
||||
try_parse_soc_from_string(soc, property_len, tmp);
|
||||
@@ -834,6 +878,43 @@ struct system_on_chip* guess_soc_from_uarch(struct system_on_chip* soc, struct c
|
||||
return soc;
|
||||
}
|
||||
|
||||
struct system_on_chip* guess_soc_from_pci(struct system_on_chip* soc, struct cpuInfo* cpu) {
|
||||
struct pci_devices * pci = get_pci_devices();
|
||||
if (pci == NULL) {
|
||||
printWarn("guess_soc_from_pci: Unable to find suitable PCI devices");
|
||||
return soc;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
struct system_on_chip soc;
|
||||
} pciToSoC;
|
||||
|
||||
pciToSoC socFromPCI[] = {
|
||||
{PCI_VENDOR_NVIDIA, PCI_DEVICE_TEGRA_X1, {SOC_TEGRA_X1, SOC_VENDOR_NVIDIA, 20, "Tegra X1", NULL} },
|
||||
// {PCI_VENDOR_NVIDIA, PCI_DEVICE_GH_200,{SOC_GH_200, SOC_VENDOR_NVIDIA, ?, "Grace Hopper", NULL} },
|
||||
{0x0000, 0x0000, {UNKNOWN, SOC_VENDOR_UNKNOWN, -1, "", NULL} }
|
||||
};
|
||||
|
||||
int index = 0;
|
||||
while (socFromPCI[index].vendor_id != 0x0) {
|
||||
for (int i=0; i < pci->num_devices; i++) {
|
||||
struct pci_device * dev = pci->devices[i];
|
||||
|
||||
if (socFromPCI[index].vendor_id == dev->vendor_id &&
|
||||
socFromPCI[index].device_id == dev->device_id) {
|
||||
fill_soc(soc, socFromPCI[index].soc.soc_name, socFromPCI[index].soc.soc_model, socFromPCI[index].soc.process);
|
||||
return soc;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
printWarn("guess_soc_from_pci: No PCI device matched the list");
|
||||
return soc;
|
||||
}
|
||||
|
||||
int hex2int(char c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
@@ -1004,14 +1085,18 @@ struct system_on_chip* get_soc(struct cpuInfo* cpu) {
|
||||
printWarn("SoC detection failed using Android: Found '%s' string", soc->raw_name);
|
||||
}
|
||||
#endif // ifdef __ANDROID__
|
||||
// If cpufinfo/Android (if available) detection fails, try with nvmem
|
||||
// If previous steps failed, try with nvmem
|
||||
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) {
|
||||
soc = guess_soc_from_nvmem(soc);
|
||||
}
|
||||
// If everything else failed, try infering it from the microarchitecture
|
||||
// If previous steps failed, try infering it from the microarchitecture
|
||||
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) {
|
||||
soc = guess_soc_from_uarch(soc, cpu);
|
||||
}
|
||||
// If previous steps failed, try infering it from the pci device id
|
||||
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) {
|
||||
soc = guess_soc_from_pci(soc, cpu);
|
||||
}
|
||||
}
|
||||
#elif defined __APPLE__ || __MACH__
|
||||
soc = guess_soc_apple(soc);
|
||||
|
||||
@@ -270,11 +270,13 @@ enum {
|
||||
SOC_SNAPD_SDM660,
|
||||
SOC_SNAPD_SM6115,
|
||||
SOC_SNAPD_SM6125,
|
||||
SOC_SNAPD_SM6450,
|
||||
SOC_SNAPD_SDM670,
|
||||
SOC_SNAPD_SM6150,
|
||||
SOC_SNAPD_SM6350,
|
||||
SOC_SNAPD_SDM710,
|
||||
SOC_SNAPD_SDM712,
|
||||
SOC_SNAPD_SM4450,
|
||||
SOC_SNAPD_SM7125,
|
||||
SOC_SNAPD_SM7150_AA,
|
||||
SOC_SNAPD_SM7150_AB,
|
||||
@@ -283,6 +285,9 @@ enum {
|
||||
SOC_SNAPD_SM7250_AA,
|
||||
SOC_SNAPD_SM7250_AB,
|
||||
SOC_SNAPD_SM7250_AC,
|
||||
SOC_SNAPD_SM7435_AB,
|
||||
SOC_SNAPD_SM7450,
|
||||
SOC_SNAPD_SM7475,
|
||||
SOC_SNAPD_MSM8974AA,
|
||||
SOC_SNAPD_MSM8974AB,
|
||||
SOC_SNAPD_MSM8974AC,
|
||||
@@ -303,6 +308,7 @@ enum {
|
||||
SOC_SNAPD_SM8250_AB,
|
||||
SOC_SNAPD_SM8350,
|
||||
SOC_SNAPD_SM8450,
|
||||
SOC_SNAPD_SM8475,
|
||||
// APPLE
|
||||
SOC_APPLE_M1,
|
||||
SOC_APPLE_M1_PRO,
|
||||
@@ -363,6 +369,8 @@ enum {
|
||||
SOC_GOOGLE_TENSOR,
|
||||
SOC_GOOGLE_TENSOR_G2,
|
||||
SOC_GOOGLE_TENSOR_G3,
|
||||
// NVIDIA,
|
||||
SOC_TEGRA_X1,
|
||||
// UNKNOWN
|
||||
SOC_MODEL_UNKNOWN
|
||||
};
|
||||
@@ -373,11 +381,12 @@ inline static VENDOR get_soc_vendor_from_soc(SOC soc) {
|
||||
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_MTK_MT6893 && soc <= SOC_MTK_MT8783) return SOC_VENDOR_MEDIATEK;
|
||||
else if(soc >= SOC_SNAPD_QSD8650 && soc <= SOC_SNAPD_SM8450) return SOC_VENDOR_SNAPDRAGON;
|
||||
else if(soc >= SOC_SNAPD_QSD8650 && soc <= SOC_SNAPD_SM8475) return SOC_VENDOR_SNAPDRAGON;
|
||||
else if(soc >= SOC_APPLE_M1 && soc <= SOC_APPLE_M3_MAX) return SOC_VENDOR_APPLE;
|
||||
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;
|
||||
return SOC_VENDOR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
@@ -324,6 +324,8 @@ int get_number_of_vpus(struct cpuInfo* cpu) {
|
||||
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_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]
|
||||
|
||||
@@ -28,6 +28,7 @@ struct args_struct {
|
||||
bool help_flag;
|
||||
bool raw_flag;
|
||||
bool accurate_pp;
|
||||
bool measure_max_frequency_flag;
|
||||
bool full_cpu_name_flag;
|
||||
bool logo_long;
|
||||
bool logo_short;
|
||||
@@ -40,35 +41,37 @@ struct args_struct {
|
||||
};
|
||||
|
||||
const char args_chr[] = {
|
||||
/* [ARG_STYLE] = */ 's',
|
||||
/* [ARG_COLOR] = */ 'c',
|
||||
/* [ARG_HELP] = */ 'h',
|
||||
/* [ARG_RAW] = */ 'r',
|
||||
/* [ARG_FULLCPUNAME] = */ 'F',
|
||||
/* [ARG_LOGO_LONG] = */ 1,
|
||||
/* [ARG_LOGO_SHORT] = */ 2,
|
||||
/* [ARG_LOGO_INTEL_NEW] = */ 3,
|
||||
/* [ARG_LOGO_INTEL_OLD] = */ 4,
|
||||
/* [ARG_ACCURATE_PP] = */ 5,
|
||||
/* [ARG_DEBUG] = */ 'd',
|
||||
/* [ARG_VERBOSE] = */ 'v',
|
||||
/* [ARG_VERSION] = */ 'V',
|
||||
/* [ARG_STYLE] = */ 's',
|
||||
/* [ARG_COLOR] = */ 'c',
|
||||
/* [ARG_HELP] = */ 'h',
|
||||
/* [ARG_RAW] = */ 'r',
|
||||
/* [ARG_FULLCPUNAME] = */ 'F',
|
||||
/* [ARG_LOGO_LONG] = */ 1,
|
||||
/* [ARG_LOGO_SHORT] = */ 2,
|
||||
/* [ARG_LOGO_INTEL_NEW] = */ 3,
|
||||
/* [ARG_LOGO_INTEL_OLD] = */ 4,
|
||||
/* [ARG_ACCURATE_PP] = */ 5,
|
||||
/* [ARG_MEASURE_MAX_FREQ] = */ 6,
|
||||
/* [ARG_DEBUG] = */ 'd',
|
||||
/* [ARG_VERBOSE] = */ 'v',
|
||||
/* [ARG_VERSION] = */ 'V',
|
||||
};
|
||||
|
||||
const char *args_str[] = {
|
||||
/* [ARG_STYLE] = */ "style",
|
||||
/* [ARG_COLOR] = */ "color",
|
||||
/* [ARG_HELP] = */ "help",
|
||||
/* [ARG_RAW] = */ "raw",
|
||||
/* [ARG_FULLCPUNAME] = */ "full-cpu-name",
|
||||
/* [ARG_LOGO_LONG] = */ "logo-long",
|
||||
/* [ARG_LOGO_SHORT] = */ "logo-short",
|
||||
/* [ARG_LOGO_INTEL_NEW] = */ "logo-intel-new",
|
||||
/* [ARG_LOGO_INTEL_OLD] = */ "logo-intel-old",
|
||||
/* [ARG_ACCURATE_PP] = */ "accurate-pp",
|
||||
/* [ARG_DEBUG] = */ "debug",
|
||||
/* [ARG_VERBOSE] = */ "verbose",
|
||||
/* [ARG_VERSION] = */ "version",
|
||||
/* [ARG_STYLE] = */ "style",
|
||||
/* [ARG_COLOR] = */ "color",
|
||||
/* [ARG_HELP] = */ "help",
|
||||
/* [ARG_RAW] = */ "raw",
|
||||
/* [ARG_FULLCPUNAME] = */ "full-cpu-name",
|
||||
/* [ARG_LOGO_LONG] = */ "logo-long",
|
||||
/* [ARG_LOGO_SHORT] = */ "logo-short",
|
||||
/* [ARG_LOGO_INTEL_NEW] = */ "logo-intel-new",
|
||||
/* [ARG_LOGO_INTEL_OLD] = */ "logo-intel-old",
|
||||
/* [ARG_ACCURATE_PP] = */ "accurate-pp",
|
||||
/* [ARG_MEASURE_MAX_FREQ] = */ "measure-max-freq",
|
||||
/* [ARG_DEBUG] = */ "debug",
|
||||
/* [ARG_VERBOSE] = */ "verbose",
|
||||
/* [ARG_VERSION] = */ "version",
|
||||
};
|
||||
|
||||
static struct args_struct args;
|
||||
@@ -101,6 +104,10 @@ 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;
|
||||
}
|
||||
@@ -222,12 +229,20 @@ char* build_short_options(void) {
|
||||
memset(str, 0, sizeof(char) * (len*2 + 1));
|
||||
|
||||
#ifdef ARCH_X86
|
||||
sprintf(str, "%c:%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_RAW], c[ARG_FULLCPUNAME],
|
||||
c[ARG_LOGO_SHORT], c[ARG_LOGO_LONG],
|
||||
c[ARG_LOGO_INTEL_NEW], c[ARG_LOGO_INTEL_OLD],
|
||||
c[ARG_ACCURATE_PP], c[ARG_DEBUG], c[ARG_VERBOSE],
|
||||
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
|
||||
sprintf(str, "%c:%c:%c%c%c%c%c%c",
|
||||
@@ -263,21 +278,24 @@ bool parse_args(int argc, char* argv[]) {
|
||||
set_log_level(true);
|
||||
|
||||
const struct option long_options[] = {
|
||||
{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_HELP], no_argument, 0, args_chr[ARG_HELP] },
|
||||
{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_HELP], no_argument, 0, args_chr[ARG_HELP] },
|
||||
#ifdef ARCH_X86
|
||||
{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_ACCURATE_PP], no_argument, 0, args_chr[ARG_ACCURATE_PP] },
|
||||
{args_str[ARG_FULLCPUNAME], no_argument, 0, args_chr[ARG_FULLCPUNAME] },
|
||||
{args_str[ARG_RAW], no_argument, 0, args_chr[ARG_RAW] },
|
||||
{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_ACCURATE_PP], no_argument, 0, args_chr[ARG_ACCURATE_PP] },
|
||||
{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
|
||||
{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_DEBUG], no_argument, 0, args_chr[ARG_DEBUG] },
|
||||
{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_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_DEBUG], no_argument, 0, args_chr[ARG_DEBUG] },
|
||||
{args_str[ARG_VERBOSE], no_argument, 0, args_chr[ARG_VERBOSE] },
|
||||
{args_str[ARG_VERSION], no_argument, 0, args_chr[ARG_VERSION] },
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -313,6 +331,9 @@ bool parse_args(int argc, char* argv[]) {
|
||||
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]) {
|
||||
args.full_cpu_name_flag = true;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ enum {
|
||||
ARG_LOGO_INTEL_NEW,
|
||||
ARG_LOGO_INTEL_OLD,
|
||||
ARG_ACCURATE_PP,
|
||||
ARG_MEASURE_MAX_FREQ,
|
||||
ARG_DEBUG,
|
||||
ARG_VERBOSE,
|
||||
ARG_VERSION
|
||||
@@ -43,6 +44,7 @@ int max_arg_str_length(void);
|
||||
bool parse_args(int argc, char* argv[]);
|
||||
bool show_help(void);
|
||||
bool accurate_pp(void);
|
||||
bool measure_max_frequency_flag(void);
|
||||
bool show_full_cpu_name(void);
|
||||
bool show_logo_long(void);
|
||||
bool show_logo_short(void);
|
||||
|
||||
@@ -105,6 +105,19 @@ $C1 MMM :MMM NMM dMMK dMMX MMN \
|
||||
$C1 MMM :MMM NMM dMMMoo OMM0....:Nx. 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 \
|
||||
" $C1@@$C2######## \
|
||||
$C1@@@@@$C2########### \
|
||||
@@ -360,6 +373,27 @@ $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## ## ### ## ###### ## ## ## "
|
||||
|
||||
// --------------------- LONG LOGOS ------------------------- //
|
||||
#define ASCII_AMD_L \
|
||||
"$C1 \
|
||||
@@ -492,6 +526,23 @@ $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;
|
||||
|
||||
// +-----------------------------------------------------------------------------------------------------------------+
|
||||
@@ -500,6 +551,7 @@ typedef struct ascii_logo asciiL;
|
||||
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_new = { ASCII_INTEL_NEW, 51, 9, false, {C_FG_CYAN}, {C_FG_CYAN, C_FG_WHITE} };
|
||||
asciiL logo_hygon = { ASCII_HYGON, 51, 11, false, {C_FG_RED}, {C_FG_RED, 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_mtk = { ASCII_MTK, 59, 5, false, {C_FG_BLUE, C_FG_YELLOW}, {C_FG_BLUE, C_FG_YELLOW} };
|
||||
asciiL logo_exynos = { ASCII_EXYNOS, 22, 13, true, {C_BG_BLUE, C_FG_WHITE}, {C_FG_BLUE, C_FG_WHITE} };
|
||||
@@ -516,6 +568,7 @@ asciiL logo_riscv = { ASCII_RISCV, 63, 18, false, {C_FG_CYAN, C_FG_Y
|
||||
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} };
|
||||
|
||||
// Long variants | ----------------------------------------------------------------------------------------------------------------|
|
||||
asciiL logo_amd_l = { ASCII_AMD_L, 62, 19, true, {C_BG_WHITE, C_BG_GREEN}, {C_FG_WHITE, C_FG_GREEN} };
|
||||
@@ -525,6 +578,7 @@ asciiL logo_arm_l = { ASCII_ARM_L, 60, 8, true, {C_BG_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
|
||||
|
||||
@@ -145,17 +145,25 @@ char* get_str_l3(struct cache* cach) {
|
||||
|
||||
char* get_str_freq(struct frequency* freq) {
|
||||
//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);
|
||||
char* string = emalloc(sizeof(char)*size);
|
||||
memset(string, 0, sizeof(char)*size);
|
||||
char* string = ecalloc(size, sizeof(char));
|
||||
|
||||
if(freq->max == UNKNOWN_DATA || freq->max < 0)
|
||||
if(freq->max == UNKNOWN_DATA || freq->max < 0) {
|
||||
snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN);
|
||||
else if(freq->max >= 1000)
|
||||
snprintf(string,size,"%.3f "STRING_GIGAHERZ,(float)(freq->max)/1000);
|
||||
else
|
||||
snprintf(string,size,"%d "STRING_MEGAHERZ,freq->max);
|
||||
}
|
||||
else if(freq->max >= 1000) {
|
||||
if (freq->measured)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ enum {
|
||||
// ARCH_X86
|
||||
CPU_VENDOR_INTEL,
|
||||
CPU_VENDOR_AMD,
|
||||
CPU_VENDOR_HYGON,
|
||||
// ARCH_ARM
|
||||
CPU_VENDOR_ARM,
|
||||
CPU_VENDOR_APPLE,
|
||||
@@ -32,6 +33,7 @@ enum {
|
||||
enum {
|
||||
HV_VENDOR_KVM,
|
||||
HV_VENDOR_QEMU,
|
||||
HV_VENDOR_VBOX,
|
||||
HV_VENDOR_HYPERV,
|
||||
HV_VENDOR_VMWARE,
|
||||
HV_VENDOR_XEN,
|
||||
@@ -43,8 +45,9 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
CORE_TYPE_EFFICIENCY,
|
||||
CORE_TYPE_PERFORMANCE,
|
||||
CORE_TYPE_EFFICIENCY,
|
||||
CORE_TYPE_LP_EFFICIENCY,
|
||||
CORE_TYPE_UNKNOWN
|
||||
};
|
||||
|
||||
@@ -56,6 +59,8 @@ typedef int32_t VENDOR;
|
||||
struct frequency {
|
||||
int32_t base;
|
||||
int32_t max;
|
||||
// Indicates if max frequency was measured
|
||||
bool measured;
|
||||
};
|
||||
|
||||
struct hypervisor {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#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,
|
||||
@@ -69,28 +70,15 @@ void nop_function(uint64_t iters) {
|
||||
}
|
||||
}
|
||||
|
||||
// Differences between x86 measure_frequency this measure_max_frequency:
|
||||
// - measure_frequency employs all cores simultaneously wherease
|
||||
// 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 -1;
|
||||
}
|
||||
|
||||
// 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 instructions;
|
||||
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);
|
||||
@@ -103,18 +91,12 @@ int64_t measure_max_frequency(uint32_t core) {
|
||||
if (fd == -1) {
|
||||
perror("perf_event_open");
|
||||
if (errno == EPERM || errno == EACCES) {
|
||||
printf("You may not have permission to collect stats.\n");
|
||||
printf("Consider tweaking /proc/sys/kernel/perf_event_paranoid or running as root.\n");
|
||||
printErr("You may not have permission to collect stats.\n"\
|
||||
"Consider tweaking /proc/sys/kernel/perf_event_paranoid or running as root");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* frequency_banner = "cpufetch is measuring the max frequency...";
|
||||
printf("%s", frequency_banner);
|
||||
fflush(stdout);
|
||||
|
||||
uint64_t iters = 10000000;
|
||||
struct timespec start, end;
|
||||
if (clock_gettime(clock, &start) == -1) {
|
||||
perror("clock_gettime");
|
||||
return -1;
|
||||
@@ -130,7 +112,15 @@ int64_t measure_max_frequency(uint32_t core) {
|
||||
|
||||
nop_function(iters);
|
||||
|
||||
read(fd, &instructions, sizeof(uint64_t));
|
||||
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;
|
||||
@@ -142,8 +132,59 @@ int64_t measure_max_frequency(uint32_t core) {
|
||||
|
||||
uint64_t nsecs = (end.tv_sec*1e9 + end.tv_nsec) - (start.tv_sec*1e9 + start.tv_nsec);
|
||||
uint64_t usecs = nsecs/1000;
|
||||
double frequency = instructions/((double)usecs);
|
||||
*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
|
||||
|
||||
@@ -30,11 +30,17 @@ void print_help(char *argv[]) {
|
||||
#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])), "");
|
||||
#endif
|
||||
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 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 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
|
||||
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])), "");
|
||||
@@ -45,7 +51,7 @@ void print_help(char *argv[]) {
|
||||
printf(" * \"amd\": Use AMD color scheme \n");
|
||||
printf(" * \"ibm\", Use IBM color scheme \n");
|
||||
printf(" * \"arm\": Use ARM color scheme \n");
|
||||
printf(" * \"rockchip\": 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(" 5 colors must be given in RGB with the format: R,G,B:R,G,B:...\n");
|
||||
@@ -80,6 +86,11 @@ void print_help(char *argv[]) {
|
||||
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");
|
||||
printf("\n");
|
||||
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[]) {
|
||||
|
||||
178
src/common/pci.c
Normal file
178
src/common/pci.c
Normal file
@@ -0,0 +1,178 @@
|
||||
#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
|
||||
|
||||
/*
|
||||
* doc: https://wiki.osdev.org/PCI#Class_Codes
|
||||
* https://pci-ids.ucw.cz/read/PC
|
||||
*/
|
||||
#define PCI_VENDOR_ID_AMD 0x1002
|
||||
#define CLASS_VGA_CONTROLLER 0x0300
|
||||
#define CLASS_3D_CONTROLLER 0x0302
|
||||
|
||||
// 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(sizeof(char), strLen);
|
||||
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")));
|
||||
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")));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Right now, we are interested in PCI devices which
|
||||
// vendor is NVIDIA (to be extended in the future).
|
||||
// Should we also restrict to VGA controllers only?
|
||||
bool pci_device_is_useful(struct pci_device* dev) {
|
||||
return dev->vendor_id == PCI_VENDOR_NVIDIA;
|
||||
}
|
||||
|
||||
// Filter the input list in order to get only those PCI devices which
|
||||
// we are interested in (decided by pci_device_is_useful)
|
||||
// and return the filtered result.
|
||||
struct pci_devices * filter_pci_devices(struct pci_devices * pci) {
|
||||
int * devices_to_get = emalloc(sizeof(int) * pci->num_devices);
|
||||
int dev_ptr = 0;
|
||||
|
||||
for (int i=0; i < pci->num_devices; i++) {
|
||||
if (pci_device_is_useful(pci->devices[i])) {
|
||||
devices_to_get[dev_ptr] = i;
|
||||
dev_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
struct pci_devices * pci_filtered = emalloc(sizeof(struct pci_devices));
|
||||
pci_filtered->num_devices = dev_ptr;
|
||||
|
||||
if (pci_filtered->num_devices == 0) {
|
||||
pci_filtered->devices = NULL;
|
||||
}
|
||||
else {
|
||||
pci_filtered->devices = emalloc(sizeof(struct pci_device) * pci_filtered->num_devices);
|
||||
|
||||
for (int i=0; i < pci_filtered->num_devices; i++)
|
||||
pci_filtered->devices[i] = pci->devices[devices_to_get[i]];
|
||||
}
|
||||
|
||||
return pci_filtered;
|
||||
}
|
||||
|
||||
// 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 filter_pci_devices(pci);
|
||||
}
|
||||
20
src/common/pci.h
Normal file
20
src/common/pci.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef __PCI__
|
||||
#define __PCI__
|
||||
|
||||
#define PCI_VENDOR_NVIDIA 0x10de
|
||||
#define PCI_DEVICE_TEGRA_X1 0x0faf
|
||||
|
||||
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
|
||||
@@ -360,6 +360,9 @@ void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* ter
|
||||
else if(art->vendor == CPU_VENDOR_AMD) {
|
||||
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 {
|
||||
art->art = &logo_unknown;
|
||||
}
|
||||
@@ -386,6 +389,8 @@ void choose_ascii_art(struct ascii* art, struct color** cs, struct terminal* ter
|
||||
art->art = &logo_allwinner;
|
||||
else if(art->vendor == SOC_VENDOR_ROCKCHIP)
|
||||
art->art = &logo_rockchip;
|
||||
else if(art->vendor == SOC_VENDOR_NVIDIA)
|
||||
art->art = choose_ascii_art_aux(&logo_nvidia_l, &logo_nvidia, term, lf);
|
||||
else {
|
||||
art->art = choose_ascii_art_aux(&logo_arm_l, &logo_arm, term, lf);
|
||||
}
|
||||
@@ -609,8 +614,9 @@ bool print_cpufetch_x86(struct cpuInfo* cpu, STYLE s, struct color** cs, struct
|
||||
}
|
||||
|
||||
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:");
|
||||
if (ptr->core_type == CORE_TYPE_PERFORMANCE) sprintf(cpu_num, "P-cores:");
|
||||
else if (ptr->core_type == CORE_TYPE_EFFICIENCY) sprintf(cpu_num, "E-cores:");
|
||||
else if (ptr->core_type == CORE_TYPE_LP_EFFICIENCY) sprintf(cpu_num, "LP-E-cores:");
|
||||
else printBug("Found invalid core type!\n");
|
||||
|
||||
setAttribute(art, ATTRIBUTE_CPU_NUM, cpu_num);
|
||||
|
||||
@@ -20,6 +20,7 @@ static char* soc_trademark_string[] = {
|
||||
[SOC_VENDOR_APPLE] = "Apple ",
|
||||
[SOC_VENDOR_ROCKCHIP] = "Rockchip ",
|
||||
[SOC_VENDOR_GOOGLE] = "Google ",
|
||||
[SOC_VENDOR_NVIDIA] = "NVIDIA ",
|
||||
// RISC-V
|
||||
[SOC_VENDOR_SIFIVE] = "SiFive ",
|
||||
[SOC_VENDOR_STARFIVE] = "StarFive ",
|
||||
|
||||
@@ -24,6 +24,7 @@ enum {
|
||||
SOC_VENDOR_APPLE,
|
||||
SOC_VENDOR_ROCKCHIP,
|
||||
SOC_VENDOR_GOOGLE,
|
||||
SOC_VENDOR_NVIDIA,
|
||||
// RISC-V
|
||||
SOC_VENDOR_SIFIVE,
|
||||
SOC_VENDOR_STARFIVE,
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../common/global.h"
|
||||
#include "../common/cpu.h"
|
||||
#include "global.h"
|
||||
#include "cpu.h"
|
||||
|
||||
uint32_t get_sys_info_by_name(char* name) {
|
||||
size_t size = 0;
|
||||
@@ -14,6 +14,7 @@
|
||||
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",
|
||||
@@ -145,6 +146,7 @@ struct uarch* get_cpu_uarch(struct cpuInfo* cpu) {
|
||||
struct frequency* get_frequency_info(void) {
|
||||
struct frequency* freq = emalloc(sizeof(struct frequency));
|
||||
|
||||
freq->measured = false;
|
||||
freq->max = get_max_freq_from_file(0);
|
||||
freq->base = get_min_freq_from_file(0);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
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);
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ int get_total_cores_module(int total_cores, int module) {
|
||||
|
||||
while(!end) {
|
||||
if(!bind_to_cpu(i)) {
|
||||
printBug("get_total_cores_module: Cannot bind to core %d", i);
|
||||
return -1;
|
||||
}
|
||||
uint32_t eax = 0x0000001A;
|
||||
@@ -99,6 +100,17 @@ int get_total_cores_module(int total_cores, int module) {
|
||||
uint32_t edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
int32_t core_type = eax >> 24 & 0xFF;
|
||||
|
||||
// Here we artificially create a new core type for
|
||||
// LP-E cores. In case the core has no L3 (on a hybrid)
|
||||
// architecture, then we now it's an LP-E core.
|
||||
eax = 0x4;
|
||||
ebx = 0;
|
||||
ecx = 0x3;
|
||||
edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
core_type += eax == 0;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for(int j=0; j < total_modules && !found; j++) {
|
||||
|
||||
203
src/x86/cpuid.c
203
src/x86/cpuid.c
@@ -26,10 +26,12 @@
|
||||
|
||||
#define CPU_VENDOR_INTEL_STRING "GenuineIntel"
|
||||
#define CPU_VENDOR_AMD_STRING "AuthenticAMD"
|
||||
#define CPU_VENDOR_HYGON_STRING "HygonGenuine"
|
||||
|
||||
static const char *hv_vendors_string[] = {
|
||||
[HV_VENDOR_KVM] = "KVMKVMKVM",
|
||||
[HV_VENDOR_QEMU] = "TCGTCGTCGTCG",
|
||||
[HV_VENDOR_VBOX] = "VBoxVBoxVBox",
|
||||
[HV_VENDOR_HYPERV] = "Microsoft Hv",
|
||||
[HV_VENDOR_VMWARE] = "VMwareVMware",
|
||||
[HV_VENDOR_XEN] = "XenVMMXenVMM",
|
||||
@@ -42,6 +44,7 @@ static const char *hv_vendors_string[] = {
|
||||
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",
|
||||
@@ -134,39 +137,31 @@ bool abbreviate_intel_cpu_name(char** name) {
|
||||
char* new_name_ptr = new_name;
|
||||
char* aux_ptr = NULL;
|
||||
|
||||
// 1. Remove "(R)"
|
||||
// 1. Find "Intel(R)"
|
||||
old_name_ptr = strstr(old_name_ptr, "Intel(R)");
|
||||
if(old_name_ptr == NULL) return false;
|
||||
strcpy(new_name_ptr, "Intel");
|
||||
new_name_ptr += strlen("Intel");
|
||||
old_name_ptr += strlen("Intel(R)");
|
||||
|
||||
// 2. Remove "(R)" or "(TM)"
|
||||
aux_ptr = strstr(old_name_ptr, "(");
|
||||
if(aux_ptr == NULL) return false;
|
||||
strncpy(new_name_ptr, old_name_ptr, aux_ptr-old_name_ptr);
|
||||
|
||||
new_name_ptr += aux_ptr-old_name_ptr;
|
||||
strcpy(new_name_ptr, " ");
|
||||
new_name_ptr++;
|
||||
old_name_ptr = strstr(aux_ptr, ")");
|
||||
if(old_name_ptr == NULL) return false;
|
||||
old_name_ptr++;
|
||||
while(*old_name_ptr == ' ') old_name_ptr++;
|
||||
|
||||
// 3. Copy the CPU name
|
||||
// 2. Search for "@"
|
||||
aux_ptr = strstr(old_name_ptr, "@");
|
||||
if(aux_ptr == NULL) return false;
|
||||
strncpy(new_name_ptr, old_name_ptr, (aux_ptr-1)-old_name_ptr);
|
||||
if(aux_ptr == NULL) {
|
||||
// New CPUs, copy end ptr is end of string
|
||||
aux_ptr = old_name + strlen(old_name);
|
||||
strncpy(new_name_ptr, old_name_ptr, (aux_ptr)-old_name_ptr);
|
||||
}
|
||||
else {
|
||||
// Copy end ptr is "@"
|
||||
strncpy(new_name_ptr, old_name_ptr, (aux_ptr-1)-old_name_ptr);
|
||||
}
|
||||
|
||||
// 4. Remove dummy strings in Intel CPU names
|
||||
// 3. Remove dummy strings in Intel CPU names
|
||||
strremove(new_name, "(R)");
|
||||
strremove(new_name, "(TM)");
|
||||
strremove(new_name, " CPU");
|
||||
strremove(new_name, " Dual");
|
||||
strremove(new_name, " 0");
|
||||
|
||||
free(old_name);
|
||||
*name = new_name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -394,6 +389,17 @@ bool set_cpu_module(int m, int total_modules, int32_t* first_core) {
|
||||
uint32_t edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
int32_t core_type = eax >> 24 & 0xFF;
|
||||
|
||||
// Here we artificially create a new core type for
|
||||
// LP-E cores. In case the core has no L3 (on a hybrid)
|
||||
// architecture, then we now it's an LP-E core.
|
||||
eax = 0x4;
|
||||
ebx = 0;
|
||||
ecx = 0x3;
|
||||
edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
core_type += eax == 0;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for(int j=0; j < total_modules && !found; j++) {
|
||||
@@ -420,13 +426,19 @@ bool set_cpu_module(int m, int total_modules, int32_t* first_core) {
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// This is a normal architecture
|
||||
// This is a non-hybrid architecture
|
||||
*first_core = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Difference between E and LP-E cores:
|
||||
// According to Intel Core Ultra Processor Datasheet Volume 1 of 2
|
||||
// (https://www.intel.com/content/www/us/en/content-details/792044/intel-core-ultra-processor-datasheet-volume-1-of-2.html),
|
||||
// LP-E cores do not have L3 cache. This seems to be the only way of differentiating them.
|
||||
// - https://community.intel.com/t5/Processors/Detecting-LP-E-Cores-on-Meteor-Lake-in-software/m-p/1584555/highlight/true#M70732
|
||||
// - https://x.com/InstLatX64/status/1741416428538941718
|
||||
int32_t get_core_type(void) {
|
||||
uint32_t eax = 0x0000001A;
|
||||
uint32_t ebx = 0;
|
||||
@@ -437,8 +449,26 @@ int32_t get_core_type(void) {
|
||||
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;
|
||||
if (type == 0x40) return CORE_TYPE_PERFORMANCE;
|
||||
else if (type == 0x20) {
|
||||
// get_core_type is only called iff hybrid_flag is true, which can only
|
||||
// happen if CPUID maxLevel >= 0x7 so we can assume the CPU supports
|
||||
// CPUID leaf 0x4
|
||||
eax = 0x4;
|
||||
ebx = 0;
|
||||
ecx = 0x3;
|
||||
edx = 0;
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
if (eax == 0) {
|
||||
// No L3 access, this is LP-E
|
||||
return CORE_TYPE_LP_EFFICIENCY;
|
||||
}
|
||||
else {
|
||||
return CORE_TYPE_EFFICIENCY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printErr("Found invalid core type: 0x%.8X\n", type);
|
||||
return CORE_TYPE_UNKNOWN;
|
||||
@@ -453,7 +483,6 @@ struct cpuInfo* get_cpu_info(void) {
|
||||
cpu->cach = NULL;
|
||||
cpu->feat = NULL;
|
||||
|
||||
cpu->num_cpus = 1;
|
||||
uint32_t eax = 0;
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
@@ -472,6 +501,8 @@ struct cpuInfo* get_cpu_info(void) {
|
||||
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);
|
||||
@@ -509,7 +540,13 @@ struct cpuInfo* get_cpu_info(void) {
|
||||
cpu->hybrid_flag = (edx >> 15) & 0x1;
|
||||
}
|
||||
|
||||
if(cpu->hybrid_flag) cpu->num_cpus = 2;
|
||||
if(cpu->hybrid_flag) {
|
||||
struct uarch* tmp = get_cpu_uarch(cpu);
|
||||
cpu->num_cpus = get_hybrid_num_cpus(tmp);
|
||||
}
|
||||
else {
|
||||
cpu->num_cpus = 1;
|
||||
}
|
||||
|
||||
struct cpuInfo* ptr = cpu;
|
||||
for(uint32_t i=0; i < cpu->num_cpus; i++) {
|
||||
@@ -524,8 +561,9 @@ struct cpuInfo* get_cpu_info(void) {
|
||||
ptr->topo = NULL;
|
||||
ptr->cach = NULL;
|
||||
ptr->feat = NULL;
|
||||
// We assume that this cores have the
|
||||
// same cpuid capabilities
|
||||
// We assume that this core has the
|
||||
// same cpuid capabilities as the core in the
|
||||
// first module
|
||||
ptr->cpu_vendor = cpu->cpu_vendor;
|
||||
ptr->maxLevels = cpu->maxLevels;
|
||||
ptr->maxExtendedLevels = cpu->maxExtendedLevels;
|
||||
@@ -651,10 +689,15 @@ bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
|
||||
void get_topology_from_udev(struct topology* topo) {
|
||||
topo->total_cores = get_ncores_from_cpuinfo();
|
||||
// TODO: To be improved in the future
|
||||
// Conservative setting as we only know the total
|
||||
// number of cores.
|
||||
topo->logical_cores = UNKNOWN_DATA;
|
||||
topo->physical_cores = UNKNOWN_DATA;
|
||||
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;
|
||||
@@ -690,6 +733,8 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, int
|
||||
if(cpu->hybrid_flag) {
|
||||
#ifdef __linux__
|
||||
topo->total_cores_module = get_total_cores_module(topo->total_cores, module);
|
||||
printBug("get_total_cores_module: Failed to get number of cores in module");
|
||||
return NULL;
|
||||
#else
|
||||
UNUSED(module);
|
||||
topo->total_cores_module = topo->total_cores;
|
||||
@@ -701,30 +746,29 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, int
|
||||
|
||||
switch(cpu->cpu_vendor) {
|
||||
case CPU_VENDOR_INTEL:
|
||||
bool toporet = false;
|
||||
if (cpu->maxLevels >= 0x00000004) {
|
||||
bool toporet = get_topology_from_apic(cpu, topo);
|
||||
if(!toporet) {
|
||||
#ifdef __linux__
|
||||
printWarn("Failed to retrieve topology from APIC, using udev...\n");
|
||||
get_topology_from_udev(topo);
|
||||
#else
|
||||
printErr("Failed to retrieve topology from APIC, assumming default values...\n");
|
||||
topo->logical_cores = UNKNOWN_DATA;
|
||||
topo->physical_cores = UNKNOWN_DATA;
|
||||
topo->smt_available = 1;
|
||||
topo->smt_supported = 1;
|
||||
#endif
|
||||
}
|
||||
toporet = get_topology_from_apic(cpu, topo);
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels);
|
||||
topo->physical_cores = UNKNOWN_DATA;
|
||||
topo->logical_cores = UNKNOWN_DATA;
|
||||
topo->smt_available = 1;
|
||||
topo->smt_supported = 1;
|
||||
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000004, cpu->maxLevels);
|
||||
}
|
||||
if(!toporet) {
|
||||
#ifdef __linux__
|
||||
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;
|
||||
case CPU_VENDOR_AMD:
|
||||
case CPU_VENDOR_HYGON:
|
||||
if (cpu->maxExtendedLevels >= 0x80000008) {
|
||||
eax = 0x80000008;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
@@ -921,6 +965,7 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
|
||||
struct frequency* get_frequency_info(struct cpuInfo* cpu) {
|
||||
struct frequency* freq = emalloc(sizeof(struct frequency));
|
||||
freq->measured = false;
|
||||
|
||||
if(cpu->maxLevels < 0x00000016) {
|
||||
#if defined (_WIN32) || defined (__APPLE__)
|
||||
@@ -930,7 +975,7 @@ struct frequency* get_frequency_info(struct cpuInfo* cpu) {
|
||||
#else
|
||||
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_DATA;
|
||||
freq->max = get_max_freq_from_file(0);
|
||||
freq->max = get_max_freq_from_file(cpu->first_core_id);
|
||||
|
||||
if(freq->max == 0) {
|
||||
printWarn("Read max CPU frequency from udev and got 0 MHz");
|
||||
@@ -957,7 +1002,7 @@ struct frequency* get_frequency_info(struct cpuInfo* cpu) {
|
||||
printWarn("Read max CPU frequency from CPUID and got 0 MHz");
|
||||
#ifdef __linux__
|
||||
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) {
|
||||
printWarn("Read max CPU frequency from udev and got 0 MHz");
|
||||
@@ -970,10 +1015,11 @@ struct frequency* get_frequency_info(struct cpuInfo* cpu) {
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (freq->max == UNKNOWN_DATA) {
|
||||
printWarn("All previous methods failed, measuring CPU frequency");
|
||||
// TODO: Support hybrid architectures
|
||||
freq->max = measure_max_frequency(0);
|
||||
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
|
||||
|
||||
@@ -998,24 +1044,33 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc
|
||||
string = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN) + 1));
|
||||
strcpy(string, STRING_UNKNOWN);
|
||||
}
|
||||
else 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 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 {
|
||||
uint32_t max_size = 4+7+1;
|
||||
string = emalloc(sizeof(char) * max_size);
|
||||
snprintf(string, max_size, "%d cores",topo->physical_cores * topo_sockets);
|
||||
char cores_str[6];
|
||||
memset(cores_str, 0, sizeof(char) * 6);
|
||||
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;
|
||||
|
||||
@@ -143,4 +143,4 @@ int64_t measure_frequency(struct cpuInfo* cpu) {
|
||||
|
||||
printf("\r%*c", num_spaces, ' ');
|
||||
return freq_struct->freq;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,5 @@
|
||||
#define LOOP_ITERS 100000000
|
||||
|
||||
int64_t measure_frequency(struct cpuInfo* cpu);
|
||||
void nop_function_x86(uint64_t iters);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -94,6 +94,7 @@ enum {
|
||||
UARCH_TIGER_LAKE,
|
||||
UARCH_ALDER_LAKE,
|
||||
UARCH_RAPTOR_LAKE,
|
||||
UARCH_METEOR_LAKE,
|
||||
// AMD //
|
||||
UARCH_AM486,
|
||||
UARCH_AM5X86,
|
||||
@@ -248,6 +249,7 @@ struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, u
|
||||
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, 10, 10, NA, "Meteor Lake", UARCH_METEOR_LAKE, 7) // instlatx64.atw.hu (Ultra 7 155H)
|
||||
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)
|
||||
@@ -382,6 +384,7 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
|
||||
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)
|
||||
@@ -391,6 +394,25 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
|
||||
return arch;
|
||||
}
|
||||
|
||||
struct uarch* get_uarch_from_cpuid_hygon(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
|
||||
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));
|
||||
@@ -435,8 +457,16 @@ struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t dump, uint32_t
|
||||
}
|
||||
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);
|
||||
}
|
||||
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
|
||||
@@ -508,6 +538,7 @@ int get_number_of_vpus(struct cpuInfo* cpu) {
|
||||
case UARCH_TIGER_LAKE:
|
||||
case UARCH_ALDER_LAKE:
|
||||
case UARCH_RAPTOR_LAKE:
|
||||
case UARCH_METEOR_LAKE:
|
||||
|
||||
// AMD
|
||||
case UARCH_ZEN2:
|
||||
@@ -521,6 +552,11 @@ int get_number_of_vpus(struct cpuInfo* cpu) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get_hybrid_num_cpus(struct uarch* arch) {
|
||||
if (arch->uarch == UARCH_METEOR_LAKE) return 3;
|
||||
else return 2;
|
||||
}
|
||||
|
||||
bool choose_new_intel_logo_uarch(struct cpuInfo* cpu) {
|
||||
switch(cpu->arch->uarch) {
|
||||
case UARCH_ALDER_LAKE:
|
||||
|
||||
@@ -12,6 +12,7 @@ char* infer_cpu_name_from_uarch(struct uarch* arch);
|
||||
bool vpus_are_AVX512(struct cpuInfo* cpu);
|
||||
bool is_knights_landing(struct cpuInfo* cpu);
|
||||
int get_number_of_vpus(struct cpuInfo* cpu);
|
||||
uint32_t get_hybrid_num_cpus(struct uarch* arch);
|
||||
bool choose_new_intel_logo_uarch(struct cpuInfo* cpu);
|
||||
char* get_str_uarch(struct cpuInfo* cpu);
|
||||
char* get_str_process(struct cpuInfo* cpu);
|
||||
|
||||
Reference in New Issue
Block a user