mirror of
https://github.com/Dr-Noob/cpufetch.git
synced 2026-03-25 07:50:40 +01:00
[v0.98] Use malloc/calloc wrapper that exits when alloc fails, as suggested by #90
This commit is contained in:
168
src/x86/apic.c
168
src/x86/apic.c
@@ -60,7 +60,7 @@ uint32_t get_apic_id(bool x2apic_id) {
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
|
||||
|
||||
if(x2apic_id) {
|
||||
eax = 0x0000000B;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
@@ -92,12 +92,12 @@ bool bind_to_cpu(int cpu_id) {
|
||||
cpuset_t currentCPU;
|
||||
CPU_ZERO(¤tCPU);
|
||||
CPU_SET(cpu_id, ¤tCPU);
|
||||
if(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), ¤tCPU) == -1) {
|
||||
if(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), ¤tCPU) == -1) {
|
||||
perror("cpuset_setaffinity");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -109,51 +109,51 @@ bool fill_topo_masks_apic(struct topology* topo) {
|
||||
uint32_t core_plus_smt_id_max_cnt;
|
||||
uint32_t core_id_max_cnt;
|
||||
uint32_t smt_id_per_core_max_cnt;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
core_plus_smt_id_max_cnt = (ebx >> 16) & 0xFF;
|
||||
|
||||
|
||||
eax = 0x00000004;
|
||||
ecx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
core_id_max_cnt = (eax >> 26) + 1;
|
||||
smt_id_per_core_max_cnt = core_plus_smt_id_max_cnt / core_id_max_cnt;
|
||||
|
||||
topo->apic->smt_mask = create_mask(smt_id_per_core_max_cnt, &(topo->apic->smt_mask_width));
|
||||
smt_id_per_core_max_cnt = core_plus_smt_id_max_cnt / core_id_max_cnt;
|
||||
|
||||
topo->apic->smt_mask = create_mask(smt_id_per_core_max_cnt, &(topo->apic->smt_mask_width));
|
||||
topo->apic->core_mask = create_mask(core_id_max_cnt,&(topo->apic->pkg_mask_shift));
|
||||
topo->apic->pkg_mask_shift += topo->apic->smt_mask_width;
|
||||
topo->apic->core_mask <<= topo->apic->smt_mask_width;
|
||||
topo->apic->pkg_mask = (-1) ^ (topo->apic->core_mask | topo->apic->smt_mask);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fill_topo_masks_x2apic(struct topology* topo) {
|
||||
int32_t level_type;
|
||||
int32_t level_shift;
|
||||
|
||||
|
||||
int32_t coreplus_smt_mask = 0;
|
||||
bool level2 = false;
|
||||
bool level1 = false;
|
||||
|
||||
|
||||
uint32_t eax = 0;
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
|
||||
while(true) {
|
||||
eax = 0x0000000B;
|
||||
ecx = i;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
if(ebx == 0) break;
|
||||
|
||||
|
||||
level_type = (ecx >> 8) & 0xFF;
|
||||
level_shift = eax & 0xFFF;
|
||||
|
||||
switch(level_type) {
|
||||
level_shift = eax & 0xFFF;
|
||||
|
||||
switch(level_type) {
|
||||
case 1: // SMT
|
||||
topo->apic->smt_mask = ~(0xFFFFFFFF << level_shift);
|
||||
topo->apic->smt_mask_width = level_shift;
|
||||
@@ -170,10 +170,10 @@ bool fill_topo_masks_x2apic(struct topology* topo) {
|
||||
printErr("Found invalid level when querying topology: %d", level_type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
i++; // sublevel to query
|
||||
}
|
||||
|
||||
|
||||
if (level1 && level2) {
|
||||
topo->apic->core_mask = coreplus_smt_mask ^ topo->apic->smt_mask;
|
||||
}
|
||||
@@ -194,13 +194,13 @@ bool fill_topo_masks_x2apic(struct topology* topo) {
|
||||
// as the number of cores, but in the case of Xeon Phi KNL it is not
|
||||
uint32_t max_apic_id_size(uint32_t** cache_id_apic, struct topology* topo) {
|
||||
uint32_t max = 0;
|
||||
|
||||
|
||||
for(int i=0; i < topo->cach->max_cache_level; i++) {
|
||||
for(int j=0; j < topo->total_cores; j++) {
|
||||
for(int j=0; j < topo->total_cores; j++) {
|
||||
if(cache_id_apic[j][i] > max) max = cache_id_apic[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
max++;
|
||||
if(max > (uint32_t) topo->total_cores) return max;
|
||||
return topo->total_cores;
|
||||
@@ -208,15 +208,15 @@ uint32_t max_apic_id_size(uint32_t** cache_id_apic, struct topology* topo) {
|
||||
|
||||
bool build_topo_from_apic(uint32_t* apic_pkg, uint32_t* apic_smt, uint32_t** cache_id_apic, struct topology* topo) {
|
||||
uint32_t size = max_apic_id_size(cache_id_apic, topo);
|
||||
uint32_t* sockets = malloc(sizeof(uint32_t) * size);
|
||||
uint32_t* smt = malloc(sizeof(uint32_t) * size);
|
||||
uint32_t* apic_id = malloc(sizeof(uint32_t) * size);
|
||||
uint32_t* sockets = emalloc(sizeof(uint32_t) * size);
|
||||
uint32_t* smt = emalloc(sizeof(uint32_t) * size);
|
||||
uint32_t* apic_id = emalloc(sizeof(uint32_t) * size);
|
||||
uint32_t num_caches = 0;
|
||||
|
||||
|
||||
memset(sockets, 0, sizeof(uint32_t) * size);
|
||||
memset(smt, 0, sizeof(uint32_t) * size);
|
||||
memset(apic_id, 0, sizeof(uint32_t) * size);
|
||||
|
||||
memset(apic_id, 0, sizeof(uint32_t) * size);
|
||||
|
||||
// System topology
|
||||
for(int i=0; i < topo->total_cores; i++) {
|
||||
sockets[apic_pkg[i]] = 1;
|
||||
@@ -228,44 +228,44 @@ bool build_topo_from_apic(uint32_t* apic_pkg, uint32_t* apic_smt, uint32_t** cac
|
||||
if(smt[i] != 0)
|
||||
topo->smt_available++;
|
||||
}
|
||||
|
||||
|
||||
topo->logical_cores = topo->total_cores / topo->sockets;
|
||||
topo->physical_cores = topo->logical_cores / topo->smt_available;
|
||||
|
||||
|
||||
// Cache topology
|
||||
for(int i=0; i < topo->cach->max_cache_level; i++) {
|
||||
num_caches = 0;
|
||||
memset(apic_id, 0, sizeof(uint32_t) * size);
|
||||
|
||||
for(int c=0; c < topo->total_cores; c++) {
|
||||
|
||||
for(int c=0; c < topo->total_cores; c++) {
|
||||
apic_id[cache_id_apic[c][i]]++;
|
||||
}
|
||||
for(uint32_t c=0; c < size; c++) {
|
||||
for(uint32_t c=0; c < size; c++) {
|
||||
if(apic_id[c] > 0) num_caches++;
|
||||
}
|
||||
|
||||
|
||||
topo->cach->cach_arr[i]->num_caches = num_caches;
|
||||
}
|
||||
|
||||
|
||||
free(sockets);
|
||||
free(smt);
|
||||
free(apic_id);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void get_cache_topology_from_apic(struct topology* topo) {
|
||||
void get_cache_topology_from_apic(struct topology* topo) {
|
||||
uint32_t eax = 0x00000004;
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
|
||||
for(int i=0; i < topo->cach->max_cache_level; i++) {
|
||||
|
||||
for(int i=0; i < topo->cach->max_cache_level; i++) {
|
||||
eax = 0x00000004;
|
||||
ecx = i;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
uint32_t SMTMaxCntPerEachCache = ((eax >> 14) & 0x7FF) + 1;
|
||||
uint32_t dummy;
|
||||
topo->apic->cache_select_mask[i] = create_mask(SMTMaxCntPerEachCache,&dummy);
|
||||
@@ -289,15 +289,15 @@ void add_apic_to_array(uint32_t apic, uint32_t* apic_ids, int n) {
|
||||
if(apic_ids[i] != (uint32_t) -1) last = i+1;
|
||||
i++;
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
|
||||
if(!found) {
|
||||
apic_ids[last] = apic;
|
||||
//printf("Added %d\n", apic);
|
||||
}
|
||||
}
|
||||
|
||||
bool fill_apic_ids(uint32_t* apic_ids, int n, bool x2apic_id) {
|
||||
#ifdef __APPLE__
|
||||
#ifdef __APPLE__
|
||||
// macOS extremely dirty approach...
|
||||
printf("cpufetch is computing APIC IDs, please wait...\n");
|
||||
bool end = false;
|
||||
@@ -306,11 +306,11 @@ bool fill_apic_ids(uint32_t* apic_ids, int n, bool x2apic_id) {
|
||||
|
||||
while(!end) {
|
||||
apic = get_apic_id(x2apic_id);
|
||||
|
||||
|
||||
add_apic_to_array(apic, apic_ids, n);
|
||||
end = apic_array_full(apic_ids, n);
|
||||
end = apic_array_full(apic_ids, n);
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for(int i=0; i < n; i++) {
|
||||
if(!bind_to_cpu(i)) {
|
||||
@@ -323,14 +323,14 @@ bool fill_apic_ids(uint32_t* apic_ids, int n, bool x2apic_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
|
||||
uint32_t apic_id;
|
||||
uint32_t* apic_ids = malloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t* apic_pkg = malloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t* apic_core = malloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t* apic_smt = malloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t** cache_smt_id_apic = malloc(sizeof(uint32_t*) * topo->total_cores);
|
||||
uint32_t** cache_id_apic = malloc(sizeof(uint32_t*) * topo->total_cores);
|
||||
bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
|
||||
uint32_t apic_id;
|
||||
uint32_t* apic_ids = emalloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t* apic_pkg = emalloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t* apic_core = emalloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t* apic_smt = emalloc(sizeof(uint32_t) * topo->total_cores);
|
||||
uint32_t** cache_smt_id_apic = emalloc(sizeof(uint32_t*) * topo->total_cores);
|
||||
uint32_t** cache_id_apic = emalloc(sizeof(uint32_t*) * topo->total_cores);
|
||||
bool x2apic_id;
|
||||
|
||||
if(cpu->maxLevels >= 0x0000000B) {
|
||||
@@ -347,48 +347,48 @@ bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
|
||||
else {
|
||||
x2apic_id = false;
|
||||
}
|
||||
|
||||
|
||||
for(int i=0; i < topo->total_cores; i++) {
|
||||
cache_smt_id_apic[i] = malloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
cache_id_apic[i] = malloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
cache_smt_id_apic[i] = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
cache_id_apic[i] = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
}
|
||||
topo->apic->cache_select_mask = malloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
topo->apic->cache_id_apic = malloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
|
||||
topo->apic->cache_select_mask = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
topo->apic->cache_id_apic = emalloc(sizeof(uint32_t) * (topo->cach->max_cache_level));
|
||||
|
||||
if(x2apic_id) {
|
||||
if(!fill_topo_masks_x2apic(topo))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(!fill_topo_masks_apic(topo))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
get_cache_topology_from_apic(topo);
|
||||
|
||||
|
||||
get_cache_topology_from_apic(topo);
|
||||
|
||||
if(!fill_apic_ids(apic_ids, topo->total_cores, x2apic_id))
|
||||
return false;
|
||||
|
||||
for(int i=0; i < topo->total_cores; i++) {
|
||||
|
||||
for(int i=0; i < topo->total_cores; i++) {
|
||||
apic_id = apic_ids[i];
|
||||
|
||||
|
||||
apic_pkg[i] = (apic_id & topo->apic->pkg_mask) >> topo->apic->pkg_mask_shift;
|
||||
apic_core[i] = (apic_id & topo->apic->core_mask) >> topo->apic->smt_mask_width;
|
||||
apic_smt[i] = apic_id & topo->apic->smt_mask;
|
||||
|
||||
|
||||
for(int c=0; c < topo->cach->max_cache_level; c++) {
|
||||
cache_smt_id_apic[i][c] = apic_id & topo->apic->cache_select_mask[c];
|
||||
cache_id_apic[i][c] = apic_id & (-1 ^ topo->apic->cache_select_mask[c]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* DEBUG
|
||||
for(int i=0; i < topo->cach->max_cache_level; i++) {
|
||||
printf("[CACH %1d]", i);
|
||||
for(int j=0; j < topo->total_cores; j++)
|
||||
printf("[%03d]", cache_id_apic[j][i]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
for(int i=0; i < topo->total_cores; i++)
|
||||
printf("[%2d] 0x%.8X\n", i, apic_pkg[i]);
|
||||
printf("\n");
|
||||
@@ -397,16 +397,16 @@ bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
|
||||
printf("\n");
|
||||
for(int i=0; i < topo->total_cores; i++)
|
||||
printf("[%2d] 0x%.8X\n", i, apic_smt[i]);*/
|
||||
|
||||
|
||||
|
||||
|
||||
bool ret = build_topo_from_apic(apic_pkg, apic_smt, cache_id_apic, topo);
|
||||
|
||||
|
||||
// Assumption: If we cant get smt_available, we assume it is equal to smt_supported...
|
||||
if (!x2apic_id) {
|
||||
printWarn("Can't read SMT from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels);
|
||||
printWarn("Can't read SMT from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels);
|
||||
topo->smt_supported = topo->smt_available;
|
||||
}
|
||||
|
||||
|
||||
free(apic_pkg);
|
||||
free(apic_core);
|
||||
free(apic_smt);
|
||||
@@ -416,17 +416,17 @@ bool get_topology_from_apic(struct cpuInfo* cpu, struct topology* topo) {
|
||||
}
|
||||
free(cache_smt_id_apic);
|
||||
free(cache_id_apic);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t is_smt_enabled_amd(struct topology* topo) {
|
||||
#ifdef __APPLE__
|
||||
UNUSED(topo);
|
||||
return 1;
|
||||
#else
|
||||
#else
|
||||
uint32_t id;
|
||||
|
||||
|
||||
for(int i = 0; i < topo->total_cores; i++) {
|
||||
if(!bind_to_cpu(i)) {
|
||||
printErr("Failed binding to CPU %d", i);
|
||||
@@ -435,7 +435,7 @@ uint32_t is_smt_enabled_amd(struct topology* topo) {
|
||||
id = get_apic_id(false) & 1; // get the last bit
|
||||
if(id == 1) return 2; // We assume there isn't any AMD CPU with more than 2th per core.
|
||||
}
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
328
src/x86/cpuid.c
328
src/x86/cpuid.c
@@ -58,22 +58,22 @@ void init_topology_struct(struct topology* topo, struct cache* cach) {
|
||||
topo->smt_available = 0;
|
||||
topo->smt_supported = 0;
|
||||
topo->sockets = 0;
|
||||
topo->apic = malloc(sizeof(struct apic));
|
||||
topo->apic = emalloc(sizeof(struct apic));
|
||||
topo->cach = cach;
|
||||
}
|
||||
|
||||
void init_cache_struct(struct cache* cach) {
|
||||
cach->L1i = malloc(sizeof(struct cach));
|
||||
cach->L1d = malloc(sizeof(struct cach));
|
||||
cach->L2 = malloc(sizeof(struct cach));
|
||||
cach->L3 = malloc(sizeof(struct cach));
|
||||
|
||||
cach->cach_arr = malloc(sizeof(struct cach*) * 4);
|
||||
cach->L1i = emalloc(sizeof(struct cach));
|
||||
cach->L1d = emalloc(sizeof(struct cach));
|
||||
cach->L2 = emalloc(sizeof(struct cach));
|
||||
cach->L3 = emalloc(sizeof(struct cach));
|
||||
|
||||
cach->cach_arr = emalloc(sizeof(struct cach*) * 4);
|
||||
cach->cach_arr[0] = cach->L1i;
|
||||
cach->cach_arr[1] = cach->L1d;
|
||||
cach->cach_arr[2] = cach->L2;
|
||||
cach->cach_arr[3] = cach->L3;
|
||||
|
||||
|
||||
cach->max_cache_level = 0;
|
||||
cach->L1i->exists = false;
|
||||
cach->L1d->exists = false;
|
||||
@@ -83,7 +83,7 @@ void init_cache_struct(struct cache* cach) {
|
||||
|
||||
void get_name_cpuid(char* name, uint32_t reg1, uint32_t reg2, uint32_t reg3) {
|
||||
uint32_t c = 0;
|
||||
|
||||
|
||||
name[c++] = reg1 & MASK;
|
||||
name[c++] = (reg1>>8) & MASK;
|
||||
name[c++] = (reg1>>16) & MASK;
|
||||
@@ -106,14 +106,14 @@ char* get_str_cpu_name_internal() {
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
uint32_t c = 0;
|
||||
|
||||
char * name = malloc(sizeof(char) * CPU_NAME_MAX_LENGTH);
|
||||
|
||||
char * name = emalloc(sizeof(char) * CPU_NAME_MAX_LENGTH);
|
||||
memset(name, 0, CPU_NAME_MAX_LENGTH);
|
||||
|
||||
for(int i=0; i < 3; i++) {
|
||||
|
||||
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;
|
||||
@@ -129,22 +129,22 @@ char* get_str_cpu_name_internal() {
|
||||
name[c++] = edx & MASK;
|
||||
name[c++] = (edx>>8) & MASK;
|
||||
name[c++] = (edx>>16) & MASK;
|
||||
name[c++] = (edx>>24) & MASK;
|
||||
name[c++] = (edx>>24) & MASK;
|
||||
}
|
||||
name[c] = '\0';
|
||||
|
||||
//Remove unused characters
|
||||
|
||||
//Remove unused characters
|
||||
char *str = name;
|
||||
char *dest = name;
|
||||
// Remove spaces before name
|
||||
while (*str != '\0' && *str == ' ')str++;
|
||||
while (*str != '\0' && *str == ' ')str++;
|
||||
// Remove spaces between the name and after it
|
||||
while (*str != '\0') {
|
||||
while (*str == ' ' && *(str + 1) == ' ') str++;
|
||||
*dest++ = *str++;
|
||||
}
|
||||
*dest = '\0';
|
||||
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -153,27 +153,27 @@ struct uarch* get_cpu_uarch(struct cpuInfo* cpu) {
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
uint32_t stepping = eax & 0xF;
|
||||
uint32_t model = (eax >> 4) & 0xF;
|
||||
uint32_t emodel = (eax >> 16) & 0xF;
|
||||
uint32_t family = (eax >> 8) & 0xF;
|
||||
uint32_t efamily = (eax >> 20) & 0xFF;
|
||||
|
||||
|
||||
return get_uarch_from_cpuid(cpu, efamily, family, emodel, model, (int)stepping);
|
||||
}
|
||||
|
||||
struct hypervisor* get_hp_info(bool hv_present) {
|
||||
struct hypervisor* hv = malloc(sizeof(struct hypervisor));
|
||||
struct hypervisor* hv = emalloc(sizeof(struct hypervisor));
|
||||
if(!hv_present) {
|
||||
hv->present = false;
|
||||
return hv;
|
||||
return hv;
|
||||
}
|
||||
|
||||
hv->present = true;
|
||||
|
||||
|
||||
hv->present = true;
|
||||
|
||||
uint32_t eax = 0x40000000;
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
@@ -184,37 +184,37 @@ struct hypervisor* get_hp_info(bool hv_present) {
|
||||
char name[13];
|
||||
memset(name, 0, 13);
|
||||
get_name_cpuid(name, ebx, ecx, edx);
|
||||
|
||||
|
||||
bool found = false;
|
||||
uint8_t len = sizeof(hv_vendors_string) / sizeof(hv_vendors_string[0]);
|
||||
|
||||
|
||||
for(uint8_t v=0; v < len && !found; v++) {
|
||||
if(strcmp(hv_vendors_string[v], name) == 0) {
|
||||
hv->hv_vendor = v;
|
||||
found = true;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!found) {
|
||||
hv->hv_vendor = HV_VENDOR_INVALID;
|
||||
printWarn("Unknown hypervisor vendor: %s", name);
|
||||
printWarn("Unknown hypervisor vendor: %s", name);
|
||||
}
|
||||
|
||||
|
||||
hv->hv_name = hv_vendors_name[hv->hv_vendor];
|
||||
|
||||
|
||||
return hv;
|
||||
}
|
||||
|
||||
struct cpuInfo* get_cpu_info() {
|
||||
struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo));
|
||||
struct features* feat = malloc(sizeof(struct features));
|
||||
struct cpuInfo* cpu = emalloc(sizeof(struct cpuInfo));
|
||||
struct features* feat = emalloc(sizeof(struct features));
|
||||
cpu->feat = feat;
|
||||
|
||||
|
||||
bool *ptr = &(feat->AES);
|
||||
for(uint32_t i = 0; i < sizeof(struct features)/sizeof(bool); i++, ptr++) {
|
||||
*ptr = false;
|
||||
}
|
||||
|
||||
|
||||
uint32_t eax = 0;
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
@@ -228,11 +228,11 @@ struct cpuInfo* get_cpu_info() {
|
||||
char name[13];
|
||||
memset(name,0,13);
|
||||
get_name_cpuid(name, ebx, edx, ecx);
|
||||
|
||||
|
||||
if(strcmp(CPU_VENDOR_INTEL_STRING,name) == 0)
|
||||
cpu->cpu_vendor = CPU_VENDOR_INTEL;
|
||||
else if (strcmp(CPU_VENDOR_AMD_STRING,name) == 0)
|
||||
cpu->cpu_vendor = CPU_VENDOR_AMD;
|
||||
cpu->cpu_vendor = CPU_VENDOR_AMD;
|
||||
else {
|
||||
cpu->cpu_vendor = CPU_VENDOR_INVALID;
|
||||
printErr("Unknown CPU vendor: %s", name);
|
||||
@@ -245,7 +245,7 @@ struct cpuInfo* get_cpu_info() {
|
||||
ecx = 0;
|
||||
edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
cpu->maxExtendedLevels = eax;
|
||||
cpu->maxExtendedLevels = eax;
|
||||
|
||||
//Fill instructions support
|
||||
if (cpu->maxLevels >= 0x00000001){
|
||||
@@ -271,7 +271,7 @@ struct cpuInfo* get_cpu_info() {
|
||||
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;
|
||||
@@ -288,9 +288,9 @@ struct cpuInfo* get_cpu_info() {
|
||||
((ebx & (1U << 21)) != 0));
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read features information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000007, cpu->maxLevels);
|
||||
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);
|
||||
@@ -298,25 +298,25 @@ struct cpuInfo* get_cpu_info() {
|
||||
feat->FMA4 = (ecx & (1U << 16)) != 0;
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read features information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000001, cpu->maxExtendedLevels);
|
||||
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);
|
||||
else {
|
||||
cpu->cpu_name = emalloc(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);
|
||||
printWarn("Can't read cpu name from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000004, cpu->maxExtendedLevels);
|
||||
}
|
||||
|
||||
|
||||
cpu->topology_extensions = false;
|
||||
if(cpu->cpu_vendor == CPU_VENDOR_AMD && cpu->maxExtendedLevels >= 0x80000001) {
|
||||
eax = 0x80000001;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
cpu->topology_extensions = (ecx >> 22) & 1;
|
||||
}
|
||||
|
||||
|
||||
cpu->arch = get_cpu_uarch(cpu);
|
||||
cpu->freq = get_frequency_info(cpu);
|
||||
cpu->cach = get_cache_info(cpu);
|
||||
@@ -328,26 +328,26 @@ struct cpuInfo* get_cpu_info() {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
|
||||
if(cpu->maxExtendedLevels >= 0x8000001D && cpu->topology_extensions) {
|
||||
bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
|
||||
if(cpu->maxExtendedLevels >= 0x8000001D && cpu->topology_extensions) {
|
||||
uint32_t i, eax, ebx, ecx, edx, num_sharing_cache, cache_type, cache_level;
|
||||
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
eax = 0x8000001D;
|
||||
ebx = 0;
|
||||
ecx = i; // cache id
|
||||
edx = 0;
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
cache_type = eax & 0x1F;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
cache_type = eax & 0x1F;
|
||||
|
||||
if(cache_type > 0) {
|
||||
num_sharing_cache = ((eax >> 14) & 0xFFF) + 1;
|
||||
cache_level = (eax >>= 5) & 0x7;
|
||||
|
||||
switch (cache_type) {
|
||||
num_sharing_cache = ((eax >> 14) & 0xFFF) + 1;
|
||||
cache_level = (eax >>= 5) & 0x7;
|
||||
|
||||
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);
|
||||
@@ -355,7 +355,7 @@ bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
|
||||
}
|
||||
topo->cach->L1d->num_caches = topo->logical_cores / num_sharing_cache;
|
||||
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);
|
||||
@@ -363,9 +363,9 @@ bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
|
||||
}
|
||||
topo->cach->L1i->num_caches = topo->logical_cores / num_sharing_cache;
|
||||
break;
|
||||
|
||||
|
||||
case 3: // Unified Cache (This may be L2 or L3)
|
||||
if(cache_level == 2) {
|
||||
if(cache_level == 2) {
|
||||
topo->cach->L2->num_caches = topo->logical_cores / num_sharing_cache;
|
||||
}
|
||||
else if(cache_level == 3) {
|
||||
@@ -375,44 +375,44 @@ bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
|
||||
printWarn("Found unknown unified cache at level %d", cache_level);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: // Unknown cache type
|
||||
printBug("Unknown cache type %d with level %d found at i=%d", cache_type, cache_level, i);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
i++;
|
||||
} while (cache_type > 0);
|
||||
} while (cache_type > 0);
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X and topology_extensions=%s). Guessing cache topology", 0x8000001D, cpu->maxExtendedLevels, cpu->topology_extensions ? "true" : "false");
|
||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X and topology_extensions=%s). Guessing cache topology", 0x8000001D, cpu->maxExtendedLevels, cpu->topology_extensions ? "true" : "false");
|
||||
topo->cach->L1i->num_caches = topo->physical_cores;
|
||||
topo->cach->L1d->num_caches = topo->physical_cores;
|
||||
|
||||
|
||||
if(topo->cach->L3->exists) {
|
||||
topo->cach->L2->num_caches = topo->physical_cores;
|
||||
topo->cach->L3->num_caches = 1;
|
||||
topo->cach->L3->num_caches = 1;
|
||||
}
|
||||
else {
|
||||
topo->cach->L2->num_caches = 1;
|
||||
topo->cach->L2->num_caches = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Main reference: https://software.intel.com/content/www/us/en/develop/articles/intel-64-architecture-processor-topology-enumeration.html
|
||||
// Very interesting resource: https://wiki.osdev.org/Detecting_CPU_Topology_(80x86)
|
||||
struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) {
|
||||
struct topology* topo = malloc(sizeof(struct topology));
|
||||
struct topology* topo = emalloc(sizeof(struct topology));
|
||||
init_topology_struct(topo, cach);
|
||||
|
||||
|
||||
uint32_t eax = 0;
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
|
||||
|
||||
// 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!
|
||||
@@ -425,45 +425,45 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) {
|
||||
if((topo->total_cores = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
|
||||
perror("sysconf");
|
||||
topo->total_cores = topo->logical_cores; // fallback
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(cpu->cpu_vendor) {
|
||||
case CPU_VENDOR_INTEL:
|
||||
if (cpu->maxLevels >= 0x00000004) {
|
||||
if (cpu->maxLevels >= 0x00000004) {
|
||||
get_topology_from_apic(cpu, topo);
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels);
|
||||
else {
|
||||
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000001, cpu->maxLevels);
|
||||
topo->physical_cores = 1;
|
||||
topo->logical_cores = 1;
|
||||
topo->smt_available = 1;
|
||||
topo->smt_supported = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CPU_VENDOR_AMD:
|
||||
case CPU_VENDOR_AMD:
|
||||
if (cpu->maxExtendedLevels >= 0x80000008) {
|
||||
eax = 0x80000008;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
eax = 0x80000008;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
topo->logical_cores = (ecx & 0xFF) + 1;
|
||||
|
||||
|
||||
if (cpu->maxExtendedLevels >= 0x8000001E && cpu->topology_extensions) {
|
||||
eax = 0x8000001E;
|
||||
eax = 0x8000001E;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
topo->smt_supported = ((ebx >> 8) & 0x03) + 1;
|
||||
topo->smt_supported = ((ebx >> 8) & 0x03) + 1;
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X and topology_extensions=%s)", 0x8000001E, cpu->maxExtendedLevels, cpu->topology_extensions ? "true" : "false");
|
||||
topo->smt_supported = 1;
|
||||
}
|
||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X and topology_extensions=%s)", 0x8000001E, cpu->maxExtendedLevels, cpu->topology_extensions ? "true" : "false");
|
||||
topo->smt_supported = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxExtendedLevels);
|
||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxExtendedLevels);
|
||||
topo->physical_cores = 1;
|
||||
topo->logical_cores = 1;
|
||||
topo->smt_supported = 1;
|
||||
topo->smt_supported = 1;
|
||||
}
|
||||
|
||||
|
||||
if (cpu->maxLevels >= 0x00000001) {
|
||||
if(topo->smt_supported > 1)
|
||||
topo->smt_available = is_smt_enabled_amd(topo);
|
||||
@@ -471,25 +471,25 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) {
|
||||
topo->smt_available = 1;
|
||||
}
|
||||
else {
|
||||
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels);
|
||||
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels);
|
||||
topo->smt_available = 1;
|
||||
}
|
||||
topo->physical_cores = topo->logical_cores / topo->smt_available;
|
||||
|
||||
|
||||
if(topo->smt_supported > 1)
|
||||
topo->sockets = topo->total_cores / topo->smt_supported / topo->physical_cores; // Idea borrowed from lscpu
|
||||
else
|
||||
topo->sockets = topo->total_cores / topo->physical_cores;
|
||||
|
||||
get_cache_topology_amd(cpu, topo);
|
||||
|
||||
topo->sockets = topo->total_cores / topo->physical_cores;
|
||||
|
||||
get_cache_topology_amd(cpu, topo);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
printBug("Cant get topology because VENDOR is empty");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
return topo;
|
||||
}
|
||||
|
||||
@@ -499,13 +499,13 @@ struct cache* get_cache_info_amd_fallback(struct cache* cach) {
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
cach->L1d->size = (ecx >> 24) * 1024;
|
||||
cach->L1i->size = (edx >> 24) * 1024;
|
||||
|
||||
|
||||
eax = 0x80000006;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
cach->L2->size = (ecx >> 16) * 1024;
|
||||
cach->L3->size = (edx >> 18) * 512 * 1024;
|
||||
|
||||
@@ -529,17 +529,17 @@ struct cache* get_cache_info_general(struct cache* cach, uint32_t level) {
|
||||
uint32_t edx = 0;
|
||||
int i=0;
|
||||
int32_t cache_type;
|
||||
|
||||
|
||||
do {
|
||||
eax = level; // get cache info
|
||||
ebx = 0;
|
||||
ecx = i; // cache id
|
||||
edx = 0;
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
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;
|
||||
@@ -547,11 +547,11 @@ struct cache* get_cache_info_general(struct cache* cach, uint32_t level) {
|
||||
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;
|
||||
|
||||
int32_t cache_total_size = cache_ways_of_associativity * cache_physical_line_partitions * cache_coherency_line_size * cache_sets;
|
||||
cach->max_cache_level++;
|
||||
|
||||
switch (cache_type) {
|
||||
|
||||
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);
|
||||
@@ -560,7 +560,7 @@ struct cache* get_cache_info_general(struct cache* cach, uint32_t level) {
|
||||
cach->L1d->size = cache_total_size;
|
||||
cach->L1d->exists = true;
|
||||
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);
|
||||
@@ -569,9 +569,9 @@ struct cache* get_cache_info_general(struct cache* cach, uint32_t level) {
|
||||
cach->L1i->size = cache_total_size;
|
||||
cach->L1i->exists = true;
|
||||
break;
|
||||
|
||||
|
||||
case 3: // Unified Cache (This may be L2 or L3)
|
||||
if(cache_level == 2) {
|
||||
if(cache_level == 2) {
|
||||
cach->L2->size = cache_total_size;
|
||||
cach->L2->exists = true;
|
||||
}
|
||||
@@ -584,21 +584,21 @@ struct cache* get_cache_info_general(struct cache* cach, uint32_t level) {
|
||||
cach->max_cache_level--;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: // Unknown cache type
|
||||
printBug("Unknown cache type %d with level %d found at i=%d", cache_type, cache_level, i);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i++;
|
||||
} while (cache_type > 0);
|
||||
|
||||
|
||||
return cach;
|
||||
}
|
||||
|
||||
struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
struct cache* cach = malloc(sizeof(struct cache));
|
||||
struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
struct cache* cach = emalloc(sizeof(struct cache));
|
||||
init_cache_struct(cach);
|
||||
|
||||
uint32_t level;
|
||||
@@ -607,9 +607,9 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
// We use extended 0x8000001D for AMD
|
||||
// or 0x80000005/6 for old AMD
|
||||
if(cpu->cpu_vendor == CPU_VENDOR_INTEL) {
|
||||
level = 0x00000004;
|
||||
level = 0x00000004;
|
||||
if(cpu->maxLevels < level) {
|
||||
printWarn("Can't read cache information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", level, cpu->maxLevels);
|
||||
printWarn("Can't read cache information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", level, cpu->maxLevels);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
@@ -619,7 +619,7 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
else {
|
||||
level = 0x8000001D;
|
||||
if(cpu->maxExtendedLevels < level || !cpu->topology_extensions) {
|
||||
printWarn("Can't read cache information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X and topology_extensions=%s)", level, cpu->maxExtendedLevels, cpu->topology_extensions ? "true" : "false");
|
||||
printWarn("Can't read cache information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X and topology_extensions=%s)", level, cpu->maxExtendedLevels, cpu->topology_extensions ? "true" : "false");
|
||||
level = 0x80000006;
|
||||
if(cpu->maxExtendedLevels < level) {
|
||||
printWarn("Can't read cache information from cpuid using old method (needed extended level is 0x%.8X, max is 0x%.8X)", level, cpu->maxExtendedLevels);
|
||||
@@ -629,7 +629,7 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
cach = get_cache_info_amd_fallback(cach);
|
||||
}
|
||||
else {
|
||||
cach = get_cache_info_general(cach, level);
|
||||
cach = get_cache_info_general(cach, level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,8 +637,8 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
|
||||
}
|
||||
|
||||
struct frequency* get_frequency_info(struct cpuInfo* cpu) {
|
||||
struct frequency* freq = malloc(sizeof(struct frequency));
|
||||
|
||||
struct frequency* freq = emalloc(sizeof(struct frequency));
|
||||
|
||||
if(cpu->maxLevels < 0x00000016) {
|
||||
#if defined (_WIN32) || defined (__APPLE__)
|
||||
printWarn("Can't read frequency information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x00000016, cpu->maxLevels);
|
||||
@@ -703,7 +703,7 @@ char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64
|
||||
//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);
|
||||
char* string = emalloc(sizeof(char)*size);
|
||||
|
||||
//First check we have consistent data
|
||||
if(freq == UNKNOWN_FREQ) {
|
||||
@@ -714,8 +714,8 @@ char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64
|
||||
struct features* feat = cpu->feat;
|
||||
double flops = topo->physical_cores * topo->sockets * (freq*1000000);
|
||||
int vpus = get_number_of_vpus(cpu);
|
||||
|
||||
flops = flops * vpus;
|
||||
|
||||
flops = flops * vpus;
|
||||
|
||||
if(feat->FMA3 || feat->FMA4)
|
||||
flops = flops*2;
|
||||
@@ -729,11 +729,11 @@ char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64
|
||||
flops = flops*8;
|
||||
else if(feat->SSE)
|
||||
flops = flops*4;
|
||||
|
||||
|
||||
// See https://sites.utexas.edu/jdm4372/2018/01/22/a-peculiar-
|
||||
// throughput-limitation-on-intels-xeon-phi-x200-knights-landing/
|
||||
if(is_knights_landing(cpu))
|
||||
flops = flops * 6 / 7;
|
||||
flops = flops * 6 / 7;
|
||||
|
||||
if(flops >= (double)1000000000000.0)
|
||||
snprintf(string,size,"%.2f TFLOP/s",flops/1000000000000);
|
||||
@@ -741,7 +741,7 @@ char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64
|
||||
snprintf(string,size,"%.2f GFLOP/s",flops/1000000000);
|
||||
else
|
||||
snprintf(string,size,"%.2f MFLOP/s",flops/1000000);
|
||||
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
@@ -751,7 +751,7 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc
|
||||
if(topo->smt_supported > 1) {
|
||||
//3 for digits, 21 for ' cores (SMT disabled)' which is the longest possible output
|
||||
uint32_t size = 3+21+1;
|
||||
string = malloc(sizeof(char)*size);
|
||||
string = emalloc(sizeof(char)*size);
|
||||
if(dual_socket) {
|
||||
if(topo->smt_available > 1)
|
||||
snprintf(string, size, "%d cores (%d threads)",topo->physical_cores * topo->sockets, topo->logical_cores * topo->sockets);
|
||||
@@ -775,7 +775,7 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc
|
||||
}
|
||||
else {
|
||||
uint32_t size = 3+7+1;
|
||||
string = malloc(sizeof(char)*size);
|
||||
string = emalloc(sizeof(char)*size);
|
||||
if(dual_socket)
|
||||
snprintf(string, size, "%d cores",topo->physical_cores * topo->sockets);
|
||||
else
|
||||
@@ -786,7 +786,7 @@ char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_soc
|
||||
|
||||
char* get_str_avx(struct cpuInfo* cpu) {
|
||||
//If all AVX are available, it will use up to 15
|
||||
char* string = malloc(sizeof(char)*17+1);
|
||||
char* string = emalloc(sizeof(char)*17+1);
|
||||
if(!cpu->feat->AVX)
|
||||
snprintf(string,2+1,"No");
|
||||
else if(!cpu->feat->AVX2)
|
||||
@@ -808,7 +808,7 @@ char* get_str_sse(struct cpuInfo* cpu) {
|
||||
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);
|
||||
char* string = emalloc(sizeof(char)*SSE_sl+SSE2_sl+SSE3_sl+SSSE3_sl+SSE4a_sl+SSE4_1_sl+SSE4_2_sl+1);
|
||||
|
||||
if(cpu->feat->SSE) {
|
||||
snprintf(string+last,SSE_sl+1,"SSE,");
|
||||
@@ -845,7 +845,7 @@ char* get_str_sse(struct cpuInfo* cpu) {
|
||||
}
|
||||
|
||||
char* get_str_fma(struct cpuInfo* cpu) {
|
||||
char* string = malloc(sizeof(char)*9+1);
|
||||
char* string = emalloc(sizeof(char)*9+1);
|
||||
if(!cpu->feat->FMA3)
|
||||
snprintf(string,2+1,"No");
|
||||
else if(!cpu->feat->FMA4)
|
||||
@@ -861,9 +861,9 @@ void print_debug(struct cpuInfo* cpu) {
|
||||
uint32_t ebx = 0;
|
||||
uint32_t ecx = 0;
|
||||
uint32_t edx = 0;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
printf("%s\n", cpu->cpu_name);
|
||||
if(cpu->hv->present) {
|
||||
printf("- Hypervisor: %s\n", cpu->hv->hv_name);
|
||||
@@ -871,7 +871,7 @@ void print_debug(struct cpuInfo* cpu) {
|
||||
printf("- Max standard level: 0x%.8X\n", cpu->maxLevels);
|
||||
printf("- Max extended level: 0x%.8X\n", cpu->maxExtendedLevels);
|
||||
if(cpu->cpu_vendor == CPU_VENDOR_AMD) {
|
||||
printf("- AMD topology extensions: %d\n", cpu->topology_extensions);
|
||||
printf("- AMD topology extensions: %d\n", cpu->topology_extensions);
|
||||
}
|
||||
printf("- CPUID dump: 0x%.8X\n", eax);
|
||||
|
||||
@@ -887,7 +887,7 @@ void print_raw(struct cpuInfo* cpu) {
|
||||
printf("%s\n\n", cpu->cpu_name);
|
||||
printf(" CPUID leaf sub EAX EBX ECX EDX \n");
|
||||
printf("--------------------------------------------------------------\n");
|
||||
|
||||
|
||||
for(int c=0; c < cpu->topo->total_cores; c++) {
|
||||
#ifndef __APPLE__
|
||||
if(!bind_to_cpu(c)) {
|
||||
@@ -895,9 +895,9 @@ void print_raw(struct cpuInfo* cpu) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("CPU %d:\n", c);
|
||||
|
||||
|
||||
printf("CPU %d:\n", c);
|
||||
|
||||
for(uint32_t reg=0x00000000; reg <= cpu->maxLevels; reg++) {
|
||||
if(reg == 0x00000004) {
|
||||
for(uint32_t reg2=0x00000000; reg2 < cpu->cach->max_cache_level; reg2++) {
|
||||
@@ -905,9 +905,9 @@ void print_raw(struct cpuInfo* cpu) {
|
||||
ebx = 0;
|
||||
ecx = reg2;
|
||||
edx = 0;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, reg2, eax, ebx, ecx, edx);
|
||||
}
|
||||
}
|
||||
@@ -917,9 +917,9 @@ void print_raw(struct cpuInfo* cpu) {
|
||||
ebx = 0;
|
||||
ecx = reg2;
|
||||
edx = 0;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, reg2, eax, ebx, ecx, edx);
|
||||
}
|
||||
}
|
||||
@@ -928,10 +928,10 @@ void print_raw(struct cpuInfo* cpu) {
|
||||
ebx = 0;
|
||||
ecx = 0;
|
||||
edx = 0;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, 0x00, eax, ebx, ecx, edx);
|
||||
|
||||
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, 0x00, eax, ebx, ecx, edx);
|
||||
}
|
||||
}
|
||||
for(uint32_t reg=0x80000000; reg <= cpu->maxExtendedLevels; reg++) {
|
||||
@@ -941,9 +941,9 @@ void print_raw(struct cpuInfo* cpu) {
|
||||
ebx = 0;
|
||||
ecx = reg2;
|
||||
edx = 0;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, reg2, eax, ebx, ecx, edx);
|
||||
}
|
||||
}
|
||||
@@ -952,9 +952,9 @@ void print_raw(struct cpuInfo* cpu) {
|
||||
ebx = 0;
|
||||
ecx = 0;
|
||||
edx = 0;
|
||||
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
|
||||
printf(" 0x%.8X 0x%.2X: 0x%.8X 0x%.8X 0x%.8X 0x%.8X\n", reg, 0x00, eax, ebx, ecx, edx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ struct uarch {
|
||||
#define UARCH_END else { printBug("Unknown microarchitecture detected: M=0x%.8X EM=0x%.8X F=0x%.8X EF=0x%.8X S=0x%.8X", m, em, f, ef, s); fill_uarch(arch, "Unknown", UARCH_UNKNOWN, 0); }
|
||||
|
||||
void fill_uarch(struct uarch* arch, char* str, MICROARCH u, uint32_t process) {
|
||||
arch->uarch_str = malloc(sizeof(char) * (strlen(str)+1));
|
||||
arch->uarch_str = emalloc(sizeof(char) * (strlen(str)+1));
|
||||
strcpy(arch->uarch_str, str);
|
||||
arch->uarch = u;
|
||||
arch->process= process;
|
||||
@@ -132,8 +132,8 @@ void fill_uarch(struct uarch* arch, char* str, MICROARCH u, uint32_t process) {
|
||||
|
||||
// Inspired in Todd Allen's decode_uarch_intel
|
||||
struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
|
||||
struct uarch* arch = malloc(sizeof(struct uarch));
|
||||
|
||||
struct uarch* arch = emalloc(sizeof(struct uarch));
|
||||
|
||||
// EF: Extended Family //
|
||||
// F: Family //
|
||||
// EM: Extended Model //
|
||||
@@ -249,14 +249,14 @@ struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, u
|
||||
CHECK_UARCH(arch, 1, 15, 0, 1, NA, "Itanium2", UARCH_ITANIUM2, 130)
|
||||
CHECK_UARCH(arch, 1, 15, 0, 2, NA, "Itanium2", UARCH_ITANIUM2, 130)
|
||||
UARCH_END
|
||||
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
// iNApired in Todd Allen's decode_uarch_amd
|
||||
struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
|
||||
struct uarch* arch = malloc(sizeof(struct uarch));
|
||||
|
||||
struct uarch* arch = emalloc(sizeof(struct uarch));
|
||||
|
||||
// EF: Extended Family //
|
||||
// F: Family //
|
||||
// EM: Extended Model //
|
||||
@@ -264,7 +264,7 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
|
||||
// S: Stepping //
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// EF F EM M S //
|
||||
UARCH_START
|
||||
UARCH_START
|
||||
CHECK_UARCH(arch, 0, 4, 0, 3, NA, "Am486", UARCH_AM486, UNK)
|
||||
CHECK_UARCH(arch, 0, 4, 0, 7, NA, "Am486", UARCH_AM486, UNK)
|
||||
CHECK_UARCH(arch, 0, 4, 0, 8, NA, "Am486", UARCH_AM486, UNK)
|
||||
@@ -352,14 +352,14 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
|
||||
CHECK_UARCH(arch, 10, 15, 2, 1, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
|
||||
CHECK_UARCH(arch, 10, 15, 5, 0, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
|
||||
UARCH_END
|
||||
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
|
||||
if(cpu->cpu_vendor == CPU_VENDOR_INTEL)
|
||||
return get_uarch_from_cpuid_intel(ef, f, em, m, s);
|
||||
else
|
||||
else
|
||||
return get_uarch_from_cpuid_amd(ef, f, em, m, s);
|
||||
}
|
||||
|
||||
@@ -368,33 +368,33 @@ bool vpus_are_AVX512(struct cpuInfo* cpu) {
|
||||
}
|
||||
|
||||
bool is_knights_landing(struct cpuInfo* cpu) {
|
||||
return cpu->arch->uarch == UARCH_KNIGHTS_LANDING;
|
||||
return cpu->arch->uarch == UARCH_KNIGHTS_LANDING;
|
||||
}
|
||||
|
||||
int get_number_of_vpus(struct cpuInfo* cpu) {
|
||||
int get_number_of_vpus(struct cpuInfo* cpu) {
|
||||
switch(cpu->arch->uarch) {
|
||||
// Intel
|
||||
case UARCH_HASWELL:
|
||||
case UARCH_BROADWELL:
|
||||
|
||||
|
||||
case UARCH_SKYLAKE:
|
||||
case UARCH_CASCADE_LAKE:
|
||||
case UARCH_CASCADE_LAKE:
|
||||
case UARCH_KABY_LAKE:
|
||||
case UARCH_COMET_LAKE:
|
||||
case UARCH_ROCKET_LAKE:
|
||||
case UARCH_AMBER_LAKE:
|
||||
case UARCH_WHISKEY_LAKE:
|
||||
case UARCH_COFFE_LAKE:
|
||||
case UARCH_PALM_COVE:
|
||||
|
||||
case UARCH_PALM_COVE:
|
||||
|
||||
case UARCH_KNIGHTS_LANDING:
|
||||
case UARCH_KNIGHTS_MILL:
|
||||
|
||||
case UARCH_ICE_LAKE:
|
||||
|
||||
|
||||
case UARCH_ICE_LAKE:
|
||||
|
||||
// AMD
|
||||
case UARCH_ZEN2:
|
||||
case UARCH_ZEN3:
|
||||
case UARCH_ZEN3:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
@@ -402,11 +402,11 @@ int get_number_of_vpus(struct cpuInfo* cpu) {
|
||||
}
|
||||
|
||||
char* get_str_uarch(struct cpuInfo* cpu) {
|
||||
return cpu->arch->uarch_str;
|
||||
return cpu->arch->uarch_str;
|
||||
}
|
||||
|
||||
char* get_str_process(struct cpuInfo* cpu) {
|
||||
char* str = malloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
|
||||
char* str = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
|
||||
int32_t process = cpu->arch->process;
|
||||
|
||||
if(process == UNK) {
|
||||
@@ -426,7 +426,7 @@ char* get_str_process(struct cpuInfo* cpu) {
|
||||
return str;
|
||||
}
|
||||
|
||||
void free_uarch_struct(struct uarch* arch) {
|
||||
void free_uarch_struct(struct uarch* arch) {
|
||||
free(arch->uarch_str);
|
||||
free(arch);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user