diff --git a/Makefile b/Makefile index 24c771d..8db5ffb 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ CXXFLAGS=-Wall -Wextra -Werror -fstack-protector-all -pedantic -Wno-unused -std= SANITY_FLAGS=-Wfloat-equal -Wshadow -Wpointer-arith -Wstrict-overflow=5 -Wformat=2 SRC_DIR=src/ -SOURCE=$(SRC_DIR)main.c $(SRC_DIR)standart.c $(SRC_DIR)extended.c $(SRC_DIR)cpuid.c $(SRC_DIR)printer.c $(SRC_DIR)args.c $(SRC_DIR)global.c -HEADERS=$(SRC_DIR)standart.h $(SRC_DIR)extended.h $(SRC_DIR)cpuid.h $(SRC_DIR)printer.h $(SRC_DIR)ascii.h $(SRC_DIR)args.h $(SRC_DIR)global.h +SOURCE=$(SRC_DIR)main.c $(SRC_DIR)cpuid.c $(SRC_DIR)cpuid_asm.c $(SRC_DIR)printer.c $(SRC_DIR)args.c $(SRC_DIR)global.c +HEADERS=$(SRC_DIR)cpuid.h $(SRC_DIR)cpuid_asm.h $(SRC_DIR)printer.h $(SRC_DIR)ascii.h $(SRC_DIR)args.h $(SRC_DIR)global.h ifneq ($(OS),Windows_NT) SOURCE += $(SRC_DIR)udev.c diff --git a/src/cpuid.c b/src/cpuid.c index 9a7b556..b70ac38 100644 --- a/src/cpuid.c +++ b/src/cpuid.c @@ -1,10 +1,839 @@ -#include "cpuid.h" +#include +#include +#include +#include +#include -void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { - __asm volatile("cpuid" - : "=a" (*eax), - "=b" (*ebx), - "=c" (*ecx), - "=d" (*edx) - : "0" (*eax), "2" (*ecx)); +#ifdef _WIN32 +#include +#else +#include +#include "udev.h" +#endif + +#include "cpuid.h" +#include "cpuid_asm.h" +#include "global.h" + +#define VENDOR_INTEL_STRING "GenuineIntel" +#define VENDOR_AMD_STRING "AuthenticAMD" + +#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 CPU_NAME_MAX_LENGTH 64 + +#define MASK 0xFF + +/* + * cpuid reference: http://www.sandpile.org/x86/cpuid.htm + * cpuid amd: https://www.amd.com/system/files/TechDocs/25481.pdf + */ + +struct cpuInfo { + bool AVX; + bool AVX2; + bool AVX512; + bool SSE; + bool SSE2; + bool SSE3; + bool SSSE3; + bool SSE4a; + bool SSE4_1; + bool SSE4_2; + bool FMA3; + bool FMA4; + bool AES; + bool SHA; + + VENDOR cpu_vendor; + + char* cpu_name; + // Max cpuids levels + uint32_t maxLevels; + // Max cpuids extended levels + uint32_t maxExtendedLevels; +}; + +struct cache { + int32_t L1i; + int32_t L1d; + int32_t L2; + int32_t L3; +}; + +struct frequency { + int64_t base; + int64_t max; +}; + +struct topology { + int64_t total_cores; + uint32_t physical_cores; + uint32_t logical_cores; + uint32_t smt; + uint32_t sockets; + bool ht; +}; + +void init_cpu_info(struct cpuInfo* cpu) { + cpu->AVX = false; + cpu->AVX2 = false; + cpu->AVX512 = false; + cpu->SSE = false; + cpu->SSE2 = false; + cpu->SSE3 = false; + cpu->SSSE3 = false; + cpu->SSE4a = false; + cpu->SSE4_1 = false; + cpu->SSE4_2 = false; + cpu->FMA3 = false; + cpu->FMA4 = false; + cpu->AES = false; + cpu->SHA = false; +} + +void get_cpu_vendor_internal(char* name, uint32_t ebx,uint32_t ecx,uint32_t edx) { + name[__COUNTER__] = ebx & MASK; + name[__COUNTER__] = (ebx>>8) & MASK; + name[__COUNTER__] = (ebx>>16) & MASK; + name[__COUNTER__] = (ebx>>24) & MASK; + + name[__COUNTER__] = edx & MASK; + name[__COUNTER__] = (edx>>8) & MASK; + name[__COUNTER__] = (edx>>16) & MASK; + name[__COUNTER__] = (edx>>24) & MASK; + + name[__COUNTER__] = ecx & MASK; + name[__COUNTER__] = (ecx>>8) & MASK; + name[__COUNTER__] = (ecx>>16) & MASK; + name[__COUNTER__] = (ecx>>24) & MASK; +} + +char* get_str_cpu_name_internal() { + uint32_t eax = 0; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + uint32_t c = 0; + + char * name = malloc(sizeof(char) * CPU_NAME_MAX_LENGTH); + memset(name, 0, CPU_NAME_MAX_LENGTH); + + for(int i=0; i < 3; i++) { + eax = 0x80000002 + i; + cpuid(&eax, &ebx, &ecx, &edx); + + name[c++] = eax & MASK; + name[c++] = (eax>>8) & MASK; + name[c++] = (eax>>16) & MASK; + name[c++] = (eax>>24) & MASK; + name[c++] = ebx & MASK; + name[c++] = (ebx>>8) & MASK; + name[c++] = (ebx>>16) & MASK; + name[c++] = (ebx>>24) & MASK; + name[c++] = ecx & MASK; + name[c++] = (ecx>>8) & MASK; + name[c++] = (ecx>>16) & MASK; + name[c++] = (ecx>>24) & MASK; + name[c++] = edx & MASK; + name[c++] = (edx>>8) & MASK; + name[c++] = (edx>>16) & MASK; + name[c++] = (edx>>24) & MASK; + } + name[c] = '\0'; + + //Remove unused characters + char *str = name; + char *dest = name; + while (*str != '\0') { + while (*str == ' ' && *(str + 1) == ' ') str++; + *dest++ = *str++; + } + *dest = '\0'; + + return name; +} + +struct cpuInfo* get_cpu_info() { + struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); + init_cpu_info(cpu); + uint32_t eax = 0; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + + //Get max cpuid level + cpuid(&eax, &ebx, &ecx, &edx); + cpu->maxLevels = eax; + + //Fill vendor + char name[13]; + memset(name,0,13); + get_cpu_vendor_internal(name, ebx, ecx, edx); + + if(strcmp(VENDOR_INTEL_STRING,name) == 0) + cpu->cpu_vendor = VENDOR_INTEL; + else if (strcmp(VENDOR_AMD_STRING,name) == 0) + cpu->cpu_vendor = VENDOR_AMD; + else { + cpu->cpu_vendor = VENDOR_INVALID; + printErr("Unknown CPU vendor: %s", name); + return NULL; + } + + //Get max extended level + eax = 0x80000000; + ebx = 0; + ecx = 0; + edx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + cpu->maxExtendedLevels = eax; + + //Fill instructions support + if (cpu->maxLevels >= 0x00000001){ + eax = 0x00000001; + cpuid(&eax, &ebx, &ecx, &edx); + cpu->SSE = (edx & ((int)1 << 25)) != 0; + cpu->SSE2 = (edx & ((int)1 << 26)) != 0; + cpu->SSE3 = (ecx & ((int)1 << 0)) != 0; + + cpu->SSSE3 = (ecx & ((int)1 << 9)) != 0; + cpu->SSE4_1 = (ecx & ((int)1 << 19)) != 0; + cpu->SSE4_2 = (ecx & ((int)1 << 20)) != 0; + + cpu->AES = (ecx & ((int)1 << 25)) != 0; + + cpu->AVX = (ecx & ((int)1 << 28)) != 0; + cpu->FMA3 = (ecx & ((int)1 << 12)) != 0; + } + else { + printWarn("Can't read features information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels); + } + + if (cpu->maxLevels >= 0x00000007){ + eax = 0x00000007; + ecx = 0x00000000; + cpuid(&eax, &ebx, &ecx, &edx); + cpu->AVX2 = (ebx & ((int)1 << 5)) != 0; + cpu->SHA = (ebx & ((int)1 << 29)) != 0; + cpu->AVX512 = (((ebx & ((int)1 << 16)) != 0) || + ((ebx & ((int)1 << 28)) != 0) || + ((ebx & ((int)1 << 26)) != 0) || + ((ebx & ((int)1 << 27)) != 0) || + ((ebx & ((int)1 << 31)) != 0) || + ((ebx & ((int)1 << 30)) != 0) || + ((ebx & ((int)1 << 17)) != 0) || + ((ebx & ((int)1 << 21)) != 0)); + } + else { + printWarn("Can't read features information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000007, cpu->maxLevels); + } + + if (cpu->maxExtendedLevels >= 0x80000001){ + eax = 0x80000001; + cpuid(&eax, &ebx, &ecx, &edx); + cpu->SSE4a = (ecx & ((int)1 << 6)) != 0; + cpu->FMA4 = (ecx & ((int)1 << 16)) != 0; + } + else { + printWarn("Can't read features information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000001, cpu->maxExtendedLevels); + } + + if (cpu->maxExtendedLevels >= 0x80000004){ + cpu->cpu_name = get_str_cpu_name_internal(); + } + else { + cpu->cpu_name = malloc(sizeof(char)*8); + sprintf(cpu->cpu_name,"Unknown"); + printWarn("Can't read cpu name from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000004, cpu->maxExtendedLevels); + } + + return cpu; +} + +// 80/2/20 +struct topology* get_topology_info(struct cpuInfo* cpu) { + struct topology* topo = malloc(sizeof(struct topology)); + uint32_t eax = 0; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + int32_t type; + + if (cpu->maxLevels >= 0x00000001) { + eax = 0x00000001; + cpuid(&eax, &ebx, &ecx, &edx); + topo->ht = edx & (1 << 28); + } + else { + printWarn("Can't read HT information from cpuid (needed level is 0x%.8X, max is 0x%.8X). Assuming HT is disabled", 0x00000001, cpu->maxLevels); + topo->ht = false; + } + + switch(cpu->cpu_vendor) { + case VENDOR_INTEL: + if (cpu->maxLevels >= 0x0000000B) { + eax = 0x0000000B; + ecx = 0x00000000; + cpuid(&eax, &ebx, &ecx, &edx); + type = (ecx >> 8) & 0xFF; + if (type != 1) { + printBug("Unexpected type in cpuid 0x0000000B (expected 1, got %d)", type); + return NULL; + } + topo->smt = ebx & 0xFFFF; + + eax = 0x0000000B; + ecx = 0x00000001; + cpuid(&eax, &ebx, &ecx, &edx); + type = (ecx >> 8) & 0xFF; + if (type < 2) { + printBug("Unexpected type in cpuid 0x0000000B (expected < 2, got %d)", type); + return NULL; + } + topo->logical_cores = ebx & 0xFFFF; + topo->physical_cores = topo->logical_cores / topo->smt; + } + else { + printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels); + topo->physical_cores = 1; + topo->logical_cores = 1; + topo->smt = 1; + } + break; + case VENDOR_AMD: + if (cpu->maxExtendedLevels >= 0x80000008) { + eax = 0x80000008; + cpuid(&eax, &ebx, &ecx, &edx); + topo->logical_cores = (ecx & 0xFF) + 1; + + if (cpu->maxExtendedLevels >= 0x8000001E) { + eax = 0x8000001E; + cpuid(&eax, &ebx, &ecx, &edx); + topo->smt = ((ebx >> 8) & 0x03) + 1; + } + else { + printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x8000001E, cpu->maxLevels); + topo->smt = 1; + } + topo->physical_cores = topo->logical_cores / topo->smt; + } + else { + printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxLevels); + topo->physical_cores = 1; + topo->logical_cores = 1; + topo->smt = 1; + } + break; + default: + printBug("Cant get topology because VENDOR is empty"); + return NULL; + } + + // Ask the OS the total number of cores it sees + // If we have one socket, it will be same as the cpuid, + // but in dual socket it will not! + #ifdef _WIN32 + SYSTEM_INFO info; + GetSystemInfo(&info); + topo->total_cores = info.dwNumberOfProcessors; + #else + if((topo->total_cores = sysconf(_SC_NPROCESSORS_ONLN)) == -1) { + perror("sysconf"); + topo->total_cores = topo->logical_cores; // fallback + } + #endif + topo->sockets = topo->total_cores / topo->smt / topo->physical_cores; // Idea borrowed from lscpu + + return topo; +} + +struct cache* get_cache_info(struct cpuInfo* cpu) { + struct cache* cach = malloc(sizeof(struct cache)); + uint32_t eax = 0; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + uint32_t level; + + // We use standart 0x00000004 for Intel + // We use extended 0x8000001D for AMD + if(cpu->cpu_vendor == VENDOR_INTEL) { + level = 0x00000004; + if(cpu->maxLevels < level) { + printErr("Can't read cache information from cpuid (needed level is %d, max is %d)", level, cpu->maxLevels); + return NULL; + } + } + else { + level = 0x8000001D; + if(cpu->maxExtendedLevels < level) { + printErr("Can't read cache information from cpuid (needed extended level is %d, max is %d)", level, cpu->maxExtendedLevels); + return NULL; + } + } + + // We suppose there are 4 caches (at most) + for(int i=0; i < 4; i++) { + eax = level; // get cache info + ebx = 0; + ecx = i; // cache id + edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + int32_t cache_type = eax & 0x1F; + + // If its 0, we tried fetching a non existing cache + if (cache_type > 0) { + int32_t cache_level = (eax >>= 5) & 0x7; + int32_t cache_is_self_initializing = (eax >>= 3) & 0x1; // does not need SW initialization + int32_t cache_is_fully_associative = (eax >>= 1) & 0x1; + uint32_t cache_sets = ecx + 1; + uint32_t cache_coherency_line_size = (ebx & 0xFFF) + 1; + uint32_t cache_physical_line_partitions = ((ebx >>= 12) & 0x3FF) + 1; + uint32_t cache_ways_of_associativity = ((ebx >>= 10) & 0x3FF) + 1; + + int32_t cache_total_size = cache_ways_of_associativity * cache_physical_line_partitions * cache_coherency_line_size * cache_sets; + + switch (cache_type) { + case 1: // Data Cache (We assume this is L1d) + if(cache_level != 1) { + printBug("Found data cache at level %d (expected 1)", cache_level); + return NULL; + } + cach->L1d = cache_total_size; + break; + + case 2: // Instruction Cache (We assume this is L1i) + if(cache_level != 1) { + printBug("Found instruction cache at level %d (expected 1)", cache_level); + return NULL; + } + cach->L1i = cache_total_size; + break; + + case 3: // Unified Cache (This may be L2 or L3) + if(cache_level == 2) cach->L2 = cache_total_size; + else if(cache_level == 3) cach->L3 = cache_total_size; + else { + printBug("Found unified cache at level %d (expected == 2 or 3)", cache_level); + return NULL; + } + break; + + default: // Unknown Type Cache + printBug("Unknown Type Cache found at ID %d", i); + return NULL; + } + } + else if(i == 2) cach->L2 = UNKNOWN; + else if(i == 3) cach->L3 = UNKNOWN; + else { + printBug("Could not find cache ID %d", i); + return NULL; + } + } + + // Sanity checks. If we read values greater than this, they can't be valid ones + // The values were chosen by me + if(cach->L1i > 64 * 1024) { + printBug("Invalid L1i size: %dKB\n", cach->L1i/1024); + return NULL; + } + if(cach->L1d > 64 * 1024) { + printBug("Invalid L1d size: %dKB\n", cach->L1d/1024); + return NULL; + } + if(cach->L2 != UNKNOWN && cach->L2 > 2 * 1048576) { + printBug("Invalid L2 size: %dMB\n", cach->L2/(1048576)); + return NULL; + } + if(cach->L3 != UNKNOWN && cach->L3 > 100 * 1048576) { + printBug("Invalid L3 size: %dMB\n", cach->L3/(1048576)); + return NULL; + } + + return cach; +} + +struct frequency* get_frequency_info(struct cpuInfo* cpu) { + struct frequency* freq = malloc(sizeof(struct frequency)); + + if(cpu->maxLevels < 0x16) { + #ifdef _WIN32 + printErr("Can't read frequency information from cpuid (needed level is %d, max is %d)", 0x16, cpu->maxLevels); + freq->base = UNKNOWN; + freq->max = UNKNOWN; + #else + printWarn("Can't read frequency information from cpuid (needed level is %d, max is %d). Using udev", 0x16, cpu->maxLevels); + freq->base = UNKNOWN; + freq->max = get_max_freq_from_file(); + #endif + } + else { + uint32_t eax = 0x16; + uint32_t ebx = 0; + uint32_t ecx = 0; + uint32_t edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + freq->base = eax; + freq->max = ebx; + } + + return freq; +} + +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); + printf("L1d=%dB\n",cach->L1d); + printf("L2=%dB\n",cach->L2); + printf("L3=%dB\n",cach->L3); +} + +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) { + /*** + PP = PeakPerformance + SP = SinglePrecision + + PP(SP) = + N_CORES * + FREQUENCY * + 2(Two vector units) * + 2(If cpu has fma) * + 16(If AVX512), 8(If AVX), 4(If SSE) * + + ***/ + + //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) { + snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN); + return string; + } + + double flops = topo->physical_cores*(freq*1000000); + + // Intel USUALLY has two VPUs. I have never seen an AMD + // with two VPUs. + if(cpu->cpu_vendor == VENDOR_INTEL) flops = flops * 2; + + if(cpu->FMA3 || cpu->FMA4) + flops = flops*2; + + if(cpu->AVX512) + flops = flops*16; + else if(cpu->AVX || cpu->AVX2) + flops = flops*8; + else if(cpu->SSE) + flops = flops*4; + + 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_topology(struct topology* topo) { + char* string; + if(topo->smt > 1) { + //3 for digits, 8 for ' cores (', 3 for digits, 9 for ' threads)' + uint32_t size = 3+8+3+9+1; + string = malloc(sizeof(char)*size); + snprintf(string, size, "%d cores (%d threads)",topo->physical_cores,topo->logical_cores); + } + else { + uint32_t size = 3+7+1; + string = malloc(sizeof(char)*size); + snprintf(string, size, "%d cores",topo->physical_cores); + } + 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)*15+1); + if(!cpu->AVX) + snprintf(string,2+1,"No"); + else if(!cpu->AVX2) + snprintf(string,3+1,"AVX"); + else if(!cpu->AVX512) + snprintf(string,8+1,"AVX,AVX2"); + else + snprintf(string,15+1,"AVX,AVX2,AVX512"); + + return string; +} + +char* get_str_sse(struct cpuInfo* cpu) { + uint32_t last = 0; + uint32_t SSE_sl = 4; + uint32_t SSE2_sl = 5; + uint32_t SSE3_sl = 5; + uint32_t SSSE3_sl = 6; + uint32_t SSE4a_sl = 6; + uint32_t SSE4_1_sl = 7; + uint32_t SSE4_2_sl = 7; + char* string = malloc(sizeof(char)*SSE_sl+SSE2_sl+SSE3_sl+SSSE3_sl+SSE4a_sl+SSE4_1_sl+SSE4_2_sl+1); + + if(cpu->SSE) { + snprintf(string+last,SSE_sl+1,"SSE,"); + last+=SSE_sl; + } + if(cpu->SSE2) { + snprintf(string+last,SSE2_sl+1,"SSE2,"); + last+=SSE2_sl; + } + if(cpu->SSE3) { + snprintf(string+last,SSE3_sl+1,"SSE3,"); + last+=SSE3_sl; + } + if(cpu->SSSE3) { + snprintf(string+last,SSSE3_sl+1,"SSSE3,"); + last+=SSSE3_sl; + } + if(cpu->SSE4a) { + snprintf(string+last,SSE4a_sl+1,"SSE4a,"); + last+=SSE4a_sl; + } + if(cpu->SSE4_1) { + snprintf(string+last,SSE4_1_sl+1,"SSE4_1,"); + last+=SSE4_1_sl; + } + if(cpu->SSE4_2) { + snprintf(string+last,SSE4_2_sl+1,"SSE4_2,"); + last+=SSE4_2_sl; + } + + //Purge last comma + string[last-1] = '\0'; + return string; +} + +char* get_str_fma(struct cpuInfo* cpu) { + char* string = malloc(sizeof(char)*9+1); + if(!cpu->FMA3) + snprintf(string,2+1,"No"); + else if(!cpu->FMA4) + snprintf(string,4+1,"FMA3"); + else + snprintf(string,9+1,"FMA3,FMA4"); + + 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; +} + +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; +} + +int32_t get_value_as_smallest_unit(char ** str, uint32_t value) { + int32_t sanity_ret; + *str = malloc(sizeof(char)* 7); //4 for digits, 2 for units + + if(value/1024 >= 1024) + sanity_ret = snprintf(*str, 6,"%d"STRING_MEGABYTES,value/(1<<20)); + else + sanity_ret = snprintf(*str, 6,"%d"STRING_KILOBYTES,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\n", 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'\n", tmp); + return NULL; + } + free(tmp); + return string; +} + +char* get_str_cache(int32_t cache_size, struct topology* topo, bool llc) { + if(llc) { + if(topo->sockets == 1) + return get_str_cache_one(cache_size); + else + return get_str_cache_two(cache_size, topo->sockets); + } + else + return get_str_cache_two(cache_size, topo->physical_cores); +} + +char* get_str_l1i(struct cache* cach, struct topology* topo) { + return get_str_cache(cach->L1i, topo, false); +} + +char* get_str_l1d(struct cache* cach, struct topology* topo) { + return get_str_cache(cach->L1d, topo, false); +} + +char* get_str_l2(struct cache* cach, struct topology* topo) { + if(cach->L2 == UNKNOWN) { + char* string = malloc(sizeof(char) * 5); + snprintf(string, 5, STRING_NONE); + return string; + } + return get_str_cache(cach->L2, topo, false); +} + +char* get_str_l3(struct cache* cach, struct topology* topo) { + if(cach->L3 == UNKNOWN) { + char* string = malloc(sizeof(char) * 5); + snprintf(string, 5, STRING_NONE); + return string; + } + return get_str_cache(cach->L3, topo, true); +} + +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) + 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 print_levels(struct cpuInfo* cpu, char* cpu_name) { + printf("%s\n", cpu_name); + printf("- Max standart level: 0x%.8X\n", cpu->maxLevels); + printf("- Max extended level: 0x%.8X\n", cpu->maxExtendedLevels); +} + +void free_topo_struct(struct topology* topo) { + free(topo); +} + +void free_cache_struct(struct cache* cach) { + free(cach); +} + +void free_freq_struct(struct frequency* freq) { + free(freq); } diff --git a/src/cpuid.h b/src/cpuid.h index 4ca8b4a..bc1b7a0 100644 --- a/src/cpuid.h +++ b/src/cpuid.h @@ -3,6 +3,55 @@ #include -void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); +#define VENDOR_EMPTY 0 +#define VENDOR_INTEL 1 +#define VENDOR_AMD 2 +#define VENDOR_INVALID 3 + +#define UNKNOWN -1 + +struct cpuInfo; +struct frequency; +struct cache; +struct topology; + +typedef int32_t VENDOR; + +struct cpuInfo* get_cpu_info(); +VENDOR get_cpu_vendor(struct cpuInfo* cpu); +int64_t get_freq(struct frequency* freq); +struct cache* get_cache_info(struct cpuInfo* cpu); +struct frequency* get_frequency_info(struct cpuInfo* cpu); +struct topology* get_topology_info(struct cpuInfo* cpu); + +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, struct topology* topo); +char* get_str_l1d(struct cache* cach, struct topology* topo); +char* get_str_l2(struct cache* cach, struct topology* topo); +char* get_str_l3(struct cache* cach, struct topology* topo); + +char* get_str_freq(struct frequency* freq); + +char* get_str_topology(struct topology* topo); + +char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq); + +void print_levels(struct cpuInfo* cpu, char* cpu_name); + +void free_cpuinfo_struct(struct cpuInfo* cpu); +void free_cache_struct(struct cache* cach); +void free_topo_struct(struct topology* topo); +void free_freq_struct(struct frequency* freq); + +void debug_cpu_info(struct cpuInfo* cpu); +void debug_cache(struct cache* cach); +void debug_frequency(struct frequency* freq); #endif diff --git a/src/cpuid_asm.c b/src/cpuid_asm.c new file mode 100644 index 0000000..0f24bc5 --- /dev/null +++ b/src/cpuid_asm.c @@ -0,0 +1,10 @@ +#include "cpuid_asm.h" + +void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { + __asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} diff --git a/src/cpuid_asm.h b/src/cpuid_asm.h new file mode 100644 index 0000000..1727e90 --- /dev/null +++ b/src/cpuid_asm.h @@ -0,0 +1,8 @@ +#ifndef __CPUID_ASM__ +#define __CPUID_ASM__ + +#include + +void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); + +#endif diff --git a/src/extended.c b/src/extended.c deleted file mode 100644 index ae45cbc..0000000 --- a/src/extended.c +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include "extended.h" - -char* get_str_cpu_name() { - uint32_t eax = 0; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - - char *name = malloc(sizeof(char)*64); - memset(name, 0, 64); - - //First, check we can use extended - eax = 0x80000000; - cpuid(&eax, &ebx, &ecx, &edx); - if(eax < 0x80000001) { - char* none = malloc(sizeof(char)*64); - sprintf(none,"Unknown"); - return none; - } - - //We can, fetch name - eax = 0x80000002; - cpuid(&eax, &ebx, &ecx, &edx); - - name[__COUNTER__] = eax & MASK; - name[__COUNTER__] = (eax>>8) & MASK; - name[__COUNTER__] = (eax>>16) & MASK; - name[__COUNTER__] = (eax>>24) & MASK; - name[__COUNTER__] = ebx & MASK; - name[__COUNTER__] = (ebx>>8) & MASK; - name[__COUNTER__] = (ebx>>16) & MASK; - name[__COUNTER__] = (ebx>>24) & MASK; - name[__COUNTER__] = ecx & MASK; - name[__COUNTER__] = (ecx>>8) & MASK; - name[__COUNTER__] = (ecx>>16) & MASK; - name[__COUNTER__] = (ecx>>24) & MASK; - name[__COUNTER__] = edx & MASK; - name[__COUNTER__] = (edx>>8) & MASK; - name[__COUNTER__] = (edx>>16) & MASK; - name[__COUNTER__] = (edx>>24) & MASK; - - eax = 0x80000003; - cpuid(&eax, &ebx, &ecx, &edx); - - name[__COUNTER__] = eax & MASK; - name[__COUNTER__] = (eax>>8) & MASK; - name[__COUNTER__] = (eax>>16) & MASK; - name[__COUNTER__] = (eax>>24) & MASK; - name[__COUNTER__] = ebx & MASK; - name[__COUNTER__] = (ebx>>8) & MASK; - name[__COUNTER__] = (ebx>>16) & MASK; - name[__COUNTER__] = (ebx>>24) & MASK; - name[__COUNTER__] = ecx & MASK; - name[__COUNTER__] = (ecx>>8) & MASK; - name[__COUNTER__] = (ecx>>16) & MASK; - name[__COUNTER__] = (ecx>>24) & MASK; - name[__COUNTER__] = edx & MASK; - name[__COUNTER__] = (edx>>8) & MASK; - name[__COUNTER__] = (edx>>16) & MASK; - name[__COUNTER__] = (edx>>24) & MASK; - - eax = 0x80000004; - cpuid(&eax, &ebx, &ecx, &edx); - - name[__COUNTER__] = eax & MASK; - name[__COUNTER__] = (eax>>8) & MASK; - name[__COUNTER__] = (eax>>16) & MASK; - name[__COUNTER__] = (eax>>24) & MASK; - name[__COUNTER__] = ebx & MASK; - name[__COUNTER__] = (ebx>>8) & MASK; - name[__COUNTER__] = (ebx>>16) & MASK; - name[__COUNTER__] = (ebx>>24) & MASK; - name[__COUNTER__] = ecx & MASK; - name[__COUNTER__] = (ecx>>8) & MASK; - name[__COUNTER__] = (ecx>>16) & MASK; - name[__COUNTER__] = (ecx>>24) & MASK; - name[__COUNTER__] = edx & MASK; - name[__COUNTER__] = (edx>>8) & MASK; - name[__COUNTER__] = (edx>>16) & MASK; - name[__COUNTER__] = (edx>>24) & MASK; - - name[__COUNTER__] = '\0'; - - //Remove unused characters - char *str = name; - char *dest = name; - while (*str != '\0') { - while (*str == ' ' && *(str + 1) == ' ') str++; - *dest++ = *str++; - } - *dest = '\0'; - - return name; -} diff --git a/src/extended.h b/src/extended.h deleted file mode 100644 index 6a9c29f..0000000 --- a/src/extended.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __EXTENDED__ -#define __EXTENDED__ - -#define MASK 0xFF -#include "cpuid.h" -#include -#include - -char* get_str_cpu_name(); - -#endif diff --git a/src/main.c b/src/main.c index 212364c..aa42f22 100644 --- a/src/main.c +++ b/src/main.c @@ -3,8 +3,7 @@ #include "args.h" #include "printer.h" -#include "standart.h" -#include "extended.h" +#include "cpuid.h" #include "global.h" /*** @@ -68,11 +67,10 @@ int main(int argc, char* argv[]) { struct cpuInfo* cpu = get_cpu_info(); if(cpu == NULL) return EXIT_FAILURE; - char* cpuName = get_str_cpu_name(); if(show_levels()) { print_version(); - print_levels(cpu, cpuName); + print_levels(cpu, get_str_cpu_name(cpu)); return EXIT_SUCCESS; } @@ -88,58 +86,8 @@ int main(int argc, char* argv[]) { if(topo == NULL) return EXIT_FAILURE; - struct ascii* art = set_ascii(get_cpu_vendor(cpu),get_style()); - if(art == NULL) + if(print_cpufetch(cpu, cach, freq, topo, get_style())) + return EXIT_SUCCESS; + else return EXIT_FAILURE; - - char* maxFrequency = get_str_freq(freq); - char* nCores = get_str_topology(topo); - char* avx = get_str_avx(cpu); - char* sse = get_str_sse(cpu); - char* fma = get_str_fma(cpu); - char* aes = get_str_aes(cpu); - char* sha = get_str_sha(cpu); - char* l1i = get_str_l1i(cach, topo); - char* l1d = get_str_l1d(cach, topo); - char* l2 = get_str_l2(cach, topo); - char* l3 = get_str_l3(cach, topo); - char* pp = get_str_peak_performance(cpu,topo,get_freq(freq)); - - setAttribute(art,ATTRIBUTE_NAME,cpuName); - setAttribute(art,ATTRIBUTE_FREQUENCY,maxFrequency); - setAttribute(art,ATTRIBUTE_NCORES,nCores); - setAttribute(art,ATTRIBUTE_AVX,avx); - setAttribute(art,ATTRIBUTE_SSE,sse); - setAttribute(art,ATTRIBUTE_FMA,fma); - setAttribute(art,ATTRIBUTE_AES,aes); - setAttribute(art,ATTRIBUTE_SHA,sha); - setAttribute(art,ATTRIBUTE_L1i,l1i); - setAttribute(art,ATTRIBUTE_L1d,l1d); - setAttribute(art,ATTRIBUTE_L2,l2); - setAttribute(art,ATTRIBUTE_L3,l3); - setAttribute(art,ATTRIBUTE_PEAK,pp); - - print_ascii(art); - - free(cpuName); - free(maxFrequency); - free(nCores); - free(avx); - free(sse); - free(fma); - free(aes); - free(sha); - free(l1i); - free(l1d); - free(l2); - free(l3); - free(pp); - - free(cpu); - free(art); - free_cache_struct(cach); - free_topo_struct(topo); - free_freq_struct(freq); - - return EXIT_SUCCESS; } diff --git a/src/printer.c b/src/printer.c index 66346d7..54ed916 100644 --- a/src/printer.c +++ b/src/printer.c @@ -36,6 +36,23 @@ #define LINES_SPACE_UP 3 #define LINES_SPACE_DOWN 4 +#define ATTRIBUTE_COUNT 13 +#define ATTRIBUTE_NAME 0 +#define ATTRIBUTE_FREQUENCY 1 +#define ATTRIBUTE_NCORES 2 +#define ATTRIBUTE_AVX 3 +#define ATTRIBUTE_SSE 4 +#define ATTRIBUTE_FMA 5 +#define ATTRIBUTE_AES 6 +#define ATTRIBUTE_SHA 7 +#define ATTRIBUTE_L1i 8 +#define ATTRIBUTE_L1d 9 +#define ATTRIBUTE_L2 10 +#define ATTRIBUTE_L3 11 +#define ATTRIBUTE_PEAK 12 + +static const int STYLES_CODE_LIST [STYLES_COUNT] = {STYLE_DEFAULT, STYLE_DARK}; + static const char* ATTRIBUTE_FIELDS [ATTRIBUTE_COUNT] = { TITLE_NAME, TITLE_FREQUENCY, TITLE_NCORES, TITLE_AVX, TITLE_SSE, TITLE_FMA, TITLE_AES, TITLE_SHA, @@ -186,3 +203,61 @@ void print_ascii(struct ascii* art) { else print_ascii_amd(art); } + +bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* freq, struct topology* topo, STYLE s) { + struct ascii* art = set_ascii(get_cpu_vendor(cpu),s); + if(art == NULL) + return false; + + char* cpu_name = get_str_cpu_name(cpu); + char* max_frequency = get_str_freq(freq); + char* nCores = get_str_topology(topo); + char* avx = get_str_avx(cpu); + char* sse = get_str_sse(cpu); + char* fma = get_str_fma(cpu); + char* aes = get_str_aes(cpu); + char* sha = get_str_sha(cpu); + char* l1i = get_str_l1i(cach, topo); + char* l1d = get_str_l1d(cach, topo); + char* l2 = get_str_l2(cach, topo); + char* l3 = get_str_l3(cach, topo); + char* pp = get_str_peak_performance(cpu,topo,get_freq(freq)); + + setAttribute(art,ATTRIBUTE_NAME,cpu_name); + setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency); + setAttribute(art,ATTRIBUTE_NCORES,nCores); + setAttribute(art,ATTRIBUTE_AVX,avx); + setAttribute(art,ATTRIBUTE_SSE,sse); + setAttribute(art,ATTRIBUTE_FMA,fma); + setAttribute(art,ATTRIBUTE_AES,aes); + setAttribute(art,ATTRIBUTE_SHA,sha); + setAttribute(art,ATTRIBUTE_L1i,l1i); + setAttribute(art,ATTRIBUTE_L1d,l1d); + setAttribute(art,ATTRIBUTE_L2,l2); + setAttribute(art,ATTRIBUTE_L3,l3); + setAttribute(art,ATTRIBUTE_PEAK,pp); + + print_ascii(art); + + free(cpu_name); + free(max_frequency); + free(nCores); + free(avx); + free(sse); + free(fma); + free(aes); + free(sha); + free(l1i); + free(l1d); + free(l2); + free(l3); + free(pp); + + free(cpu); + free(art); + free_cache_struct(cach); + free_topo_struct(topo); + free_freq_struct(freq); + + return true; +} diff --git a/src/printer.h b/src/printer.h index e34eaad..7af2842 100644 --- a/src/printer.h +++ b/src/printer.h @@ -1,23 +1,7 @@ #ifndef __PRINTER__ #define __PRINTER__ -#include "standart.h" -#include "ascii.h" - -#define ATTRIBUTE_COUNT 13 -#define ATTRIBUTE_NAME 0 -#define ATTRIBUTE_FREQUENCY 1 -#define ATTRIBUTE_NCORES 2 -#define ATTRIBUTE_AVX 3 -#define ATTRIBUTE_SSE 4 -#define ATTRIBUTE_FMA 5 -#define ATTRIBUTE_AES 6 -#define ATTRIBUTE_SHA 7 -#define ATTRIBUTE_L1i 8 -#define ATTRIBUTE_L1d 9 -#define ATTRIBUTE_L2 10 -#define ATTRIBUTE_L3 11 -#define ATTRIBUTE_PEAK 12 +#include "cpuid.h" typedef int STYLE; #define STYLES_COUNT 3 @@ -28,11 +12,6 @@ typedef int STYLE; #define STYLE_DARK 1 #define STYLE_NONE 2 -struct ascii; - -static const int STYLES_CODE_LIST [STYLES_COUNT] = {STYLE_DEFAULT, STYLE_DARK}; -struct ascii* set_ascii(VENDOR cpuVendor, STYLE style); -void print_ascii(struct ascii* art); -void setAttribute(struct ascii* art, int type, char* value); +bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* freq, struct topology* topo, STYLE s); #endif diff --git a/src/standart.c b/src/standart.c deleted file mode 100644 index ad46c04..0000000 --- a/src/standart.c +++ /dev/null @@ -1,778 +0,0 @@ -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#include "udev.h" -#endif - -#include "standart.h" -#include "cpuid.h" -#include "global.h" - -#define VENDOR_INTEL_STRING "GenuineIntel" -#define VENDOR_AMD_STRING "AuthenticAMD" - -#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 MASK 0xFF - -/* - * cpuid reference: http://www.sandpile.org/x86/cpuid.htm - * cpuid amd: https://www.amd.com/system/files/TechDocs/25481.pdf - */ - -struct cpuInfo { - bool AVX; - bool AVX2; - bool AVX512; - bool SSE; - bool SSE2; - bool SSE3; - bool SSSE3; - bool SSE4a; - bool SSE4_1; - bool SSE4_2; - bool FMA3; - bool FMA4; - bool AES; - bool SHA; - - VENDOR cpu_vendor; - - // Max cpuids levels - uint32_t maxLevels; - // Max cpuids extended levels - uint32_t maxExtendedLevels; -}; - -struct cache { - int32_t L1i; - int32_t L1d; - int32_t L2; - int32_t L3; -}; - -struct frequency { - int64_t base; - int64_t max; -}; - -struct topology { - int64_t total_cores; - uint32_t physical_cores; - uint32_t logical_cores; - uint32_t smt; - uint32_t sockets; - bool ht; -}; - -void init_cpu_info(struct cpuInfo* cpu) { - cpu->AVX = false; - cpu->AVX2 = false; - cpu->AVX512 = false; - cpu->SSE = false; - cpu->SSE2 = false; - cpu->SSE3 = false; - cpu->SSSE3 = false; - cpu->SSE4a = false; - cpu->SSE4_1 = false; - cpu->SSE4_2 = false; - cpu->FMA3 = false; - cpu->FMA4 = false; - cpu->AES = false; - cpu->SHA = false; -} - -void get_cpu_vendor_internal(char* name, uint32_t ebx,uint32_t ecx,uint32_t edx) { - name[__COUNTER__] = ebx & MASK; - name[__COUNTER__] = (ebx>>8) & MASK; - name[__COUNTER__] = (ebx>>16) & MASK; - name[__COUNTER__] = (ebx>>24) & MASK; - - name[__COUNTER__] = edx & MASK; - name[__COUNTER__] = (edx>>8) & MASK; - name[__COUNTER__] = (edx>>16) & MASK; - name[__COUNTER__] = (edx>>24) & MASK; - - name[__COUNTER__] = ecx & MASK; - name[__COUNTER__] = (ecx>>8) & MASK; - name[__COUNTER__] = (ecx>>16) & MASK; - name[__COUNTER__] = (ecx>>24) & MASK; -} - -struct cpuInfo* get_cpu_info() { - struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); - init_cpu_info(cpu); - uint32_t eax = 0; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - - //Get max cpuid level - cpuid(&eax, &ebx, &ecx, &edx); - cpu->maxLevels = eax; - - //Fill vendor - char name[13]; - memset(name,0,13); - get_cpu_vendor_internal(name, ebx, ecx, edx); - - if(strcmp(VENDOR_INTEL_STRING,name) == 0) - cpu->cpu_vendor = VENDOR_INTEL; - else if (strcmp(VENDOR_AMD_STRING,name) == 0) - cpu->cpu_vendor = VENDOR_AMD; - else { - cpu->cpu_vendor = VENDOR_INVALID; - printErr("Unknown CPU vendor: %s", name); - return NULL; - } - - //Get max extended level - eax = 0x80000000; - ebx = 0; - ecx = 0; - edx = 0; - cpuid(&eax, &ebx, &ecx, &edx); - cpu->maxExtendedLevels = eax; - - //Fill instructions support - if (cpu->maxLevels >= 0x00000001){ - eax = 0x00000001; - cpuid(&eax, &ebx, &ecx, &edx); - cpu->SSE = (edx & ((int)1 << 25)) != 0; - cpu->SSE2 = (edx & ((int)1 << 26)) != 0; - cpu->SSE3 = (ecx & ((int)1 << 0)) != 0; - - cpu->SSSE3 = (ecx & ((int)1 << 9)) != 0; - cpu->SSE4_1 = (ecx & ((int)1 << 19)) != 0; - cpu->SSE4_2 = (ecx & ((int)1 << 20)) != 0; - - cpu->AES = (ecx & ((int)1 << 25)) != 0; - - cpu->AVX = (ecx & ((int)1 << 28)) != 0; - cpu->FMA3 = (ecx & ((int)1 << 12)) != 0; - } - else { - printWarn("Can't read features information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels); - } - - if (cpu->maxLevels >= 0x00000007){ - eax = 0x00000007; - ecx = 0x00000000; - cpuid(&eax, &ebx, &ecx, &edx); - cpu->AVX2 = (ebx & ((int)1 << 5)) != 0; - cpu->SHA = (ebx & ((int)1 << 29)) != 0; - cpu->AVX512 = (((ebx & ((int)1 << 16)) != 0) || - ((ebx & ((int)1 << 28)) != 0) || - ((ebx & ((int)1 << 26)) != 0) || - ((ebx & ((int)1 << 27)) != 0) || - ((ebx & ((int)1 << 31)) != 0) || - ((ebx & ((int)1 << 30)) != 0) || - ((ebx & ((int)1 << 17)) != 0) || - ((ebx & ((int)1 << 21)) != 0)); - } - else { - printWarn("Can't read features information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000007, cpu->maxLevels); - } - - if (cpu->maxExtendedLevels >= 0x80000001){ - eax = 0x80000001; - cpuid(&eax, &ebx, &ecx, &edx); - cpu->SSE4a = (ecx & ((int)1 << 6)) != 0; - cpu->FMA4 = (ecx & ((int)1 << 16)) != 0; - } - else { - printWarn("Can't read features information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000001, cpu->maxExtendedLevels); - } - - return cpu; -} - -// 80/2/20 -struct topology* get_topology_info(struct cpuInfo* cpu) { - struct topology* topo = malloc(sizeof(struct topology)); - uint32_t eax = 0; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - int32_t type; - - if (cpu->maxLevels >= 0x00000001) { - eax = 0x00000001; - cpuid(&eax, &ebx, &ecx, &edx); - topo->ht = edx & (1 << 28); - } - else { - printWarn("Can't read HT information from cpuid (needed level is 0x%.8X, max is 0x%.8X). Assuming HT is disabled", 0x00000001, cpu->maxLevels); - topo->ht = false; - } - - switch(cpu->cpu_vendor) { - case VENDOR_INTEL: - if (cpu->maxLevels >= 0x0000000B) { - eax = 0x0000000B; - ecx = 0x00000000; - cpuid(&eax, &ebx, &ecx, &edx); - type = (ecx >> 8) & 0xFF; - if (type != 1) { - printBug("Unexpected type in cpuid 0x0000000B (expected 1, got %d)", type); - return NULL; - } - topo->smt = ebx & 0xFFFF; - - eax = 0x0000000B; - ecx = 0x00000001; - cpuid(&eax, &ebx, &ecx, &edx); - type = (ecx >> 8) & 0xFF; - if (type < 2) { - printBug("Unexpected type in cpuid 0x0000000B (expected < 2, got %d)", type); - return NULL; - } - topo->logical_cores = ebx & 0xFFFF; - topo->physical_cores = topo->logical_cores / topo->smt; - } - else { - printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels); - topo->physical_cores = 1; - topo->logical_cores = 1; - topo->smt = 1; - } - break; - case VENDOR_AMD: - if (cpu->maxExtendedLevels >= 0x80000008) { - eax = 0x80000008; - cpuid(&eax, &ebx, &ecx, &edx); - topo->logical_cores = (ecx & 0xFF) + 1; - - if (cpu->maxExtendedLevels >= 0x8000001E) { - eax = 0x8000001E; - cpuid(&eax, &ebx, &ecx, &edx); - topo->smt = ((ebx >> 8) & 0x03) + 1; - } - else { - printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x8000001E, cpu->maxLevels); - topo->smt = 1; - } - topo->physical_cores = topo->logical_cores / topo->smt; - } - else { - printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxLevels); - topo->physical_cores = 1; - topo->logical_cores = 1; - topo->smt = 1; - } - break; - default: - printBug("Cant get topology because VENDOR is empty"); - return NULL; - } - - // Ask the OS the total number of cores it sees - // If we have one socket, it will be same as the cpuid, - // but in dual socket it will not! - #ifdef _WIN32 - SYSTEM_INFO info; - GetSystemInfo(&info); - topo->total_cores = info.dwNumberOfProcessors; - #else - if((topo->total_cores = sysconf(_SC_NPROCESSORS_ONLN)) == -1) { - perror("sysconf"); - topo->total_cores = topo->logical_cores; // fallback - } - #endif - topo->sockets = topo->total_cores / topo->smt / topo->physical_cores; // Idea borrowed from lscpu - - return topo; -} - -struct cache* get_cache_info(struct cpuInfo* cpu) { - struct cache* cach = malloc(sizeof(struct cache)); - uint32_t eax = 0; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - uint32_t level; - - // We use standart 0x00000004 for Intel - // We use extended 0x8000001D for AMD - if(cpu->cpu_vendor == VENDOR_INTEL) { - level = 0x00000004; - if(cpu->maxLevels < level) { - printErr("Can't read cache information from cpuid (needed level is %d, max is %d)", level, cpu->maxLevels); - return NULL; - } - } - else { - level = 0x8000001D; - if(cpu->maxExtendedLevels < level) { - printErr("Can't read cache information from cpuid (needed extended level is %d, max is %d)", level, cpu->maxExtendedLevels); - return NULL; - } - } - - // We suppose there are 4 caches (at most) - for(int i=0; i < 4; i++) { - eax = level; // get cache info - ebx = 0; - ecx = i; // cache id - edx = 0; - - cpuid(&eax, &ebx, &ecx, &edx); - - int32_t cache_type = eax & 0x1F; - - // If its 0, we tried fetching a non existing cache - if (cache_type > 0) { - int32_t cache_level = (eax >>= 5) & 0x7; - int32_t cache_is_self_initializing = (eax >>= 3) & 0x1; // does not need SW initialization - int32_t cache_is_fully_associative = (eax >>= 1) & 0x1; - uint32_t cache_sets = ecx + 1; - uint32_t cache_coherency_line_size = (ebx & 0xFFF) + 1; - uint32_t cache_physical_line_partitions = ((ebx >>= 12) & 0x3FF) + 1; - uint32_t cache_ways_of_associativity = ((ebx >>= 10) & 0x3FF) + 1; - - int32_t cache_total_size = cache_ways_of_associativity * cache_physical_line_partitions * cache_coherency_line_size * cache_sets; - - switch (cache_type) { - case 1: // Data Cache (We assume this is L1d) - if(cache_level != 1) { - printBug("Found data cache at level %d (expected 1)", cache_level); - return NULL; - } - cach->L1d = cache_total_size; - break; - - case 2: // Instruction Cache (We assume this is L1i) - if(cache_level != 1) { - printBug("Found instruction cache at level %d (expected 1)", cache_level); - return NULL; - } - cach->L1i = cache_total_size; - break; - - case 3: // Unified Cache (This may be L2 or L3) - if(cache_level == 2) cach->L2 = cache_total_size; - else if(cache_level == 3) cach->L3 = cache_total_size; - else { - printBug("Found unified cache at level %d (expected == 2 or 3)", cache_level); - return NULL; - } - break; - - default: // Unknown Type Cache - printBug("Unknown Type Cache found at ID %d", i); - return NULL; - } - } - else if(i == 2) cach->L2 = UNKNOWN; - else if(i == 3) cach->L3 = UNKNOWN; - else { - printBug("Could not find cache ID %d", i); - return NULL; - } - } - - // Sanity checks. If we read values greater than this, they can't be valid ones - // The values were chosen by me - if(cach->L1i > 64 * 1024) { - printBug("Invalid L1i size: %dKB\n", cach->L1i/1024); - return NULL; - } - if(cach->L1d > 64 * 1024) { - printBug("Invalid L1d size: %dKB\n", cach->L1d/1024); - return NULL; - } - if(cach->L2 != UNKNOWN && cach->L2 > 2 * 1048576) { - printBug("Invalid L2 size: %dMB\n", cach->L2/(1048576)); - return NULL; - } - if(cach->L3 != UNKNOWN && cach->L3 > 100 * 1048576) { - printBug("Invalid L3 size: %dMB\n", cach->L3/(1048576)); - return NULL; - } - - return cach; -} - -struct frequency* get_frequency_info(struct cpuInfo* cpu) { - struct frequency* freq = malloc(sizeof(struct frequency)); - - if(cpu->maxLevels < 0x16) { - #ifdef _WIN32 - printErr("Can't read frequency information from cpuid (needed level is %d, max is %d)", 0x16, cpu->maxLevels); - freq->base = UNKNOWN; - freq->max = UNKNOWN; - #else - printWarn("Can't read frequency information from cpuid (needed level is %d, max is %d). Using udev", 0x16, cpu->maxLevels); - freq->base = UNKNOWN; - freq->max = get_max_freq_from_file(); - #endif - } - else { - uint32_t eax = 0x16; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - - cpuid(&eax, &ebx, &ecx, &edx); - - freq->base = eax; - freq->max = ebx; - } - - return freq; -} - -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); - printf("L1d=%dB\n",cach->L1d); - printf("L2=%dB\n",cach->L2); - printf("L3=%dB\n",cach->L3); -} - -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) { - /*** - PP = PeakPerformance - SP = SinglePrecision - - PP(SP) = - N_CORES * - FREQUENCY * - 2(Two vector units) * - 2(If cpu has fma) * - 16(If AVX512), 8(If AVX), 4(If SSE) * - - ***/ - - //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) { - snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN); - return string; - } - - double flops = topo->physical_cores*(freq*1000000); - - // Intel USUALLY has two VPUs. I have never seen an AMD - // with two VPUs. - if(cpu->cpu_vendor == VENDOR_INTEL) flops = flops * 2; - - if(cpu->FMA3 || cpu->FMA4) - flops = flops*2; - - if(cpu->AVX512) - flops = flops*16; - else if(cpu->AVX || cpu->AVX2) - flops = flops*8; - else if(cpu->SSE) - flops = flops*4; - - 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_topology(struct topology* topo) { - char* string; - if(topo->smt > 1) { - //3 for digits, 8 for ' cores (', 3 for digits, 9 for ' threads)' - uint32_t size = 3+8+3+9+1; - string = malloc(sizeof(char)*size); - snprintf(string, size, "%d cores (%d threads)",topo->physical_cores,topo->logical_cores); - } - else { - uint32_t size = 3+7+1; - string = malloc(sizeof(char)*size); - snprintf(string, size, "%d cores",topo->physical_cores); - } - return string; -} - -char* get_str_avx(struct cpuInfo* cpu) { - //If all AVX are available, it will use up to 15 - char* string = malloc(sizeof(char)*15+1); - if(!cpu->AVX) - snprintf(string,2+1,"No"); - else if(!cpu->AVX2) - snprintf(string,3+1,"AVX"); - else if(!cpu->AVX512) - snprintf(string,8+1,"AVX,AVX2"); - else - snprintf(string,15+1,"AVX,AVX2,AVX512"); - - return string; -} - -char* get_str_sse(struct cpuInfo* cpu) { - uint32_t last = 0; - uint32_t SSE_sl = 4; - uint32_t SSE2_sl = 5; - uint32_t SSE3_sl = 5; - uint32_t SSSE3_sl = 6; - uint32_t SSE4a_sl = 6; - uint32_t SSE4_1_sl = 7; - uint32_t SSE4_2_sl = 7; - char* string = malloc(sizeof(char)*SSE_sl+SSE2_sl+SSE3_sl+SSSE3_sl+SSE4a_sl+SSE4_1_sl+SSE4_2_sl+1); - - if(cpu->SSE) { - snprintf(string+last,SSE_sl+1,"SSE,"); - last+=SSE_sl; - } - if(cpu->SSE2) { - snprintf(string+last,SSE2_sl+1,"SSE2,"); - last+=SSE2_sl; - } - if(cpu->SSE3) { - snprintf(string+last,SSE3_sl+1,"SSE3,"); - last+=SSE3_sl; - } - if(cpu->SSSE3) { - snprintf(string+last,SSSE3_sl+1,"SSSE3,"); - last+=SSSE3_sl; - } - if(cpu->SSE4a) { - snprintf(string+last,SSE4a_sl+1,"SSE4a,"); - last+=SSE4a_sl; - } - if(cpu->SSE4_1) { - snprintf(string+last,SSE4_1_sl+1,"SSE4_1,"); - last+=SSE4_1_sl; - } - if(cpu->SSE4_2) { - snprintf(string+last,SSE4_2_sl+1,"SSE4_2,"); - last+=SSE4_2_sl; - } - - //Purge last comma - string[last-1] = '\0'; - return string; -} - -char* get_str_fma(struct cpuInfo* cpu) { - char* string = malloc(sizeof(char)*9+1); - if(!cpu->FMA3) - snprintf(string,2+1,"No"); - else if(!cpu->FMA4) - snprintf(string,4+1,"FMA3"); - else - snprintf(string,9+1,"FMA3,FMA4"); - - 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; -} - -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; -} - -int32_t get_value_as_smallest_unit(char ** str, uint32_t value) { - int32_t sanity_ret; - *str = malloc(sizeof(char)* 7); //4 for digits, 2 for units - - if(value/1024 >= 1024) - sanity_ret = snprintf(*str, 6,"%d"STRING_MEGABYTES,value/(1<<20)); - else - sanity_ret = snprintf(*str, 6,"%d"STRING_KILOBYTES,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\n", 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'\n", tmp); - return NULL; - } - free(tmp); - return string; -} - -char* get_str_cache(int32_t cache_size, struct topology* topo, bool llc) { - if(llc) { - if(topo->sockets == 1) - return get_str_cache_one(cache_size); - else - return get_str_cache_two(cache_size, topo->sockets); - } - else - return get_str_cache_two(cache_size, topo->physical_cores); -} - -char* get_str_l1i(struct cache* cach, struct topology* topo) { - return get_str_cache(cach->L1i, topo, false); -} - -char* get_str_l1d(struct cache* cach, struct topology* topo) { - return get_str_cache(cach->L1d, topo, false); -} - -char* get_str_l2(struct cache* cach, struct topology* topo) { - if(cach->L2 == UNKNOWN) { - char* string = malloc(sizeof(char) * 5); - snprintf(string, 5, STRING_NONE); - return string; - } - return get_str_cache(cach->L2, topo, false); -} - -char* get_str_l3(struct cache* cach, struct topology* topo) { - if(cach->L3 == UNKNOWN) { - char* string = malloc(sizeof(char) * 5); - snprintf(string, 5, STRING_NONE); - return string; - } - return get_str_cache(cach->L3, topo, true); -} - -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) - 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 print_levels(struct cpuInfo* cpu, char* cpu_name) { - printf("%s\n", cpu_name); - printf("- Max standart level: 0x%.8X\n", cpu->maxLevels); - printf("- Max extended level: 0x%.8X\n", cpu->maxExtendedLevels); -} - -void free_topo_struct(struct topology* topo) { - free(topo); -} - -void free_cache_struct(struct cache* cach) { - free(cach); -} - -void free_freq_struct(struct frequency* freq) { - free(freq); -} diff --git a/src/standart.h b/src/standart.h deleted file mode 100644 index 6bca7cb..0000000 --- a/src/standart.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __01h__ -#define __01h__ - -#include - -#define VENDOR_EMPTY 0 -#define VENDOR_INTEL 1 -#define VENDOR_AMD 2 -#define VENDOR_INVALID 3 - -#define UNKNOWN -1 - -struct cpuInfo; -struct frequency; -struct cache; -struct topology; - -typedef int32_t VENDOR; - -struct cpuInfo* get_cpu_info(); -VENDOR get_cpu_vendor(struct cpuInfo* cpu); -int64_t get_freq(struct frequency* freq); -struct cache* get_cache_info(struct cpuInfo* cpu); -struct frequency* get_frequency_info(struct cpuInfo* cpu); -struct topology* get_topology_info(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, struct topology* topo); -char* get_str_l1d(struct cache* cach, struct topology* topo); -char* get_str_l2(struct cache* cach, struct topology* topo); -char* get_str_l3(struct cache* cach, struct topology* topo); - -char* get_str_freq(struct frequency* freq); - -char* get_str_topology(struct topology* topo); - -char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq); - -void print_levels(struct cpuInfo* cpu, char* cpu_name); - -void free_cpuinfo_struct(struct cpuInfo* cpu); -void free_cache_struct(struct cache* cach); -void free_topo_struct(struct topology* topo); -void free_freq_struct(struct frequency* freq); - -void debug_cpu_info(struct cpuInfo* cpu); -void debug_cache(struct cache* cach); -void debug_frequency(struct frequency* freq); - -#endif diff --git a/src/udev.c b/src/udev.c index d66e731..92b87f5 100644 --- a/src/udev.c +++ b/src/udev.c @@ -6,7 +6,7 @@ #include #include "global.h" -#include "standart.h" +#include "cpuid.h" #define _PATH_SYS_SYSTEM "/sys/devices/system" #define _PATH_SYS_CPU _PATH_SYS_SYSTEM"/cpu"