diff --git a/Makefile b/Makefile index 0ee4f8a..283c3de 100644 --- a/Makefile +++ b/Makefile @@ -5,17 +5,20 @@ SANITY_FLAGS=-Wfloat-equal -Wshadow -Wpointer-arith -Wstrict-overflow=5 -Wformat 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 +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) arch := $(shell uname -m) ifeq ($(arch), x86_64) SRC_DIR=src/x86/ - SOURCE += $(SRC_COMMON)main.c $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_COMMON)udev.c $(SRC_DIR)uarch.c $(SRC_COMMON)printer.c $(SRC_COMMON)args.c $(SRC_COMMON)global.c - HEADERS += $(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_COMMON)udev.h $(SRC_DIR)uarch.h $(SRC_COMMON)ascii.h $(SRC_COMMON)printer.h $(SRC_COMMON)args.h $(SRC_COMMON)global.h + 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 CXXFLAGS += -DARCH_X86 else SRC_DIR=src/arm/ - SOURCE += $(SRC_COMMON)main.c $(SRC_DIR)midr.c $(SRC_DIR)uarch.c $(SRC_COMMON)printer.c $(SRC_COMMON)args.c $(SRC_COMMON)global.c - HEADERS += $(SRC_COMMON)ascii.h $(SRC_DIR)uarch.h $(SRC_DIR)midr.h $(SRC_COMMON)printer.h $(SRC_COMMON)args.h $(SRC_COMMON)global.h + SOURCE += $(COMMON_SRC) $(SRC_DIR)midr.c $(SRC_DIR)uarch.c + HEADERS += $(COMMON_HDR) $(SRC_DIR)midr.h $(SRC_DIR)uarch.h CXXFLAGS += -DARCH_ARM -Wno-unused-parameter endif @@ -23,8 +26,8 @@ ifneq ($(OS),Windows_NT) else # Assume x86_64 SRC_DIR=src/x86/ - SOURCE += $(SRC_COMMON)main.c $(SRC_DIR)cpuid.c $(SRC_DIR)apic.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)udev.c $(SRC_DIR)uarch.c $(SRC_COMMON)printer.c $(SRC_COMMON)args.c $(SRC_COMMON)global.c - HEADERS += $(SRC_DIR)cpuid.h $(SRC_DIR)apic.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)udev.h $(SRC_DIR)uarch.h $(SRC_COMMON)ascii.h $(SRC_COMMON)printer.h $(SRC_COMMON)args.h $(SRC_COMMON)global.h + 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 CXXFLAGS += -D_ARCH_X86 SANITY_FLAGS += -Wno-pedantic-ms-format OUTPUT=cpufetch.exe diff --git a/src/arm/midr.c b/src/arm/midr.c index 69aa169..c1e0570 100644 --- a/src/arm/midr.c +++ b/src/arm/midr.c @@ -4,11 +4,15 @@ #include #include +#include "../common/udev.h" #include "midr.h" +#define STRING_UNKNOWN "Unknown" + struct cpuInfo* get_cpu_info() { struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); + cpu->midr = get_midr_from_cpuinfo(0); cpu->cpu_vendor = CPU_VENDOR_UNKNOWN; cpu->cpu_name = malloc(sizeof(char) * CPU_NAME_MAX_LENGTH); strcpy(cpu->cpu_name, "Unknown"); @@ -34,13 +38,13 @@ void init_cache_struct(struct cache* cach) { cach->L1d = malloc(sizeof(struct cach)); cach->L2 = malloc(sizeof(struct cach)); cach->L3 = malloc(sizeof(struct cach)); - + cach->cach_arr = malloc(sizeof(struct cach*) * 4); cach->cach_arr[0] = cach->L1i; cach->cach_arr[1] = cach->L1d; cach->cach_arr[2] = cach->L2; cach->cach_arr[3] = cach->L3; - + cach->max_cache_level = 0; cach->L1i->exists = false; cach->L1d->exists = false; @@ -51,57 +55,72 @@ void init_cache_struct(struct cache* cach) { struct cache* get_cache_info(struct cpuInfo* cpu) { struct cache* cach = malloc(sizeof(struct cache)); init_cache_struct(cach); + + cach->max_cache_level = 2; + for(int i=0; i < cach->max_cache_level + 1; i++) { + cach->cach_arr[i]->exists = true; + cach->cach_arr[i]->size = 0; + } + return cach; } -struct frequency* get_frequency_info(struct cpuInfo* cpu) { +struct frequency* get_frequency_info(struct cpuInfo* cpu) { struct frequency* freq = malloc(sizeof(struct frequency)); - + freq->base = UNKNOWN_FREQ; - freq->max = UNKNOWN_FREQ; - - return freq; + freq->max = get_max_freq_from_file(); + + return freq; } struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) { - struct topology* topo = malloc(sizeof(struct topology)); + struct topology* topo = malloc(sizeof(struct topology)); init_topology_struct(topo, cach); + + topo->total_cores = get_ncores_from_cpuinfo(); + topo->physical_cores = topo->total_cores; + topo->logical_cores = topo->total_cores; + topo->smt_available = 1; + topo->smt_supported = 0; + topo->sockets = 1; + return topo; } -VENDOR get_cpu_vendor(struct cpuInfo* cpu) { - return cpu->cpu_vendor; +char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket) { + uint32_t size = 3+7+1; + char* string = malloc(sizeof(char)*size); + snprintf(string, size, "%d cores", topo->physical_cores); + + return string; } -uint32_t get_nsockets(struct topology* topo) { return 0; } -int64_t get_freq(struct frequency* freq) { return 0; } -char* get_str_cpu_name(struct cpuInfo* cpu) { - return cpu->cpu_name; +char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq) { + //7 for GFLOP/s and 6 for digits,eg 412.14 + uint32_t size = 7+6+1+1; + assert(strlen(STRING_UNKNOWN)+1 <= size); + char* string = malloc(sizeof(char)*size); + + //First check we have consistent data + if(freq == UNKNOWN_FREQ) { + snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN); + return string; + } + + double flops = topo->physical_cores * topo->sockets * (freq*1000000); + + if(flops >= (double)1000000000000.0) + snprintf(string,size,"%.2f TFLOP/s",flops/1000000000000); + else if(flops >= 1000000000.0) + snprintf(string,size,"%.2f GFLOP/s",flops/1000000000); + else + snprintf(string,size,"%.2f MFLOP/s",flops/1000000); + + return string; } -char* get_str_ncores(struct cpuInfo* cpu){ return NULL; } -char* get_str_avx(struct cpuInfo* cpu){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "No"); return tmp; } -char* get_str_sse(struct cpuInfo* cpu){ return NULL; } -char* get_str_fma(struct cpuInfo* cpu){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "No"); return tmp; } -char* get_str_aes(struct cpuInfo* cpu){ return NULL; } -char* get_str_sha(struct cpuInfo* cpu){ return NULL; } -char* get_str_l1i(struct cache* cach){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "0 KB"); return tmp; } -char* get_str_l1d(struct cache* cach){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "0 KB"); return tmp; } -char* get_str_l2(struct cache* cach){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "0 KB"); return tmp; } -char* get_str_l3(struct cache* cach){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "0 KB"); return tmp; } +void free_topo_struct(struct topology* topo) { + free(topo); +} -char* get_str_freq(struct frequency* freq){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "0 MHz"); return tmp; } - -char* get_str_sockets(struct topology* topo){ return NULL; } -char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket){ char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "0 cores"); return tmp; } - -char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq) { char* tmp = malloc(sizeof(char) * 10); strcpy(tmp, "0 MFLOP/s"); return tmp; } - -void free_cache_struct(struct cache* cach){ } -void free_topo_struct(struct topology* topo){ } -void free_freq_struct(struct frequency* freq){ } -void free_cpuinfo_struct(struct cpuInfo* cpu){ } - -void debug_cpu_info(struct cpuInfo* cpu){ } -void debug_cache(struct cache* cach){ } -void debug_frequency(struct frequency* freq){ } diff --git a/src/arm/midr.h b/src/arm/midr.h index 86eaa48..e4e7d20 100644 --- a/src/arm/midr.h +++ b/src/arm/midr.h @@ -8,37 +8,48 @@ struct cache* get_cache_info(struct cpuInfo* cpu); struct frequency* get_frequency_info(struct cpuInfo* cpu); struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach); -VENDOR get_cpu_vendor(struct cpuInfo* cpu); uint32_t get_nsockets(struct topology* topo); -int64_t get_freq(struct frequency* freq); - -char* get_str_cpu_name(struct cpuInfo* cpu); -char* get_str_ncores(struct cpuInfo* cpu); -char* get_str_avx(struct cpuInfo* cpu); -char* get_str_sse(struct cpuInfo* cpu); -char* get_str_fma(struct cpuInfo* cpu); -char* get_str_aes(struct cpuInfo* cpu); -char* get_str_sha(struct cpuInfo* cpu); - -char* get_str_l1i(struct cache* cach); -char* get_str_l1d(struct cache* cach); -char* get_str_l2(struct cache* cach); -char* get_str_l3(struct cache* cach); - -char* get_str_freq(struct frequency* freq); - -char* get_str_sockets(struct topology* topo); char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket); - char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq); -void free_cache_struct(struct cache* cach); void free_topo_struct(struct topology* topo); -void free_freq_struct(struct frequency* freq); -void free_cpuinfo_struct(struct cpuInfo* cpu); -void debug_cpu_info(struct cpuInfo* cpu); -void debug_cache(struct cache* cach); -void debug_frequency(struct frequency* freq); +// Code taken from cpuinfo (https://github.com/pytorch/cpuinfo/blob/master/src/arm/midr.h) +#define CPUINFO_ARM_MIDR_IMPLEMENTER_MASK UINT32_C(0xFF000000) +#define CPUINFO_ARM_MIDR_VARIANT_MASK UINT32_C(0x00F00000) +#define CPUINFO_ARM_MIDR_ARCHITECTURE_MASK UINT32_C(0x000F0000) +#define CPUINFO_ARM_MIDR_PART_MASK UINT32_C(0x0000FFF0) +#define CPUINFO_ARM_MIDR_REVISION_MASK UINT32_C(0x0000000F) + +#define CPUINFO_ARM_MIDR_IMPLEMENTER_OFFSET 24 +#define CPUINFO_ARM_MIDR_VARIANT_OFFSET 20 +#define CPUINFO_ARM_MIDR_ARCHITECTURE_OFFSET 16 +#define CPUINFO_ARM_MIDR_PART_OFFSET 4 +#define CPUINFO_ARM_MIDR_REVISION_OFFSET 0 + +inline static uint32_t midr_set_implementer(uint32_t midr, uint32_t implementer) { + return (midr & ~CPUINFO_ARM_MIDR_IMPLEMENTER_MASK) | + ((implementer << CPUINFO_ARM_MIDR_IMPLEMENTER_OFFSET) & CPUINFO_ARM_MIDR_IMPLEMENTER_MASK); +} + +inline static uint32_t midr_set_variant(uint32_t midr, uint32_t variant) { + return (midr & ~CPUINFO_ARM_MIDR_VARIANT_MASK) | + ((variant << CPUINFO_ARM_MIDR_VARIANT_OFFSET) & CPUINFO_ARM_MIDR_VARIANT_MASK); +} + +inline static uint32_t midr_set_architecture(uint32_t midr, uint32_t architecture) { + return (midr & ~CPUINFO_ARM_MIDR_ARCHITECTURE_MASK) | + ((architecture << CPUINFO_ARM_MIDR_ARCHITECTURE_OFFSET) & CPUINFO_ARM_MIDR_ARCHITECTURE_MASK); +} + +inline static uint32_t midr_set_part(uint32_t midr, uint32_t part) { + return (midr & ~CPUINFO_ARM_MIDR_PART_MASK) | + ((part << CPUINFO_ARM_MIDR_PART_OFFSET) & CPUINFO_ARM_MIDR_PART_MASK); +} + +inline static uint32_t midr_set_revision(uint32_t midr, uint32_t revision) { + return (midr & ~CPUINFO_ARM_MIDR_REVISION_MASK) | + ((revision << CPUINFO_ARM_MIDR_REVISION_OFFSET) & CPUINFO_ARM_MIDR_REVISION_MASK); +} #endif diff --git a/src/common/cpu.c b/src/common/cpu.c new file mode 100755 index 0000000..0cfa147 --- /dev/null +++ b/src/common/cpu.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include + +#include "../common/global.h" +#include "cpu.h" + +#ifdef ARCH_X86 + #include "../x86/uarch.h" +#elif ARCH_ARM + #include "../arm/uarch.h" +#endif + +#define STRING_UNKNOWN "Unknown" +#define STRING_YES "Yes" +#define STRING_NO "No" +#define STRING_NONE "None" +#define STRING_MEGAHERZ "MHz" +#define STRING_GIGAHERZ "GHz" +#define STRING_KILOBYTES "KB" +#define STRING_MEGABYTES "MB" + +VENDOR get_cpu_vendor(struct cpuInfo* cpu) { + return cpu->cpu_vendor; +} + +uint32_t get_nsockets(struct topology* topo) { + return topo->sockets; +} + +int64_t get_freq(struct frequency* freq) { + return freq->max; +} + +char* get_str_sockets(struct topology* topo) { + char* string = malloc(sizeof(char) * 2); + int32_t sanity_ret = snprintf(string, 2, "%d", topo->sockets); + if(sanity_ret < 0) { + printBug("get_str_sockets: snprintf returned a negative value for input: '%d'", topo->sockets); + return NULL; + } + return string; +} + +char* get_str_cpu_name(struct cpuInfo* cpu) { + return cpu->cpu_name; +} + +int32_t get_value_as_smallest_unit(char ** str, uint32_t value) { + int32_t sanity_ret; + *str = malloc(sizeof(char)* 11); //8 for digits, 2 for units + + if(value/1024 >= 1024) + sanity_ret = snprintf(*str, 10,"%.4g"STRING_MEGABYTES, (double)value/(1<<20)); + else + sanity_ret = snprintf(*str, 10,"%.4g"STRING_KILOBYTES, (double)value/(1<<10)); + + return sanity_ret; +} + +// String functions +char* get_str_cache_two(int32_t cache_size, uint32_t physical_cores) { + // 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)' + uint32_t max_size = 4+2 + 2 + 4+2 + 7 + 1; + int32_t sanity_ret; + char* string = malloc(sizeof(char) * max_size); + char* tmp1; + char* tmp2; + int32_t tmp1_len = get_value_as_smallest_unit(&tmp1, cache_size); + int32_t tmp2_len = get_value_as_smallest_unit(&tmp2, cache_size * physical_cores); + + if(tmp1_len < 0) { + printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size); + return NULL; + } + if(tmp2_len < 0) { + printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size * physical_cores); + return NULL; + } + + uint32_t size = tmp1_len + 2 + tmp2_len + 7 + 1; + sanity_ret = snprintf(string, size, "%s (%s Total)", tmp1, tmp2); + + if(sanity_ret < 0) { + printBug("get_str_cache_two: snprintf returned a negative value for input: '%s' and '%s'\n", tmp1, tmp2); + return NULL; + } + + free(tmp1); + free(tmp2); + return string; +} + +char* get_str_cache_one(int32_t cache_size) { + // 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)' + uint32_t max_size = 4+2 + 1; + int32_t sanity_ret; + char* string = malloc(sizeof(char) * max_size); + char* tmp; + int32_t tmp_len = get_value_as_smallest_unit(&tmp, cache_size); + + if(tmp_len < 0) { + printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d", cache_size); + return NULL; + } + + uint32_t size = tmp_len + 1; + sanity_ret = snprintf(string, size, "%s", tmp); + + if(sanity_ret < 0) { + printBug("get_str_cache_one: snprintf returned a negative value for input: '%s'", tmp); + return NULL; + } + free(tmp); + return string; +} + +char* get_str_cache(int32_t cache_size, int32_t num_caches) { + if(num_caches > 1) + return get_str_cache_two(cache_size, num_caches); + else + return get_str_cache_one(cache_size); +} + +char* get_str_l1i(struct cache* cach) { + return get_str_cache(cach->L1i->size, cach->L1i->num_caches); +} + +char* get_str_l1d(struct cache* cach) { + return get_str_cache(cach->L1d->size, cach->L1d->num_caches); +} + +char* get_str_l2(struct cache* cach) { + assert(cach->L2->exists); + return get_str_cache(cach->L2->size, cach->L2->num_caches); +} + +char* get_str_l3(struct cache* cach) { + if(!cach->L3->exists) + return NULL; + return get_str_cache(cach->L3->size, cach->L3->num_caches); +} + +char* get_str_freq(struct frequency* freq) { + //Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0' + uint32_t size = (4+3+1); + assert(strlen(STRING_UNKNOWN)+1 <= size); + char* string = malloc(sizeof(char)*size); + if(freq->max == UNKNOWN_FREQ) + snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN); + else if(freq->max >= 1000) + snprintf(string,size,"%.2f"STRING_GIGAHERZ,(float)(freq->max)/1000); + else + snprintf(string,size,"%.2f"STRING_MEGAHERZ,(float)(freq->max)); + return string; +} + +void free_cache_struct(struct cache* cach) { + for(int i=0; i < 4; i++) free(cach->cach_arr[i]); + free(cach->cach_arr); + free(cach); +} + +void free_freq_struct(struct frequency* freq) { + free(freq); +} + +void free_hv_struct(struct hypervisor* hv) { + free(hv); +} + +void free_cpuinfo_struct(struct cpuInfo* cpu) { + free_uarch_struct(cpu->arch); + free_hv_struct(cpu->hv); + free(cpu->cpu_name); + free(cpu); +} diff --git a/src/common/cpu.h b/src/common/cpu.h index 8149a8b..0b1b0ed 100644 --- a/src/common/cpu.h +++ b/src/common/cpu.h @@ -68,6 +68,9 @@ struct cpuInfo { uint32_t maxLevels; // Max cpuids extended levels uint32_t maxExtendedLevels; +#else + // Main ID register + uint32_t midr; #endif struct uarch* arch; @@ -104,4 +107,22 @@ struct topology { #endif }; +VENDOR get_cpu_vendor(struct cpuInfo* cpu); +uint32_t get_nsockets(struct topology* topo); +int64_t get_freq(struct frequency* freq); + +char* get_str_sockets(struct topology* topo); +char* get_str_cpu_name(struct cpuInfo* cpu); +char* get_str_aes(struct cpuInfo* cpu); +char* get_str_sha(struct cpuInfo* cpu); +char* get_str_l1i(struct cache* cach); +char* get_str_l1d(struct cache* cach); +char* get_str_l2(struct cache* cach); +char* get_str_l3(struct cache* cach); +char* get_str_freq(struct frequency* freq); + +void free_cache_struct(struct cache* cach); +void free_freq_struct(struct frequency* freq); +void free_cpuinfo_struct(struct cpuInfo* cpu); + #endif diff --git a/src/common/main.c b/src/common/main.c index 5907795..fd7a37e 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -13,7 +13,7 @@ #include "../arm/midr.h" #endif -static const char* VERSION = "0.8"; +static const char* VERSION = "0.81"; void print_help(char *argv[]) { #ifdef ARCH_X86 diff --git a/src/common/printer.c b/src/common/printer.c index 2dcf9bd..57c2033 100644 --- a/src/common/printer.c +++ b/src/common/printer.c @@ -6,6 +6,7 @@ #include "printer.h" #include "ascii.h" #include "../common/global.h" +#include "../common/cpu.h" #ifdef ARCH_X86 #include "../x86/uarch.h" @@ -49,8 +50,10 @@ enum { ATTRIBUTE_SOCKETS, ATTRIBUTE_NCORES, ATTRIBUTE_NCORES_DUAL, +#ifdef ARCH_X86 ATTRIBUTE_AVX, ATTRIBUTE_FMA, +#endif ATTRIBUTE_L1i, ATTRIBUTE_L1d, ATTRIBUTE_L2, @@ -67,8 +70,10 @@ static const char* ATTRIBUTE_FIELDS [] = { "Sockets:", "Cores:", "Cores (Total):", +#ifdef ARCH_X86 "AVX:", "FMA:", +#endif "L1i Size:", "L1d Size:", "L2 Size:", @@ -85,8 +90,10 @@ static const int ATTRIBUTE_LIST[] = { ATTRIBUTE_SOCKETS, ATTRIBUTE_NCORES, ATTRIBUTE_NCORES_DUAL, +#ifdef ARCH_X86 ATTRIBUTE_AVX, ATTRIBUTE_FMA, +#endif ATTRIBUTE_L1i, ATTRIBUTE_L1d, ATTRIBUTE_L2, @@ -386,8 +393,12 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f char* max_frequency = get_str_freq(freq); char* n_cores = get_str_topology(cpu, topo, false); char* n_cores_dual = get_str_topology(cpu, topo, true); +#ifdef ARCH_X86 char* avx = get_str_avx(cpu); char* fma = get_str_fma(cpu); + setAttribute(art,ATTRIBUTE_AVX,avx); + setAttribute(art,ATTRIBUTE_FMA,fma); +#endif char* l1i = get_str_l1i(topo->cach); char* l1d = get_str_l1d(topo->cach); char* l2 = get_str_l2(topo->cach); @@ -399,8 +410,6 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f setAttribute(art,ATTRIBUTE_TECHNOLOGY,manufacturing_process); setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency); 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); @@ -428,8 +437,10 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f free(sockets); free(n_cores); free(n_cores_dual); +#ifdef ARCH_X86 free(avx); free(fma); +#endif free(l1i); free(l1d); free(l2); diff --git a/src/common/udev.c b/src/common/udev.c index 4e96929..8193cf8 100644 --- a/src/common/udev.c +++ b/src/common/udev.c @@ -10,8 +10,8 @@ #ifdef ARCH_X86 #include "../x86/cpuid.h" #else - #include "../arm/cpuid.h" -#endif + #include "../arm/midr.h" +#endif #define _PATH_SYS_SYSTEM "/sys/devices/system" #define _PATH_SYS_CPU _PATH_SYS_SYSTEM"/cpu" @@ -77,3 +77,145 @@ long get_max_freq_from_file() { long get_min_freq_from_file() { return get_freq_from_file(_PATH_FREQUENCY_MIN); } + +#ifdef ARCH_ARM + +#define UNKNOWN -1 +#define _PATH_CPUINFO "/proc/cpuinfo" + +#define CPUINFO_CPU_IMPLEMENTER_STR "CPU implementer\t: " +#define CPUINFO_CPU_ARCHITECTURE_STR "CPU architecture: " +#define CPUINFO_CPU_VARIANT_STR "CPU variant\t: " +#define CPUINFO_CPU_PART_STR "CPU part\t: " +#define CPUINFO_CPU_REVISION_STR "CPU revision\t: " + +#define CPUINFO_CPU_STRING "processor" + +int get_ncores_from_cpuinfo() { + int fd = open(_PATH_CPUINFO, O_RDONLY); + + if(fd == -1) { + perror("open"); + return UNKNOWN; + } + + //File exists, read it + int bytes_read = 0; + int offset = 0; + int block = 128; + char* buf = malloc(sizeof(char)*DEFAULT_FILE_SIZE); + memset(buf, 0, sizeof(char)*DEFAULT_FILE_SIZE); + + while ( (bytes_read = read(fd, buf+offset, block)) > 0 ) { + offset += bytes_read; + } + + int ncores = 0; + char* tmp = buf; + do { + tmp++; + ncores++; + tmp = strstr(tmp, CPUINFO_CPU_STRING); + } while(tmp != NULL); + + free(buf); + + if (close(fd) == -1) { + perror("close"); + } + + return ncores; +} + +long parse_cpuinfo_field(char* buf, char* field_str, int field_base) { + char* tmp = strstr(buf, field_str); + if(tmp == NULL) return -1; + tmp += strlen(field_str); + + char* end; + errno = 0; + long ret = strtol(tmp, &end, field_base); + if(errno != 0) { + perror("strtol"); + return -1; + } + + return ret; +} +// https://developer.arm.com/docs/ddi0595/h/aarch32-system-registers/midr +// https://static.docs.arm.com/ddi0595/h/SysReg_xml_v86A-2020-06.pdf +uint32_t get_midr_from_cpuinfo(uint32_t core) { + int fd = open(_PATH_CPUINFO, O_RDONLY); + + if(fd == -1) { + perror("open"); + return UNKNOWN; + } + + //File exists, read it + int bytes_read = 0; + int offset = 0; + int block = 128; + char* buf = malloc(sizeof(char)*DEFAULT_FILE_SIZE); + memset(buf, 0, sizeof(char)*DEFAULT_FILE_SIZE); + + while ( (bytes_read = read(fd, buf+offset, block)) > 0 ) { + offset += bytes_read; + } + + char* tmp = buf; + uint32_t current_core = 0; + while(core != current_core && tmp != NULL) { + tmp++; + current_core++; + tmp = strstr(tmp, CPUINFO_CPU_STRING); + } + + uint32_t cpu_implementer; + uint32_t cpu_architecture; + uint32_t cpu_variant; + uint32_t cpu_part; + uint32_t cpu_revision; + uint32_t midr = 0; + long ret; + + if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_IMPLEMENTER_STR, 16)) < 0) { + printf("Failed parsing cpu_implementer\n"); + return 0; + } + cpu_implementer = (uint32_t) ret; + + if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_ARCHITECTURE_STR, 10)) < 0) { + printf("Failed parsing cpu_architecture\n"); + return 0; + } + cpu_architecture = (uint32_t) 0xF; // Why? + + if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_VARIANT_STR, 16)) < 0) { + printf("Failed parsing cpu_variant\n"); + return 0; + } + cpu_variant = (uint32_t) ret; + + if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_PART_STR, 16)) < 0) { + printf("Failed parsing cpu_part\n"); + return 0; + } + cpu_part = (uint32_t) ret; + + if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_REVISION_STR, 10)) < 0) { + printf("Failed parsing cpu_revision\n"); + return 0; + } + cpu_revision = (uint32_t) ret; + + midr = midr_set_implementer(midr, cpu_implementer); + midr = midr_set_variant(midr, cpu_variant); + midr = midr_set_architecture(midr, cpu_architecture); + midr = midr_set_part(midr, cpu_part); + midr = midr_set_revision(midr, cpu_revision); + + return midr; +} + +#endif /* ARCH_ARM */ diff --git a/src/common/udev.h b/src/common/udev.h index 3517b2e..528995d 100644 --- a/src/common/udev.h +++ b/src/common/udev.h @@ -1,7 +1,14 @@ #ifndef __UDEV__ #define __UDEV__ +#include + long get_max_freq_from_file(); long get_min_freq_from_file(); +#ifdef ARCH_ARM +int get_ncores_from_cpuinfo(); +uint32_t get_midr_from_cpuinfo(uint32_t core); +#endif + #endif diff --git a/src/x86/cpuid.c b/src/x86/cpuid.c index f2ad3b6..af2ded3 100755 --- a/src/x86/cpuid.c +++ b/src/x86/cpuid.c @@ -40,14 +40,7 @@ static char *hv_vendors_name[] = { [HV_VENDOR_INVALID] = "Unknown" }; -#define STRING_YES "Yes" -#define STRING_NO "No" #define STRING_UNKNOWN "Unknown" -#define STRING_NONE "None" -#define STRING_MEGAHERZ "MHz" -#define STRING_GIGAHERZ "GHz" -#define STRING_KILOBYTES "KB" -#define STRING_MEGABYTES "MB" #define HYPERVISOR_NAME_MAX_LENGTH 17 @@ -662,55 +655,6 @@ struct frequency* get_frequency_info(struct cpuInfo* cpu) { return freq; } -uint32_t get_nsockets(struct topology* topo) { - return topo->sockets; -} - -int64_t get_freq(struct frequency* freq) { - return freq->max; -} - -VENDOR get_cpu_vendor(struct cpuInfo* cpu) { - return cpu->cpu_vendor; -} - -void debug_cpu_info(struct cpuInfo* cpu) { - printf("AVX=%s\n", cpu->AVX ? "true" : "false"); - printf("AVX2=%s\n", cpu->AVX2 ? "true" : "false"); - printf("AVX512=%s\n\n", cpu->AVX512 ? "true" : "false"); - - printf("SSE=%s\n", cpu->SSE ? "true" : "false"); - printf("SSE2=%s\n", cpu->SSE2 ? "true" : "false"); - printf("SSE3=%s\n", cpu->SSE3 ? "true" : "false"); - printf("SSSE3=%s\n", cpu->SSSE3 ? "true" : "false"); - printf("SSE4a=%s\n", cpu->SSE4a ? "true" : "false"); - printf("SSE4_1=%s\n", cpu->SSE4_1 ? "true" : "false"); - printf("SSE4_2=%s\n\n", cpu->SSE4_2 ? "true" : "false"); - - printf("FMA3=%s\n", cpu->FMA3 ? "true" : "false"); - printf("FMA4=%s\n\n", cpu->FMA4 ? "true" : "false"); - - printf("AES=%s\n", cpu->AES ? "true" : "false"); - printf("SHA=%s\n", cpu->SHA ? "true" : "false"); -} - -void debug_cache(struct cache* cach) { - printf("L1i=%dB\n",cach->L1i->size); - printf("L1d=%dB\n",cach->L1d->size); - printf("L2=%dB\n",cach->L2->size); - printf("L3=%dB\n",cach->L3->size); -} - -void debug_frequency(struct frequency* freq) { - #ifdef _WIN32 - printf("maxf=%I64d Mhz\n",freq->max); - printf("basef=%I64d Mhz\n",freq->base); - #else - printf("maxf=%ld Mhz\n",freq->max); - printf("basef=%ld Mhz\n",freq->base); - #endif -} - /*** STRING FUNCTIONS ***/ char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq) { @@ -810,20 +754,6 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc return string; } -char* get_str_sockets(struct topology* topo) { - char* string = malloc(sizeof(char) * 2); - int32_t sanity_ret = snprintf(string, 2, "%d", topo->sockets); - if(sanity_ret < 0) { - printBug("get_str_sockets: snprintf returned a negative value for input: '%d'", topo->sockets); - return NULL; - } - return string; -} - -char* get_str_cpu_name(struct cpuInfo* cpu) { - return cpu->cpu_name; -} - char* get_str_avx(struct cpuInfo* cpu) { //If all AVX are available, it will use up to 15 char* string = malloc(sizeof(char)*17+1); @@ -896,131 +826,43 @@ char* get_str_fma(struct cpuInfo* cpu) { return string; } -char* get_str_aes(struct cpuInfo* cpu) { - char* string = malloc(sizeof(char)*3+1); - if(cpu->AES) - snprintf(string,3+1,STRING_YES); - else - snprintf(string,2+1,STRING_NO); - return string; +/*** DEBUG ***/ + +void debug_cpu_info(struct cpuInfo* cpu) { + printf("AVX=%s\n", cpu->AVX ? "true" : "false"); + printf("AVX2=%s\n", cpu->AVX2 ? "true" : "false"); + printf("AVX512=%s\n\n", cpu->AVX512 ? "true" : "false"); + + printf("SSE=%s\n", cpu->SSE ? "true" : "false"); + printf("SSE2=%s\n", cpu->SSE2 ? "true" : "false"); + printf("SSE3=%s\n", cpu->SSE3 ? "true" : "false"); + printf("SSSE3=%s\n", cpu->SSSE3 ? "true" : "false"); + printf("SSE4a=%s\n", cpu->SSE4a ? "true" : "false"); + printf("SSE4_1=%s\n", cpu->SSE4_1 ? "true" : "false"); + printf("SSE4_2=%s\n\n", cpu->SSE4_2 ? "true" : "false"); + + printf("FMA3=%s\n", cpu->FMA3 ? "true" : "false"); + printf("FMA4=%s\n\n", cpu->FMA4 ? "true" : "false"); + + printf("AES=%s\n", cpu->AES ? "true" : "false"); + printf("SHA=%s\n", cpu->SHA ? "true" : "false"); } -char* get_str_sha(struct cpuInfo* cpu) { - char* string = malloc(sizeof(char)*3+1); - if(cpu->SHA) - snprintf(string,3+1,STRING_YES); - else - snprintf(string,2+1,STRING_NO); - return string; +void debug_cache(struct cache* cach) { + printf("L1i=%dB\n",cach->L1i->size); + printf("L1d=%dB\n",cach->L1d->size); + printf("L2=%dB\n",cach->L2->size); + printf("L3=%dB\n",cach->L3->size); } -int32_t get_value_as_smallest_unit(char ** str, uint32_t value) { - int32_t sanity_ret; - *str = malloc(sizeof(char)* 11); //8 for digits, 2 for units - - if(value/1024 >= 1024) - sanity_ret = snprintf(*str, 10,"%.4g"STRING_MEGABYTES, (double)value/(1<<20)); - else - sanity_ret = snprintf(*str, 10,"%.4g"STRING_KILOBYTES, (double)value/(1<<10)); - - return sanity_ret; -} - -// String functions -char* get_str_cache_two(int32_t cache_size, uint32_t physical_cores) { - // 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)' - uint32_t max_size = 4+2 + 2 + 4+2 + 7 + 1; - int32_t sanity_ret; - char* string = malloc(sizeof(char) * max_size); - char* tmp1; - char* tmp2; - int32_t tmp1_len = get_value_as_smallest_unit(&tmp1, cache_size); - int32_t tmp2_len = get_value_as_smallest_unit(&tmp2, cache_size * physical_cores); - - if(tmp1_len < 0) { - printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size); - return NULL; - } - if(tmp2_len < 0) { - printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size * physical_cores); - return NULL; - } - - uint32_t size = tmp1_len + 2 + tmp2_len + 7 + 1; - sanity_ret = snprintf(string, size, "%s (%s Total)", tmp1, tmp2); - - if(sanity_ret < 0) { - printBug("get_str_cache_two: snprintf returned a negative value for input: '%s' and '%s'\n", tmp1, tmp2); - return NULL; - } - - free(tmp1); - free(tmp2); - return string; -} - -char* get_str_cache_one(int32_t cache_size) { - // 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)' - uint32_t max_size = 4+2 + 1; - int32_t sanity_ret; - char* string = malloc(sizeof(char) * max_size); - char* tmp; - int32_t tmp_len = get_value_as_smallest_unit(&tmp, cache_size); - - if(tmp_len < 0) { - printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d", cache_size); - return NULL; - } - - uint32_t size = tmp_len + 1; - sanity_ret = snprintf(string, size, "%s", tmp); - - if(sanity_ret < 0) { - printBug("get_str_cache_one: snprintf returned a negative value for input: '%s'", tmp); - return NULL; - } - free(tmp); - return string; -} - -char* get_str_cache(int32_t cache_size, int32_t num_caches) { - if(num_caches > 1) - return get_str_cache_two(cache_size, num_caches); - else - return get_str_cache_one(cache_size); -} - -char* get_str_l1i(struct cache* cach) { - return get_str_cache(cach->L1i->size, cach->L1i->num_caches); -} - -char* get_str_l1d(struct cache* cach) { - return get_str_cache(cach->L1d->size, cach->L1d->num_caches); -} - -char* get_str_l2(struct cache* cach) { - assert(cach->L2->exists); - return get_str_cache(cach->L2->size, cach->L2->num_caches); -} - -char* get_str_l3(struct cache* cach) { - if(!cach->L3->exists) - return NULL; - return get_str_cache(cach->L3->size, cach->L3->num_caches); -} - -char* get_str_freq(struct frequency* freq) { - //Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0' - uint32_t size = (4+3+1); - assert(strlen(STRING_UNKNOWN)+1 <= size); - char* string = malloc(sizeof(char)*size); - if(freq->max == UNKNOWN_FREQ) - snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN); - else if(freq->max >= 1000) - snprintf(string,size,"%.2f"STRING_GIGAHERZ,(float)(freq->max)/1000); - else - snprintf(string,size,"%.2f"STRING_MEGAHERZ,(float)(freq->max)); - return string; +void debug_frequency(struct frequency* freq) { + #ifdef _WIN32 + printf("maxf=%I64d Mhz\n",freq->max); + printf("basef=%I64d Mhz\n",freq->base); + #else + printf("maxf=%ld Mhz\n",freq->max); + printf("basef=%ld Mhz\n",freq->base); + #endif } void free_topo_struct(struct topology* topo) { @@ -1029,24 +871,3 @@ void free_topo_struct(struct topology* topo) { free(topo->apic); free(topo); } - -void free_cache_struct(struct cache* cach) { - for(int i=0; i < 4; i++) free(cach->cach_arr[i]); - free(cach->cach_arr); - free(cach); -} - -void free_freq_struct(struct frequency* freq) { - free(freq); -} - -void free_hv_struct(struct hypervisor* hv) { - free(hv); -} - -void free_cpuinfo_struct(struct cpuInfo* cpu) { - free_uarch_struct(cpu->arch); - free_hv_struct(cpu->hv); - free(cpu->cpu_name); - free(cpu); -} diff --git a/src/x86/cpuid.h b/src/x86/cpuid.h index 3768638..ec357ee 100644 --- a/src/x86/cpuid.h +++ b/src/x86/cpuid.h @@ -8,37 +8,16 @@ struct cache* get_cache_info(struct cpuInfo* cpu); struct frequency* get_frequency_info(struct cpuInfo* cpu); struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach); -VENDOR get_cpu_vendor(struct cpuInfo* cpu); -uint32_t get_nsockets(struct topology* topo); -int64_t get_freq(struct frequency* freq); - -char* get_str_cpu_name(struct cpuInfo* cpu); -char* get_str_ncores(struct cpuInfo* cpu); char* get_str_avx(struct cpuInfo* cpu); char* get_str_sse(struct cpuInfo* cpu); char* get_str_fma(struct cpuInfo* cpu); -char* get_str_aes(struct cpuInfo* cpu); -char* get_str_sha(struct cpuInfo* cpu); - -char* get_str_l1i(struct cache* cach); -char* get_str_l1d(struct cache* cach); -char* get_str_l2(struct cache* cach); -char* get_str_l3(struct cache* cach); - -char* get_str_freq(struct frequency* freq); - -char* get_str_sockets(struct topology* topo); char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket); - char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq); -void free_cache_struct(struct cache* cach); -void free_topo_struct(struct topology* topo); -void free_freq_struct(struct frequency* freq); -void free_cpuinfo_struct(struct cpuInfo* cpu); - void debug_cpu_info(struct cpuInfo* cpu); void debug_cache(struct cache* cach); void debug_frequency(struct frequency* freq); +void free_topo_struct(struct topology* topo); + #endif