Files
cpufetch/src/common/udev.c

245 lines
6.2 KiB
C

#include "udev.h"
#include "global.h"
#include "cpu.h"
// https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html
int get_ncores_from_cpuinfo() {
// Examples:
// 0-271
// 0-7
// 0
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUS_PRESENT, &filelen)) == NULL) {
printWarn("read_file: %s: %s\n", _PATH_CPUS_PRESENT, strerror(errno));
return -1;
}
int ncores;
char* tmp1;
if((tmp1 = strstr(buf, "-")) == NULL) {
// file contains no - character, we assume that it contains 0,
// which means that the CPU contains only one core
return 1;
}
else {
tmp1++;
}
char* tmp2 = strstr(buf, "\n");
char ncores_str[filelen];
memset(ncores_str, 0, sizeof(char) * filelen);
memcpy(ncores_str, tmp1, tmp2-tmp1);
char* end;
errno = 0;
ncores = strtol(ncores_str, &end, 10) + 1;
if(errno != 0) {
printWarn("strtol: %s:\n", strerror(errno));
return -1;
}
free(buf);
return ncores;
}
char* read_file(char* path, int* len) {
int fd = open(path, O_RDONLY);
if(fd == -1) {
return NULL;
}
//File exists, read it
int bytes_read = 0;
int offset = 0;
int block = 128;
int buf_size = block * 4;
char* buf = emalloc(sizeof(char) * buf_size);
memset(buf, 0, sizeof(char) * buf_size);
while ((bytes_read = read(fd, buf+offset, block)) > 0) {
offset += bytes_read;
if(offset + block > buf_size) {
buf = erealloc(buf, sizeof(char) * buf_size * 2);
memset(buf + buf_size, 0, sizeof(char) * buf_size);
buf_size = buf_size * 2;
}
}
if (close(fd) == -1) {
return NULL;
}
*len = offset;
return buf;
}
long get_freq_from_file(char* path) {
int filelen;
char* buf;
if((buf = read_file(path, &filelen)) == NULL) {
printWarn("Could not open '%s'", path);
return UNKNOWN_DATA;
}
char* end;
errno = 0;
long ret = strtol(buf, &end, 10);
if(errno != 0) {
printBug("strtol: %s", strerror(errno));
free(buf);
return UNKNOWN_DATA;
}
// We will be getting the frequency in KHz
// We consider it is an error if frequency is
// greater than 10 GHz or less than 100 MHz
if(ret > 10000 * 1000 || ret < 100 * 1000) {
printBug("Invalid data was read from file '%s': %ld\n", path, ret);
return UNKNOWN_DATA;
}
free(buf);
return ret/1000;
}
long get_cache_size_from_file(char* path) {
int filelen;
char* buf;
if((buf = read_file(path, &filelen)) == NULL) {
printWarn("Could not open '%s'", path);
return -1;
}
buf[filelen] = '\0'; // remove the K at the end
char* end;
errno = 0;
long ret = strtol(buf, &end, 10);
if(errno != 0) {
printBug("strtol: %s", strerror(errno));
free(buf);
return -1;
}
free(buf);
return ret * 1024;
}
long get_max_freq_from_file(uint32_t core) {
char path[_PATH_FREQUENCY_MAX_LEN];
sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_FREQUENCY, _PATH_FREQUENCY_MAX);
return get_freq_from_file(path);
}
long get_min_freq_from_file(uint32_t core) {
char path[_PATH_FREQUENCY_MAX_LEN];
sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_FREQUENCY, _PATH_FREQUENCY_MIN);
return get_freq_from_file(path);
}
long get_l1i_cache_size(uint32_t core) {
char path[_PATH_CACHE_MAX_LEN];
sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L1I, _PATH_CACHE_SIZE);
return get_cache_size_from_file(path);
}
long get_l1d_cache_size(uint32_t core) {
char path[_PATH_CACHE_MAX_LEN];
sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L1D, _PATH_CACHE_SIZE);
return get_cache_size_from_file(path);
}
long get_l2_cache_size(uint32_t core) {
char path[_PATH_CACHE_MAX_LEN];
sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L2, _PATH_CACHE_SIZE);
return get_cache_size_from_file(path);
}
long get_l3_cache_size(uint32_t core) {
char path[_PATH_CACHE_MAX_LEN];
sprintf(path, "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, core, _PATH_CACHE_L3, _PATH_CACHE_SIZE);
return get_cache_size_from_file(path);
}
int get_num_caches_from_files(char** paths, int num_paths) {
int SHARED_MAP_MAX_LEN = 8 + 1;
int filelen;
char* buf;
uint32_t* shared_maps = emalloc(sizeof(uint32_t *) * num_paths);
// 1. Read cpu_shared_map from every core
for(int i=0; i < num_paths; i++) {
if((buf = read_file(paths[i], &filelen)) == NULL) {
printWarn("Could not open '%s'", paths[i]);
return -1;
}
if(filelen > SHARED_MAP_MAX_LEN) {
printBug("Shared map length is %d while the max is be %d", filelen, SHARED_MAP_MAX_LEN);
return -1;
}
char* end;
errno = 0;
long ret = strtol(buf, &end, 16);
if(errno != 0) {
printBug("strtol: %s", strerror(errno));
free(buf);
return -1;
}
shared_maps[i] = (uint32_t) ret;
}
// 2. Count number of different masks; this is the number of caches
int num_caches = 0;
bool found = false;
uint32_t* unique_shared_maps = emalloc(sizeof(uint32_t *) * num_paths);
for(int i=0; i < num_paths; i++) unique_shared_maps[i] = 0;
for(int i=0; i < num_paths; i++) {
for(int j=0; j < num_paths && !found; j++) {
if(shared_maps[i] == unique_shared_maps[j]) found = true;
}
if(!found) {
unique_shared_maps[num_caches] = shared_maps[i];
num_caches++;
}
found = false;
}
return num_caches;
}
int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level) {
char** paths = emalloc(sizeof(char *) * cpu->topo->total_cores);
char* cache_path = NULL;
if(level == 0) cache_path = _PATH_CACHE_L1I;
else if(level == 1) cache_path = _PATH_CACHE_L1D;
else if(level == 2) cache_path = _PATH_CACHE_L2;
else if(level == 3) cache_path = _PATH_CACHE_L3;
else {
printBug("Found invalid cache level to inspect: %d\n", level);
return -1;
}
for(int i=0; i < cpu->topo->total_cores; i++) {
paths[i] = emalloc(sizeof(char) * _PATH_CACHE_MAX_LEN);
sprintf(paths[i], "%s%s/cpu%d%s%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, i, cache_path, _PATH_CACHE_SHARED_MAP);
}
int ret = get_num_caches_from_files(paths, cpu->topo->total_cores);
for(int i=0; i < cpu->topo->total_cores; i++)
free(paths[i]);
free(paths);
return ret;
}