mirror of
https://github.com/Dr-Noob/cpufetch.git
synced 2026-03-25 16:00:39 +01:00
Fetch cache info from cpuid, instead of asking Linux (using /proc)
This commit is contained in:
@@ -13,4 +13,5 @@ void printError(const char *fmt, ...) {
|
|||||||
vsnprintf(buffer,buffer_size, fmt, args);
|
vsnprintf(buffer,buffer_size, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
fprintf(stderr,RED "ERROR: "RESET "%s\n",buffer);
|
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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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[]) {
|
void print_help(int argc, char *argv[]) {
|
||||||
printf("Usage: %s [--version] [--help] [--style STYLE]\n\
|
printf("Usage: %s [--version] [--help] [--style STYLE]\n\
|
||||||
@@ -61,7 +61,13 @@ int main(int argc, char* argv[]) {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
struct cache* cach = get_cache_info();
|
struct cache* cach = get_cache_info();
|
||||||
|
if(cach == NULL)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
struct frequency* freq = get_frequency_info();
|
struct frequency* freq = get_frequency_info();
|
||||||
|
if(freq == NULL)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
struct ascii* art = set_ascii(get_cpu_vendor(cpu),getStyle());
|
struct ascii* art = set_ascii(get_cpu_vendor(cpu),getStyle());
|
||||||
if(art == NULL)
|
if(art == NULL)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
122
src/standart.c
122
src/standart.c
@@ -8,6 +8,7 @@
|
|||||||
#include "standart.h"
|
#include "standart.h"
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
#include "udev.h"
|
#include "udev.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
#define STRING_YES "Yes"
|
#define STRING_YES "Yes"
|
||||||
#define STRING_NO "No"
|
#define STRING_NO "No"
|
||||||
@@ -46,6 +47,13 @@ struct cpuInfo {
|
|||||||
unsigned int maxExtendedLevels;
|
unsigned int maxExtendedLevels;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cache {
|
||||||
|
int L1i;
|
||||||
|
int L1d;
|
||||||
|
int L2;
|
||||||
|
int L3;
|
||||||
|
};
|
||||||
|
|
||||||
void init_cpu_info(struct cpuInfo* cpu) {
|
void init_cpu_info(struct cpuInfo* cpu) {
|
||||||
cpu->AVX = false;
|
cpu->AVX = false;
|
||||||
cpu->AVX2 = false;
|
cpu->AVX2 = false;
|
||||||
@@ -178,6 +186,70 @@ struct cpuInfo* get_cpu_info() {
|
|||||||
return cpu;
|
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) {
|
VENDOR get_cpu_vendor(struct cpuInfo* cpu) {
|
||||||
return cpu->cpu_vendor;
|
return cpu->cpu_vendor;
|
||||||
}
|
}
|
||||||
@@ -202,6 +274,13 @@ void debug_cpu_info(struct cpuInfo* cpu) {
|
|||||||
printf("SHA=%s\n", cpu->SHA ? "true" : "false");
|
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 ***/
|
/*** STRING FUNCTIONS ***/
|
||||||
|
|
||||||
char* get_str_peak_performance(struct cpuInfo* cpu, long freq) {
|
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);
|
snprintf(string,2+1,STRING_NO);
|
||||||
return string;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,10 +8,12 @@
|
|||||||
|
|
||||||
typedef int VENDOR;
|
typedef int VENDOR;
|
||||||
|
|
||||||
|
struct cache* get_cache_info();
|
||||||
struct cpuInfo* get_cpu_info();
|
struct cpuInfo* get_cpu_info();
|
||||||
VENDOR get_cpu_vendor(struct cpuInfo* cpu);
|
VENDOR get_cpu_vendor(struct cpuInfo* cpu);
|
||||||
|
|
||||||
char* get_str_peak_performance(struct cpuInfo* cpu, long freq);
|
char* get_str_peak_performance(struct cpuInfo* cpu, long freq);
|
||||||
|
|
||||||
char* get_str_ncores(struct cpuInfo* cpu);
|
char* get_str_ncores(struct cpuInfo* cpu);
|
||||||
char* get_str_avx(struct cpuInfo* cpu);
|
char* get_str_avx(struct cpuInfo* cpu);
|
||||||
char* get_str_sse(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_aes(struct cpuInfo* cpu);
|
||||||
char* get_str_sha(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 debug_cpu_info(struct cpuInfo* cpu);
|
||||||
|
void debugCache(struct cache* cach);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
106
src/udev.c
106
src/udev.c
@@ -14,19 +14,6 @@
|
|||||||
#define _PATH_FREQUENCY_MAX _PATH_FREQUENCY"/cpuinfo_max_freq"
|
#define _PATH_FREQUENCY_MAX _PATH_FREQUENCY"/cpuinfo_max_freq"
|
||||||
#define _PATH_FREQUENCY_MIN _PATH_FREQUENCY"/cpuinfo_min_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 {
|
struct frequency {
|
||||||
long max;
|
long max;
|
||||||
long min;
|
long min;
|
||||||
@@ -49,37 +36,6 @@ int getSize(char* buf, int size) {
|
|||||||
return cachsize;
|
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
|
// Returns CPU frequency in Hz
|
||||||
long get_freq_from_file(char* path) {
|
long get_freq_from_file(char* path) {
|
||||||
FILE *file = fopen(path, "r");
|
FILE *file = fopen(path, "r");
|
||||||
@@ -115,46 +71,6 @@ long get_freq(struct frequency* freq) {
|
|||||||
return freq->max;
|
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) {
|
char* get_str_freq(struct frequency* freq) {
|
||||||
//Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0'
|
//Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0'
|
||||||
unsigned int size = (4+3+1);
|
unsigned int size = (4+3+1);
|
||||||
@@ -169,17 +85,6 @@ char* get_str_freq(struct frequency* freq) {
|
|||||||
return string;
|
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* get_frequency_info() {
|
||||||
struct frequency* freq = malloc(sizeof(struct frequency));
|
struct frequency* freq = malloc(sizeof(struct frequency));
|
||||||
|
|
||||||
@@ -189,21 +94,10 @@ struct frequency* get_frequency_info() {
|
|||||||
return freq;
|
return freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_cache_struct(struct cache* cach) {
|
|
||||||
free(cach);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_freq_struct(struct frequency* freq) {
|
void free_freq_struct(struct frequency* freq) {
|
||||||
free(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) {
|
void debugFrequency(struct frequency* freq) {
|
||||||
printf("max f=%ldMhz\n",freq->max);
|
printf("max f=%ldMhz\n",freq->max);
|
||||||
printf("min f=%ldMhz\n",freq->min);
|
printf("min f=%ldMhz\n",freq->min);
|
||||||
|
|||||||
@@ -11,21 +11,12 @@
|
|||||||
#define STRING_GIGAHERZ "GHz"
|
#define STRING_GIGAHERZ "GHz"
|
||||||
#define STRING_KILOBYTES "KB"
|
#define STRING_KILOBYTES "KB"
|
||||||
|
|
||||||
struct cache;
|
|
||||||
struct frequency;
|
|
||||||
|
|
||||||
struct cache* get_cache_info();
|
|
||||||
struct frequency* get_frequency_info();
|
struct frequency* get_frequency_info();
|
||||||
void free_cache_struct(struct cache* cach);
|
|
||||||
void free_freq_struct(struct frequency* freq);
|
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);
|
char* get_str_freq(struct frequency* freq);
|
||||||
long get_freq(struct frequency* freq);
|
long get_freq(struct frequency* freq);
|
||||||
|
|
||||||
void debugFrequency(struct frequency* freq);
|
void debugFrequency(struct frequency* freq);
|
||||||
void debugCache(struct cache* cach);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user