diff --git a/src/global.c b/src/global.c index 165e2d6..89620a3 100644 --- a/src/global.c +++ b/src/global.c @@ -13,4 +13,5 @@ void printError(const char *fmt, ...) { vsnprintf(buffer,buffer_size, fmt, args); va_end(args); fprintf(stderr,RED "ERROR: "RESET "%s\n",buffer); + fprintf(stderr,"Please, create a new issue with this error message and your CPU in https://github.com/Dr-Noob/cpufetch/issues\n"); } diff --git a/src/main.c b/src/main.c index ba7c9ff..27d9295 100644 --- a/src/main.c +++ b/src/main.c @@ -25,7 +25,7 @@ Peak FLOPS: 512 GFLOP/s(in simple precision) ***/ -static const char* VERSION = "0.34"; +static const char* VERSION = "0.4"; void print_help(int argc, char *argv[]) { printf("Usage: %s [--version] [--help] [--style STYLE]\n\ @@ -61,7 +61,13 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; struct cache* cach = get_cache_info(); + if(cach == NULL) + return EXIT_FAILURE; + struct frequency* freq = get_frequency_info(); + if(freq == NULL) + return EXIT_FAILURE; + struct ascii* art = set_ascii(get_cpu_vendor(cpu),getStyle()); if(art == NULL) return EXIT_FAILURE; diff --git a/src/standart.c b/src/standart.c index bff2f34..a501d2a 100644 --- a/src/standart.c +++ b/src/standart.c @@ -8,6 +8,7 @@ #include "standart.h" #include "cpuid.h" #include "udev.h" +#include "global.h" #define STRING_YES "Yes" #define STRING_NO "No" @@ -46,6 +47,13 @@ struct cpuInfo { unsigned int maxExtendedLevels; }; +struct cache { + int L1i; + int L1d; + int L2; + int L3; +}; + void init_cpu_info(struct cpuInfo* cpu) { cpu->AVX = false; cpu->AVX2 = false; @@ -178,6 +186,70 @@ struct cpuInfo* get_cpu_info() { return cpu; } +// see https://stackoverflow.com/questions/12594208/c-program-to-determine-levels-size-of-cache +struct cache* get_cache_info() { + struct cache* cach = malloc(sizeof(struct cache)); + unsigned int eax, ebx, ecx, edx; + + // We suppose there are 4 caches (at most) + for(int i=0; i < 4; i++) { + eax = 4; // get cache info + ebx = 0; + ecx = i; // cache id + edx = 0; + + cpuid(&eax, &ebx, &ecx, &edx); + + int cache_type = eax & 0x1F; + + // If its 0, we tried fetching a non existing cache + if (cache_type > 0) { + int cache_level = (eax >>= 5) & 0x7; + int cache_is_self_initializing = (eax >>= 3) & 0x1; // does not need SW initialization + int cache_is_fully_associative = (eax >>= 1) & 0x1; + unsigned int cache_sets = ecx + 1; + unsigned int cache_coherency_line_size = (ebx & 0xFFF) + 1; + unsigned int cache_physical_line_partitions = ((ebx >>= 12) & 0x3FF) + 1; + unsigned int cache_ways_of_associativity = ((ebx >>= 10) & 0x3FF) + 1; + + int 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) { + printError("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) { + printError("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 { + printError("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); + return NULL; + } + } + } + + return cach; +} + VENDOR get_cpu_vendor(struct cpuInfo* cpu) { return cpu->cpu_vendor; } @@ -202,6 +274,13 @@ void debug_cpu_info(struct cpuInfo* cpu) { printf("SHA=%s\n", cpu->SHA ? "true" : "false"); } +void debugCache(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); +} + /*** STRING FUNCTIONS ***/ char* get_str_peak_performance(struct cpuInfo* cpu, long freq) { @@ -355,3 +434,46 @@ char* get_str_sha(struct cpuInfo* cpu) { snprintf(string,2+1,STRING_NO); return string; } + +// String functions +char* get_str_l1(struct cache* cach) { + //Max 2 digits,2 for 'KB',3 for '(D)' and '(I)' + int size = (2*(2+2)+6+1); + char* string = malloc(sizeof(char)*size); + snprintf(string,size,"%d"STRING_KILOBYTES"(D)%d"STRING_KILOBYTES"(I)",cach->L1d/1024,cach->L1i/1024); + return string; +} + +char* get_str_l2(struct cache* cach) { + if(cach->L2 == UNKNOWN) { + char* string = malloc(sizeof(char)*5); + snprintf(string,5,STRING_NONE); + return string; + } + else { + //Max 4 digits and 2 for 'KB' + int size = (4+2+1); + char* string = malloc(sizeof(char)*size); + snprintf(string,size,"%d"STRING_KILOBYTES,cach->L2/1024); + return string; + } +} + +char* get_str_l3(struct cache* cach) { + if(cach->L3 == UNKNOWN) { + char* string = malloc(sizeof(char)*5); + snprintf(string,5,STRING_NONE); + return string; + } + else { + //Max 4 digits and 2 for 'KB' + int size = (4+2+1); + char* string = malloc(sizeof(char)*size); + snprintf(string,size,"%d"STRING_KILOBYTES,cach->L3/1024); + return string; + } +} + +void free_cache_struct(struct cache* cach) { + free(cach); +} diff --git a/src/standart.h b/src/standart.h index 9b32e55..9ede436 100644 --- a/src/standart.h +++ b/src/standart.h @@ -8,10 +8,12 @@ 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); + char* get_str_ncores(struct cpuInfo* cpu); char* get_str_avx(struct cpuInfo* cpu); char* get_str_sse(struct cpuInfo* cpu); @@ -19,6 +21,14 @@ char* get_str_fma(struct cpuInfo* cpu); char* get_str_aes(struct cpuInfo* cpu); char* get_str_sha(struct cpuInfo* cpu); +char* get_str_l1(struct cache* cach); +char* get_str_l2(struct cache* cach); +char* get_str_l3(struct cache* cach); + +void free_cpuinfo_struct(struct cpuInfo* cpu); +void free_cache_struct(struct cache* cach); + void debug_cpu_info(struct cpuInfo* cpu); +void debugCache(struct cache* cach); #endif diff --git a/src/udev.c b/src/udev.c index d256b1c..7ae60d7 100644 --- a/src/udev.c +++ b/src/udev.c @@ -14,19 +14,6 @@ #define _PATH_FREQUENCY_MAX _PATH_FREQUENCY"/cpuinfo_max_freq" #define _PATH_FREQUENCY_MIN _PATH_FREQUENCY"/cpuinfo_min_freq" -#define _PATH_CPU_CACHE _PATH_ONE_CPU"/cache" -#define _PATH_CACHE_L1d _PATH_CPU_CACHE"/index0/size" -#define _PATH_CACHE_L1i _PATH_CPU_CACHE"/index1/size" -#define _PATH_CACHE_L2 _PATH_CPU_CACHE"/index2/size" -#define _PATH_CACHE_L3 _PATH_CPU_CACHE"/index3/size" - -struct cache { - int L1i; - int L1d; - int L2; - int L3; -}; - struct frequency { long max; long min; @@ -49,37 +36,6 @@ int getSize(char* buf, int size) { return cachsize; } -// Returns size(in bytes) of cache described by path or UNKNOWN if the cache doest no exists -//TODO: We use reads in various places, refactor -int getCache(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 = DEFAULT_BLOCK_SIZE; - char* buf = malloc(sizeof(char)*DEFAULT_FILE_SIZE); - memset(buf, 0, sizeof(char)*DEFAULT_FILE_SIZE); - - do { - bytes_read = read(fd, buf+offset, block); - offset += bytes_read; - } while(bytes_read > 0); - - //Move size from kb to bytes - int ret = getSize(buf,offset)*1024; - free(buf); - fclose(file); - - return ret; -} - // Returns CPU frequency in Hz long get_freq_from_file(char* path) { FILE *file = fopen(path, "r"); @@ -115,46 +71,6 @@ long get_freq(struct frequency* freq) { return freq->max; } -// String functions -char* get_str_l1(struct cache* cach) { - //Max 2 digits,2 for 'KB',6 for '(Data)' - //and 14 for '(Instructions)' - int size = (2*(2+2)+6+14+1); - char* string = malloc(sizeof(char)*size); - snprintf(string,size,"%d"STRING_KILOBYTES"(Data)%d"STRING_KILOBYTES"(Instructions)",cach->L1d/1024,cach->L1i/1024); - return string; -} - -char* get_str_l2(struct cache* cach) { - if(cach->L2 == UNKNOWN) { - char* string = malloc(sizeof(char)*5); - snprintf(string,5,STRING_NONE); - return string; - } - else { - //Max 4 digits and 2 for 'KB' - int size = (4+2+1); - char* string = malloc(sizeof(char)*size); - snprintf(string,size,"%d"STRING_KILOBYTES,cach->L2/1024); - return string; - } -} - -char* get_str_l3(struct cache* cach) { - if(cach->L3 == UNKNOWN) { - char* string = malloc(sizeof(char)*5); - snprintf(string,5,STRING_NONE); - return string; - } - else { - //Max 4 digits and 2 for 'KB' - int size = (4+2+1); - char* string = malloc(sizeof(char)*size); - snprintf(string,size,"%d"STRING_KILOBYTES,cach->L3/1024); - return string; - } -} - 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); @@ -169,17 +85,6 @@ char* get_str_freq(struct frequency* freq) { return string; } -struct cache* get_cache_info() { - struct cache* cach = malloc(sizeof(struct cache)); - - cach->L1i = getCache(_PATH_CACHE_L1i); - cach->L1d = getCache(_PATH_CACHE_L1d); - cach->L2 = getCache(_PATH_CACHE_L2); - cach->L3 = getCache(_PATH_CACHE_L3); - - return cach; -} - struct frequency* get_frequency_info() { struct frequency* freq = malloc(sizeof(struct frequency)); @@ -189,21 +94,10 @@ struct frequency* get_frequency_info() { return freq; } -void free_cache_struct(struct cache* cach) { - free(cach); -} - void free_freq_struct(struct frequency* freq) { free(freq); } -void debugCache(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 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 index eed1c5a..84c491b 100644 --- a/src/udev.h +++ b/src/udev.h @@ -11,21 +11,12 @@ #define STRING_GIGAHERZ "GHz" #define STRING_KILOBYTES "KB" -struct cache; -struct frequency; - -struct cache* get_cache_info(); struct frequency* get_frequency_info(); -void free_cache_struct(struct cache* cach); void free_freq_struct(struct frequency* freq); -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); long get_freq(struct frequency* freq); void debugFrequency(struct frequency* freq); -void debugCache(struct cache* cach); #endif