From b81d611282c3281414dd0fb73b941b3844809345 Mon Sep 17 00:00:00 2001 From: Dr-Noob Date: Sat, 20 Jun 2020 13:24:50 +0200 Subject: [PATCH] Fetch freq from cpuid, instead of asking Linux (using /proc). This finally removes udev dependency. However, the support of cpuid 0x16 is limited, so this may break cpufetch on some systems --- Makefile | 4 +- src/global.c | 12 +++++- src/global.h | 3 +- src/main.c | 7 ++-- src/printer.c | 6 +-- src/standart.c | 91 ++++++++++++++++++++++++++++++++++++------- src/standart.h | 18 +++++++-- src/udev.c | 104 ------------------------------------------------- src/udev.h | 22 ----------- 9 files changed, 111 insertions(+), 156 deletions(-) delete mode 100644 src/udev.c delete mode 100644 src/udev.h diff --git a/Makefile b/Makefile index 11cd6a7..67f8995 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ CXXFLAGS=-g -Wall -Wextra -Werror -fstack-protector-all -pedantic -Wno-unused 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)udev.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)udev.h $(SRC_DIR)printer.h $(SRC_DIR)ascii.h $(SRC_DIR)args.h $(SRC_DIR)global.h +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 OUTPUT=cpufetch diff --git a/src/global.c b/src/global.c index 89620a3..681f010 100644 --- a/src/global.c +++ b/src/global.c @@ -5,7 +5,17 @@ #define RED "\x1b[31;1m" #define RESET "\x1b[0m" -void printError(const char *fmt, ...) { +void printErr(const char *fmt, ...) { + int buffer_size = 4096; + char buffer[buffer_size]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer,buffer_size, fmt, args); + va_end(args); + fprintf(stderr,RED "ERROR: "RESET "%s\n",buffer); +} + +void printBug(const char *fmt, ...) { int buffer_size = 4096; char buffer[buffer_size]; va_list args; diff --git a/src/global.h b/src/global.h index 429d065..0819b42 100644 --- a/src/global.h +++ b/src/global.h @@ -1,6 +1,7 @@ #ifndef __GLOBAL__ #define __GLOBAL__ -void printError(const char *fmt, ...); +void printErr(const char *fmt, ...); +void printBug(const char *fmt, ...); #endif diff --git a/src/main.c b/src/main.c index 27d9295..ba61ae7 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,6 @@ #include "args.h" #include "printer.h" #include "standart.h" -#include "udev.h" #include "extended.h" #include "global.h" @@ -25,7 +24,7 @@ Peak FLOPS: 512 GFLOP/s(in simple precision) ***/ -static const char* VERSION = "0.4"; +static const char* VERSION = "0.41"; void print_help(int argc, char *argv[]) { printf("Usage: %s [--version] [--help] [--style STYLE]\n\ @@ -60,11 +59,11 @@ int main(int argc, char* argv[]) { if(cpu == NULL) return EXIT_FAILURE; - struct cache* cach = get_cache_info(); + struct cache* cach = get_cache_info(cpu); if(cach == NULL) return EXIT_FAILURE; - struct frequency* freq = get_frequency_info(); + struct frequency* freq = get_frequency_info(cpu); if(freq == NULL) return EXIT_FAILURE; diff --git a/src/printer.c b/src/printer.c index 05011d2..b69fea1 100644 --- a/src/printer.c +++ b/src/printer.c @@ -67,7 +67,7 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style) { /*** Check that number of lines of ascii art matches the number of spaces plus the number of lines filled with text ***/ if(LINES_SPACE_UP+LINES_SPACE_DOWN+ATTRIBUTE_COUNT != NUMBER_OF_LINES) { - printError("Number of lines do not match (%d vs %d)",LINES_SPACE_UP+LINES_SPACE_DOWN+ATTRIBUTE_COUNT,NUMBER_OF_LINES); + printBug("Number of lines do not match (%d vs %d)",LINES_SPACE_UP+LINES_SPACE_DOWN+ATTRIBUTE_COUNT,NUMBER_OF_LINES); return NULL; } @@ -86,7 +86,7 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style) { strcpy(art->color2,COL_INTEL_DARK_2); break; default: - printError("Found invalid style (%d)",style); + printBug("Found invalid style (%d)",style); return NULL; } @@ -125,7 +125,7 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style) { strcpy(art->color2,COL_AMD_DARK_2); break; default: - printError("Found invalid style (%d)",style); + printBug("Found invalid style (%d)",style); return NULL; } diff --git a/src/standart.c b/src/standart.c index a501d2a..f5872ac 100644 --- a/src/standart.c +++ b/src/standart.c @@ -7,15 +7,21 @@ #include "standart.h" #include "cpuid.h" -#include "udev.h" #include "global.h" -#define STRING_YES "Yes" -#define STRING_NO "No" - #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 UNKNOWN -1 + /* * cpuid reference: http://www.sandpile.org/x86/cpuid.htm */ @@ -54,6 +60,11 @@ struct cache { int L3; }; +struct frequency { + long base; + long max; +}; + void init_cpu_info(struct cpuInfo* cpu) { cpu->AVX = false; cpu->AVX2 = false; @@ -103,10 +114,10 @@ struct cpuInfo* get_cpu_info() { struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); init_cpu_info(cpu); - unsigned eax = 0; - unsigned ebx = 0; - unsigned ecx = 0; - unsigned edx = 0; + unsigned int eax = 0; + unsigned int ebx = 0; + unsigned int ecx = 0; + unsigned int edx = 0; //Get max cpuid level eax = 0x0000000; @@ -187,7 +198,7 @@ struct cpuInfo* get_cpu_info() { } // see https://stackoverflow.com/questions/12594208/c-program-to-determine-levels-size-of-cache -struct cache* get_cache_info() { +struct cache* get_cache_info(struct cpuInfo* cpu) { struct cache* cach = malloc(sizeof(struct cache)); unsigned int eax, ebx, ecx, edx; @@ -217,7 +228,7 @@ struct cache* get_cache_info() { switch (cache_type) { case 1: // Data Cache (We assume this is L1d) if(cache_level != 1) { - printError("Found data cache at level %d (expected 1)", cache_level); + printBug("Found data cache at level %d (expected 1)", cache_level); return NULL; } cach->L1d = cache_total_size; @@ -225,7 +236,7 @@ struct cache* get_cache_info() { case 2: // Instruction Cache (We assume this is L1i) if(cache_level != 1) { - printError("Found instruction cache at level %d (expected 1)", cache_level); + printBug("Found instruction cache at level %d (expected 1)", cache_level); return NULL; } cach->L1i = cache_total_size; @@ -235,13 +246,13 @@ struct cache* get_cache_info() { if(cache_level == 2) cach->L2 = cache_total_size; else if(cache_level == 3) cach->L3 = cache_total_size; else { - printError("Found unified cache at level %d (expected == 2 or 3)", cache_level); + printBug("Found unified cache at level %d (expected == 2 or 3)", cache_level); return NULL; } break; default: // Unknown Type Cache - printError("Unknown Type Cache found at ID %d", i); + printBug("Unknown Type Cache found at ID %d", i); return NULL; } } @@ -250,6 +261,33 @@ struct cache* get_cache_info() { return cach; } +struct frequency* get_frequency_info(struct cpuInfo* cpu) { + struct frequency* freq = malloc(sizeof(struct frequency)); + + if(cpu->maxLevels < 0x16) { + 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 { + unsigned int eax = 0x16; + unsigned int ebx = 0; + unsigned int ecx = 0; + unsigned int edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + freq->base = eax; + freq->max = ebx; + } + + return freq; +} + +long get_freq(struct frequency* freq) { + return freq->max; +} + VENDOR get_cpu_vendor(struct cpuInfo* cpu) { return cpu->cpu_vendor; } @@ -274,13 +312,18 @@ void debug_cpu_info(struct cpuInfo* cpu) { printf("SHA=%s\n", cpu->SHA ? "true" : "false"); } -void debugCache(struct cache* cach) { +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) { + printf("max f=%ldMhz\n",freq->max); + printf("base f=%ldMhz\n",freq->base); +} + /*** STRING FUNCTIONS ***/ char* get_str_peak_performance(struct cpuInfo* cpu, long freq) { @@ -308,7 +351,7 @@ char* get_str_peak_performance(struct cpuInfo* cpu, long freq) { return string; } - float flops = (cpu->nThreads/cpu->HT)*freq*2; + float flops = (cpu->nThreads/cpu->HT)*(freq*1000000)*2; if(cpu->FMA3 || cpu->FMA4) flops = flops*2; @@ -474,6 +517,24 @@ 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' + unsigned int 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 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 index 9ede436..4086d9c 100644 --- a/src/standart.h +++ b/src/standart.h @@ -6,13 +6,17 @@ #define VENDOR_AMD 2 #define VENDOR_INVALID 3 +struct cpuInfo; +struct frequency; +struct cache; + typedef int VENDOR; -struct cache* get_cache_info(); struct cpuInfo* get_cpu_info(); VENDOR get_cpu_vendor(struct cpuInfo* cpu); - -char* get_str_peak_performance(struct cpuInfo* cpu, long freq); +long get_freq(struct frequency* freq); +struct cache* get_cache_info(struct cpuInfo* cpu); +struct frequency* get_frequency_info(struct cpuInfo* cpu); char* get_str_ncores(struct cpuInfo* cpu); char* get_str_avx(struct cpuInfo* cpu); @@ -25,10 +29,16 @@ char* get_str_l1(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_peak_performance(struct cpuInfo* cpu, long freq); + void free_cpuinfo_struct(struct cpuInfo* cpu); void free_cache_struct(struct cache* cach); +void free_freq_struct(struct frequency* freq); void debug_cpu_info(struct cpuInfo* cpu); -void debugCache(struct cache* cach); +void debug_cache(struct cache* cach); +void debug_frequency(struct frequency* freq); #endif diff --git a/src/udev.c b/src/udev.c deleted file mode 100644 index 7ae60d7..0000000 --- a/src/udev.c +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include -#include -#include - -#include "udev.h" - -#define _PATH_SYS_SYSTEM "/sys/devices/system" -#define _PATH_SYS_CPU _PATH_SYS_SYSTEM"/cpu" -#define _PATH_ONE_CPU _PATH_SYS_CPU"/cpu0" - -#define _PATH_FREQUENCY _PATH_ONE_CPU"/cpufreq" -#define _PATH_FREQUENCY_MAX _PATH_FREQUENCY"/cpuinfo_max_freq" -#define _PATH_FREQUENCY_MIN _PATH_FREQUENCY"/cpuinfo_min_freq" - -struct frequency { - long max; - long min; -}; - -// Parses buf which should be expressed in the way: xxxxK where 'x' are numbers and 'K' refers to kilobytes. -// Returns the size as a int in bytes -int getSize(char* buf, int size) { - char* end = strstr (buf,"K"); - if(end == NULL) { - printf("ERROR in getSize(strstr)\n"); - return UNKNOWN; - } - *end = 0; - int cachsize = atoi(buf); - if(cachsize == 0) { - printf("ERROR in getSize(atoi)\n"); - return UNKNOWN; - } - return cachsize; -} - -// Returns CPU frequency in Hz -long get_freq_from_file(char* path) { - FILE *file = fopen(path, "r"); - - if(file == NULL) { - //Doest not exist - return UNKNOWN; - } - - //File exists, read it - int fd = fileno(file); - int bytes_read = 0; - int offset = 0; - int block = 1; - 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 ret = atoi(buf); - free(buf); - if(ret == 0) { - printf("error in get_freq_from_file\n"); - return UNKNOWN; - } - fclose(file); - return (long)ret*1000; -} - -long get_freq(struct frequency* freq) { - return freq->max; -} - -char* get_str_freq(struct frequency* freq) { - //Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0' - unsigned int 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 >= 1000000000) - snprintf(string,size,"%.2f"STRING_GIGAHERZ,(float)(freq->max)/1000000000); - else - snprintf(string,size,"%.2f"STRING_MEGAHERZ,(float)(freq->max)/1000000); - return string; -} - -struct frequency* get_frequency_info() { - struct frequency* freq = malloc(sizeof(struct frequency)); - - freq->max = get_freq_from_file(_PATH_FREQUENCY_MAX); - freq->min = get_freq_from_file(_PATH_FREQUENCY_MIN); - - return freq; -} - -void free_freq_struct(struct frequency* freq) { - free(freq); -} - -void debugFrequency(struct frequency* freq) { - printf("max f=%ldMhz\n",freq->max); - printf("min f=%ldMhz\n",freq->min); -} diff --git a/src/udev.h b/src/udev.h deleted file mode 100644 index 84c491b..0000000 --- a/src/udev.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __UDEV__ -#define __UDEV__ - -#define UNKNOWN -1 -#define DEFAULT_FILE_SIZE 4096 -#define DEFAULT_BLOCK_SIZE 128 - -#define STRING_UNKNOWN "Unknown" -#define STRING_NONE "None" -#define STRING_MEGAHERZ "MHz" -#define STRING_GIGAHERZ "GHz" -#define STRING_KILOBYTES "KB" - -struct frequency* get_frequency_info(); -void free_freq_struct(struct frequency* freq); - -char* get_str_freq(struct frequency* freq); -long get_freq(struct frequency* freq); - -void debugFrequency(struct frequency* freq); - -#endif