[v1.00] Merge latest commits from master branch

This commit is contained in:
Dr-Noob
2021-10-31 20:19:21 +01:00
55 changed files with 3626 additions and 1670 deletions

View File

@@ -4,8 +4,19 @@
#include <assert.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/auxv.h>
#include <asm/hwcap.h>
#ifdef __linux__
#include <sys/auxv.h>
#include <asm/hwcap.h>
#elif defined __APPLE__ || __MACH__
#include "sysctl.h"
// From Linux kernel: arch/arm64/include/asm/cputype.h
#define MIDR_APPLE_M1_ICESTORM 0x610F0220
#define MIDR_APPLE_M1_FIRESTORM 0x610F0230
#ifndef CPUFAMILY_ARM_FIRESTORM_ICESTORM
#define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1B588BB3
#endif
#endif
#include "../common/global.h"
#include "udev.h"
@@ -13,29 +24,12 @@
#include "uarch.h"
#include "soc.h"
#define STRING_UNKNOWN "Unknown"
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->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;
cach->L2->exists = false;
cach->L3->exists = false;
bool cores_are_equal(int c1pos, int c2pos, uint32_t* midr_array, int32_t* freq_array) {
return midr_array[c1pos] == midr_array[c2pos] && freq_array[c1pos] == freq_array[c2pos];
}
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);
cach->max_cache_level = 2;
@@ -49,45 +43,60 @@ struct cache* get_cache_info(struct cpuInfo* cpu) {
}
struct frequency* get_frequency_info(uint32_t core) {
struct frequency* freq = malloc(sizeof(struct frequency));
struct frequency* freq = emalloc(sizeof(struct frequency));
freq->base = UNKNOWN_FREQ;
freq->max = get_max_freq_from_file(core, false);
freq->max = get_max_freq_from_file(core);
return freq;
}
struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, uint32_t* midr_array, int socket_idx, int ncores) {
struct topology* topo = malloc(sizeof(struct topology));
struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach, uint32_t* midr_array, int32_t* freq_array, int socket_idx, int ncores) {
struct topology* topo = emalloc(sizeof(struct topology));
init_topology_struct(topo, cach);
topo->cach = cach;
topo->total_cores = 0;
int sockets_seen = 0;
int first_core_idx = 0;
int currrent_core_idx = 0;
int cores_in_socket = 0;
while(socket_idx + 1 > sockets_seen) {
if(midr_array[first_core_idx] == midr_array[currrent_core_idx] && currrent_core_idx < ncores) {
if(currrent_core_idx < ncores && cores_are_equal(first_core_idx, currrent_core_idx, midr_array, freq_array)) {
currrent_core_idx++;
cores_in_socket++;
}
else {
topo->total_cores = cores_in_socket;
topo->total_cores = cores_in_socket;
cores_in_socket = 0;
first_core_idx = currrent_core_idx;
sockets_seen++;
}
}
return topo;
}
bool cores_are_equal(int c1pos, int c2pos, uint32_t* midr_array, int32_t* freq_array) {
return midr_array[c1pos] == midr_array[c2pos] && freq_array[c1pos] == freq_array[c2pos];
int64_t get_peak_performance(struct cpuInfo* cpu) {
struct cpuInfo* ptr = cpu;
//First check we have consistent data
for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
if(get_freq(ptr->freq) == UNKNOWN_FREQ) {
return -1;
}
}
int64_t flops = 0;
ptr = cpu;
for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
flops += ptr->topo->total_cores * (get_freq(ptr->freq) * 1000000);
}
if(cpu->feat->NEON) flops = flops * 4;
return flops;
}
uint32_t fill_ids_from_midr(uint32_t* midr_array, int32_t* freq_array, uint32_t* ids_array, int len) {
uint32_t latest_id = 0;
bool found;
@@ -128,17 +137,18 @@ void init_cpu_info(struct cpuInfo* cpu) {
// ARM32 https://elixir.bootlin.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
// ARM64 https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
struct features* get_features_info() {
struct features* feat = malloc(sizeof(struct features));
struct features* feat = emalloc(sizeof(struct features));
bool *ptr = &(feat->AES);
for(uint32_t i = 0; i < sizeof(struct features)/sizeof(bool); i++, ptr++) {
*ptr = false;
}
#ifdef __linux__
errno = 0;
long hwcaps = getauxval(AT_HWCAP);
if(errno == ENOENT) {
printWarn("Unable to retrieve AT_HWCAP using getauxval");
printWarn("Unable to retrieve AT_HWCAP using getauxval");
}
#ifdef __aarch64__
else {
@@ -152,7 +162,7 @@ struct features* get_features_info() {
else {
feat->NEON = hwcaps & HWCAP_NEON;
}
hwcaps = getauxval(AT_HWCAP2);
if(errno == ENOENT) {
printWarn("Unable to retrieve AT_HWCAP2 using getauxval");
@@ -163,114 +173,157 @@ struct features* get_features_info() {
feat->SHA1 = hwcaps & HWCAP2_SHA1;
feat->SHA2 = hwcaps & HWCAP2_SHA2;
}
#endif
#endif // ifdef __aarch64__
#elif defined __APPLE__ || __MACH__
// Must be M1
feat->AES = true;
feat->CRC32 = true;
feat->SHA1 = true;
feat->SHA2 = true;
feat->NEON = true;
#endif // ifdef __linux__
return feat;
}
struct cpuInfo* get_cpu_info() {
struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo));
#ifdef __linux__
struct cpuInfo* get_cpu_info_linux(struct cpuInfo* cpu) {
init_cpu_info(cpu);
int ncores = get_ncores_from_cpuinfo();
bool success = false;
int32_t* freq_array = malloc(sizeof(uint32_t) * ncores);
uint32_t* midr_array = malloc(sizeof(uint32_t) * ncores);
uint32_t* ids_array = malloc(sizeof(uint32_t) * ncores);
int32_t* freq_array = emalloc(sizeof(uint32_t) * ncores);
uint32_t* midr_array = emalloc(sizeof(uint32_t) * ncores);
uint32_t* ids_array = emalloc(sizeof(uint32_t) * ncores);
for(int i=0; i < ncores; i++) {
midr_array[i] = get_midr_from_cpuinfo(i, &success);
if(!success) {
printWarn("Unable to fetch MIDR for core %d. This is probably because the core is offline", i);
midr_array[i] = midr_array[0];
}
freq_array[i] = get_max_freq_from_file(i, false);
freq_array[i] = get_max_freq_from_file(i);
if(freq_array[i] == UNKNOWN_FREQ) {
printWarn("Unable to fetch max frequency for core %d. This is probably because the core is offline", i);
freq_array[i] = freq_array[0];
}
}
}
uint32_t sockets = fill_ids_from_midr(midr_array, freq_array, ids_array, ncores);
struct cpuInfo* ptr = cpu;
int midr_idx = 0;
int tmp_midr_idx = 0;
for(uint32_t i=0; i < sockets; i++) {
if(i > 0) {
ptr->next_cpu = malloc(sizeof(struct cpuInfo));
ptr->next_cpu = emalloc(sizeof(struct cpuInfo));
ptr = ptr->next_cpu;
init_cpu_info(ptr);
tmp_midr_idx = midr_idx;
while(cores_are_equal(midr_idx, tmp_midr_idx, midr_array, freq_array)) tmp_midr_idx++;
midr_idx = tmp_midr_idx;
}
}
ptr->midr = midr_array[midr_idx];
ptr->arch = get_uarch_from_midr(ptr->midr, ptr);
ptr->feat = get_features_info();
ptr->freq = get_frequency_info(midr_idx);
ptr->cach = get_cache_info(ptr);
ptr->topo = get_topology_info(ptr, ptr->cach, midr_array, i, ncores);
ptr->topo = get_topology_info(ptr, ptr->cach, midr_array, freq_array, i, ncores);
}
cpu->num_cpus = sockets;
cpu->hv = malloc(sizeof(struct hypervisor));
cpu->hv = emalloc(sizeof(struct hypervisor));
cpu->hv->present = false;
cpu->soc = get_soc();
cpu->soc = get_soc();
cpu->peak_performance = get_peak_performance(cpu);
return cpu;
}
#elif defined __APPLE__ || __MACH__
void fill_cpu_info_firestorm_icestorm(struct cpuInfo* cpu) {
// 1. Fill ICESTORM
struct cpuInfo* ice = cpu;
ice->midr = MIDR_APPLE_M1_ICESTORM;
ice->arch = get_uarch_from_midr(ice->midr, ice);
ice->cach = get_cache_info(ice);
ice->feat = get_features_info();
ice->topo = malloc(sizeof(struct topology));
ice->topo->cach = ice->cach;
ice->topo->total_cores = 4;
ice->freq = malloc(sizeof(struct frequency));
ice->freq->base = UNKNOWN_FREQ;
ice->freq->max = 2064;
ice->hv = malloc(sizeof(struct hypervisor));
ice->hv->present = false;
ice->next_cpu = malloc(sizeof(struct cpuInfo));
// 2. Fill FIRESTORM
struct cpuInfo* fire = ice->next_cpu;
fire->midr = MIDR_APPLE_M1_FIRESTORM;
fire->arch = get_uarch_from_midr(fire->midr, fire);
fire->cach = get_cache_info(fire);
fire->feat = get_features_info();
fire->topo = malloc(sizeof(struct topology));
fire->topo->cach = fire->cach;
fire->topo->total_cores = 4;
fire->freq = malloc(sizeof(struct frequency));
fire->freq->base = UNKNOWN_FREQ;
fire->freq->max = 3200;
fire->hv = malloc(sizeof(struct hypervisor));
fire->hv->present = false;
fire->next_cpu = NULL;
}
struct cpuInfo* get_cpu_info_mach(struct cpuInfo* cpu) {
uint32_t cpu_family = get_sys_info_by_name("hw.cpufamily");
// Manually fill the cpuInfo assuming that the CPU
// is a ARM_FIRESTORM_ICESTORM (Apple M1)
if(cpu_family == CPUFAMILY_ARM_FIRESTORM_ICESTORM) {
cpu->num_cpus = 2;
cpu->soc = get_soc();
fill_cpu_info_firestorm_icestorm(cpu);
cpu->peak_performance = get_peak_performance(cpu);
}
else {
printBug("Found invalid cpu_family: 0x%.8X", cpu_family);
return NULL;
}
return cpu;
}
#endif
struct cpuInfo* get_cpu_info() {
struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo));
init_cpu_info(cpu);
#ifdef __linux__
return get_cpu_info_linux(cpu);
#elif defined __APPLE__ || __MACH__
return get_cpu_info_mach(cpu);
#endif
}
char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket) {
uint32_t size = 3+7+1;
char* string = malloc(sizeof(char)*size);
char* string = emalloc(sizeof(char)*size);
snprintf(string, size, "%d cores", topo->total_cores);
return string;
}
char* get_str_peak_performance(struct cpuInfo* cpu) {
//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);
struct cpuInfo* ptr = cpu;
//First check we have consistent data
for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
if(get_freq(ptr->freq) == UNKNOWN_FREQ) {
snprintf(string, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
return string;
}
}
double flops = 0.0;
ptr = cpu;
for(int i=0; i < cpu->num_cpus; ptr = ptr->next_cpu, i++) {
flops += ptr->topo->total_cores * (get_freq(ptr->freq) * 1000000);
}
if(cpu->feat->NEON) flops = flops * 4;
if(flops >= (double)1000000000000.0)
snprintf(string,size,"%.2f TFLOP/s",flops/1000000000000);
else if(flops >= 1000000000.0)
snprintf(string,size,"%.2f GFLOP/s",flops/1000000000);
else
snprintf(string,size,"%.2f MFLOP/s",flops/1000000);
return string;
}
char* get_str_features(struct cpuInfo* cpu) {
struct features* feat = cpu->feat;
char* string = malloc(sizeof(char) * 25);
struct features* feat = cpu->feat;
uint32_t max_len = strlen("NEON,SHA1,SHA2,AES,CRC32,") + 1;
uint32_t len = 0;
char* string = ecalloc(max_len, sizeof(char));
if(feat->NEON) {
strcat(string, "NEON,");
len += 5;
@@ -291,38 +344,38 @@ char* get_str_features(struct cpuInfo* cpu) {
strcat(string, "CRC32,");
len += 6;
}
if(len > 0) {
string[len-1] = '\0';
return string;
}
else
return NULL;
else
return NULL;
}
void print_debug(struct cpuInfo* cpu) {
int ncores = get_ncores_from_cpuinfo();
bool success = false;
for(int i=0; i < ncores; i++) {
printf("[Core %d] ", i);
long freq = get_max_freq_from_file(i, false);
long freq = get_max_freq_from_file(i);
uint32_t midr = get_midr_from_cpuinfo(i, &success);
if(!success) {
printWarn("Unable to fetch MIDR for core %d. This is probably because the core is offline", i);
printf("0x%.8X ", get_midr_from_cpuinfo(0, &success));
}
else {
printf("0x%.8X ", midr);
printf("0x%.8X ", midr);
}
if(freq == UNKNOWN_FREQ) {
printWarn("Unable to fetch max frequency for core %d. This is probably because the core is offline", i);
printf("%ld MHz\n", get_max_freq_from_file(0, false));
printf("%ld MHz\n", get_max_freq_from_file(0));
}
else {
printf("%ld MHz\n", freq);
printf("%ld MHz\n", freq);
}
}
}
}
void free_topo_struct(struct topology* topo) {

View File

@@ -7,7 +7,6 @@ struct cpuInfo* get_cpu_info();
uint32_t get_nsockets(struct topology* topo);
char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket);
char* get_str_peak_performance(struct cpuInfo* cpu);
char* get_str_features(struct cpuInfo* cpu);
void print_debug(struct cpuInfo* cpu);

View File

@@ -9,7 +9,7 @@
#include "../common/global.h"
#define min(a,b) (((a)<(b))?(a):(b))
#define STRING_UNKNOWN "Unknown"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static char* soc_trademark_string[] = {
[SOC_VENDOR_SNAPDRAGON] = "Snapdragon ",
@@ -17,6 +17,14 @@ static char* soc_trademark_string[] = {
[SOC_VENDOR_EXYNOS] = "Exynos ",
[SOC_VENDOR_KIRIN] = "Kirin ",
[SOC_VENDOR_BROADCOM] = "Broadcom BCM",
[SOC_VENDOR_APPLE] = "Apple "
};
static char* soc_rpi_string[] = {
"BCM2835",
"BCM2836",
"BCM2837",
"BCM2711"
};
void fill_soc(struct system_on_chip* soc, char* soc_name, SOC soc_model, int32_t process) {
@@ -24,34 +32,34 @@ void fill_soc(struct system_on_chip* soc, char* soc_name, SOC soc_model, int32_t
soc->soc_vendor = get_soc_vendor_from_soc(soc_model);
soc->process = process;
int len = strlen(soc_name) + strlen(soc_trademark_string[soc->soc_vendor]) + 1;
soc->soc_name = malloc(sizeof(char) * len);
soc->soc_name = emalloc(sizeof(char) * len);
memset(soc->soc_name, 0, sizeof(char) * len);
sprintf(soc->soc_name, "%s%s", soc_trademark_string[soc->soc_vendor], soc_name);
sprintf(soc->soc_name, "%s%s", soc_trademark_string[soc->soc_vendor], soc_name);
}
bool match_soc(struct system_on_chip* soc, char* raw_name, char* expected_name, char* soc_name, SOC soc_model, int32_t process) {
if(strlen(raw_name) > strlen(expected_name))
return false;
int len = strlen(raw_name);
if(strncmp(raw_name, expected_name, len) != 0) {
return false;
}
else {
fill_soc(soc, soc_name, soc_model, process);
return true;
return true;
}
}
char* toupperstr(char* str) {
int len = strlen(str) + 1;
char* ret = malloc(sizeof(char) * len);
char* ret = emalloc(sizeof(char) * len);
memset(ret, 0, sizeof(char) * len);
for(int i=0; i < len; i++) {
ret[i] = toupper((unsigned char) str[i]);
ret[i] = toupper((unsigned char) str[i]);
}
return ret;
}
@@ -59,6 +67,12 @@ char* toupperstr(char* str) {
#define SOC_EQ(raw_name, expected_name, soc_name, soc_model, soc, process) \
else if (match_soc(soc, raw_name, expected_name, soc_name, soc_model, process)) return true;
#define SOC_END else { return false; }
// Exynos special define
#define SOC_EXY_EQ(raw_name, tmpsoc, soc_name, soc_model, soc, process) \
sprintf(tmpsoc, "exynos%s", soc_name); \
if (match_soc(soc, raw_name, tmpsoc, soc_name, soc_model, process)) return true; \
sprintf(tmpsoc, "universal%s", soc_name); \
if (match_soc(soc, raw_name, tmpsoc, soc_name, soc_model, process)) return true;
// https://en.wikipedia.org/wiki/Raspberry_Pi
// http://phonedb.net/index.php?m=processor&id=562&c=broadcom_bcm21663
@@ -68,22 +82,22 @@ bool match_broadcom(char* soc_name, struct system_on_chip* soc) {
if((tmp = strstr(soc_name, "BCM")) == NULL)
return false;
SOC_START
SOC_EQ(tmp, "BCM2835", "2835", SOC_BCM_2835, soc, 65)
SOC_EQ(tmp, "BCM2836", "2836", SOC_BCM_2836, soc, 40)
SOC_EQ(tmp, "BCM2837", "2837", SOC_BCM_2837, soc, 40)
SOC_EQ(tmp, "BCM2837B0", "2837B0", SOC_BCM_2837B0, soc, 40)
SOC_EQ(tmp, "BCM2711", "2711", SOC_BCM_2711, soc, 28)
SOC_EQ(tmp, "BCM21553", "21553", SOC_BCM_21553, soc, 65)
SOC_EQ(tmp, "BCM21553-Thunderbird", "21553 Thunderbird", SOC_BCM_21553T, soc, 65)
SOC_EQ(tmp, "BCM21663", "21663", SOC_BCM_21663, soc, 40)
SOC_EQ(tmp, "BCM21664", "21664", SOC_BCM_21664, soc, 40)
SOC_EQ(tmp, "BCM28155", "28155", SOC_BCM_28155, soc, 40)
SOC_EQ(tmp, "BCM23550", "23550", SOC_BCM_23550, soc, 40)
SOC_EQ(tmp, "BCM28145", "28145", SOC_BCM_28145, soc, 40)
SOC_EQ(tmp, "BCM2157", "2157", SOC_BCM_2157, soc, 65)
SOC_EQ(tmp, "BCM21654", "21654", SOC_BCM_21654, soc, 40)
SOC_EQ(tmp, "BCM2835", "2835", SOC_BCM_2835, soc, 65)
SOC_EQ(tmp, "BCM2836", "2836", SOC_BCM_2836, soc, 40)
SOC_EQ(tmp, "BCM2837", "2837", SOC_BCM_2837, soc, 40)
SOC_EQ(tmp, "BCM2837B0", "2837B0", SOC_BCM_2837B0, soc, 40)
SOC_EQ(tmp, "BCM2711", "2711", SOC_BCM_2711, soc, 28)
SOC_EQ(tmp, "BCM21553", "21553", SOC_BCM_21553, soc, 65)
SOC_EQ(tmp, "BCM21553-Thunderbird", "21553 Thunderbird", SOC_BCM_21553T, soc, 65)
SOC_EQ(tmp, "BCM21663", "21663", SOC_BCM_21663, soc, 40)
SOC_EQ(tmp, "BCM21664", "21664", SOC_BCM_21664, soc, 40)
SOC_EQ(tmp, "BCM28155", "28155", SOC_BCM_28155, soc, 40)
SOC_EQ(tmp, "BCM23550", "23550", SOC_BCM_23550, soc, 40)
SOC_EQ(tmp, "BCM28145", "28145", SOC_BCM_28145, soc, 40)
SOC_EQ(tmp, "BCM2157", "2157", SOC_BCM_2157, soc, 65)
SOC_EQ(tmp, "BCM21654", "21654", SOC_BCM_21654, soc, 40)
SOC_END
}
@@ -94,7 +108,7 @@ bool match_hisilicon(char* soc_name, struct system_on_chip* soc) {
if((tmp = strstr(soc_name, "Hi")) == NULL)
return false;
SOC_START
SOC_EQ(tmp, "Hi3620GFC", "K3V2", SOC_HISILICON_3620, soc, 40)
//SOC_EQ(tmp, "?", "K3V2E", SOC_KIRIN, soc, ?)
@@ -130,63 +144,75 @@ bool match_hisilicon(char* soc_name, struct system_on_chip* soc) {
bool match_exynos(char* soc_name, struct system_on_chip* soc) {
char* tmp;
if((tmp = strstr(soc_name, "universal")) == NULL)
return false;
if((tmp = strstr(soc_name, "universal")) != NULL);
else if((tmp = strstr(soc_name, "exynos")) != NULL);
else return false;
// Because exynos are recently using "exynosXXXX" instead
// of "universalXXXX" as codenames, SOC_EXY_EQ will check for
// both cases, since it seems that there are some SoCs that
// can appear with both codenames
// Used by SOC_EXY_EQ
char tmpsoc[14];
SOC_START
// universalXXXX //
SOC_EQ(tmp, "universal3475", "3475", SOC_EXYNOS_3475, soc, 28)
SOC_EQ(tmp, "universal4210", "4210", SOC_EXYNOS_4210, soc, 45)
SOC_EQ(tmp, "universal4212", "4212", SOC_EXYNOS_4212, soc, 32)
SOC_EQ(tmp, "universal4412", "4412", SOC_EXYNOS_4412, soc, 32)
SOC_EQ(tmp, "universal5250", "5250", SOC_EXYNOS_5250, soc, 32)
SOC_EQ(tmp, "universal5410", "5410", SOC_EXYNOS_5410, soc, 28)
SOC_EQ(tmp, "universal5420", "5420", SOC_EXYNOS_5420, soc, 28)
SOC_EQ(tmp, "universal5422", "5422", SOC_EXYNOS_5422, soc, 28)
SOC_EQ(tmp, "universal5430", "5430", SOC_EXYNOS_5430, soc, 20)
SOC_EQ(tmp, "universal5433", "5433", SOC_EXYNOS_5433, soc, 20)
SOC_EQ(tmp, "universal5260", "5260", SOC_EXYNOS_5260, soc, 28)
SOC_EQ(tmp, "universal7270", "7270", SOC_EXYNOS_7270, soc, 14)
SOC_EQ(tmp, "universal7420", "7420", SOC_EXYNOS_7420, soc, 14)
SOC_EQ(tmp, "universal7570", "7570", SOC_EXYNOS_7570, soc, 14)
SOC_EQ(tmp, "universal7870", "7870", SOC_EXYNOS_7870, soc, 14)
SOC_EQ(tmp, "universal7872", "7872", SOC_EXYNOS_7872, soc, 14)
SOC_EQ(tmp, "universal7880", "7880", SOC_EXYNOS_7880, soc, 14)
SOC_EQ(tmp, "universal7884", "7884", SOC_EXYNOS_7884, soc, 14)
SOC_EQ(tmp, "universal7885", "7885", SOC_EXYNOS_7885, soc, 14)
SOC_EQ(tmp, "universal7904", "7904", SOC_EXYNOS_7904, soc, 14)
SOC_EQ(tmp, "universal8890", "8890", SOC_EXYNOS_8890, soc, 14)
SOC_EQ(tmp, "universal8895", "8895", SOC_EXYNOS_8895, soc, 10)
SOC_EQ(tmp, "universal9110", "9110", SOC_EXYNOS_9110, soc, 14)
SOC_EQ(tmp, "universal9609", "9609", SOC_EXYNOS_9609, soc, 10)
SOC_EQ(tmp, "universal9610", "9610", SOC_EXYNOS_9610, soc, 10)
SOC_EQ(tmp, "universal9611", "9611", SOC_EXYNOS_9611, soc, 10)
SOC_EQ(tmp, "universal9810", "9810", SOC_EXYNOS_9810, soc, 10)
SOC_EQ(tmp, "universal9820", "9820", SOC_EXYNOS_9820, soc, 8)
SOC_EQ(tmp, "universal9825", "9825", SOC_EXYNOS_9825, soc, 7)
// New exynos. Dont know if they will work //
SOC_EQ(tmp, "universal1080", "1080", SOC_EXYNOS_1080, soc, 5)
SOC_EQ(tmp, "universal990", "990", SOC_EXYNOS_990, soc, 7)
SOC_EQ(tmp, "universal980", "980", SOC_EXYNOS_980, soc, 8)
SOC_EQ(tmp, "universal880", "880", SOC_EXYNOS_880, soc, 8)
SOC_EXY_EQ(tmp, tmpsoc, "3475", SOC_EXYNOS_3475, soc, 28)
SOC_EXY_EQ(tmp, tmpsoc, "4210", SOC_EXYNOS_4210, soc, 45)
SOC_EXY_EQ(tmp, tmpsoc, "4212", SOC_EXYNOS_4212, soc, 32)
SOC_EXY_EQ(tmp, tmpsoc, "4412", SOC_EXYNOS_4412, soc, 32)
SOC_EXY_EQ(tmp, tmpsoc, "5250", SOC_EXYNOS_5250, soc, 32)
SOC_EXY_EQ(tmp, tmpsoc, "5410", SOC_EXYNOS_5410, soc, 28)
SOC_EXY_EQ(tmp, tmpsoc, "5420", SOC_EXYNOS_5420, soc, 28)
SOC_EXY_EQ(tmp, tmpsoc, "5422", SOC_EXYNOS_5422, soc, 28)
SOC_EXY_EQ(tmp, tmpsoc, "5430", SOC_EXYNOS_5430, soc, 20)
SOC_EXY_EQ(tmp, tmpsoc, "5433", SOC_EXYNOS_5433, soc, 20)
SOC_EXY_EQ(tmp, tmpsoc, "5260", SOC_EXYNOS_5260, soc, 28)
SOC_EXY_EQ(tmp, tmpsoc, "7270", SOC_EXYNOS_7270, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7420", SOC_EXYNOS_7420, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7570", SOC_EXYNOS_7570, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7570", SOC_EXYNOS_7570, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7870", SOC_EXYNOS_7870, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7870", SOC_EXYNOS_7870, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7872", SOC_EXYNOS_7872, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7880", SOC_EXYNOS_7880, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7884", SOC_EXYNOS_7884, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7885", SOC_EXYNOS_7885, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "7904", SOC_EXYNOS_7904, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "8890", SOC_EXYNOS_8890, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "8895", SOC_EXYNOS_8895, soc, 10)
SOC_EXY_EQ(tmp, tmpsoc, "9110", SOC_EXYNOS_9110, soc, 14)
SOC_EXY_EQ(tmp, tmpsoc, "9609", SOC_EXYNOS_9609, soc, 10)
SOC_EXY_EQ(tmp, tmpsoc, "9610", SOC_EXYNOS_9610, soc, 10)
SOC_EXY_EQ(tmp, tmpsoc, "9611", SOC_EXYNOS_9611, soc, 10)
SOC_EXY_EQ(tmp, tmpsoc, "9810", SOC_EXYNOS_9810, soc, 10)
SOC_EXY_EQ(tmp, tmpsoc, "9820", SOC_EXYNOS_9820, soc, 8)
SOC_EXY_EQ(tmp, tmpsoc, "9825", SOC_EXYNOS_9825, soc, 7)
SOC_EXY_EQ(tmp, tmpsoc, "1080", SOC_EXYNOS_1080, soc, 5)
SOC_EXY_EQ(tmp, tmpsoc, "990", SOC_EXYNOS_990, soc, 7)
SOC_EXY_EQ(tmp, tmpsoc, "980", SOC_EXYNOS_980, soc, 8)
SOC_EXY_EQ(tmp, tmpsoc, "880", SOC_EXYNOS_880, soc, 8)
SOC_END
}
bool match_mediatek(char* soc_name, struct system_on_chip* soc) {
char* tmp;
char* soc_name_upper = toupperstr(soc_name);
if((tmp = strstr(soc_name, "MT")) == NULL)
if((tmp = strstr(soc_name_upper, "MT")) == NULL)
return false;
SOC_START
// Dimensity //
SOC_EQ(tmp, "MT6889", "Dimensity 1000", SOC_MTK_MT6889, soc, 7)
SOC_EQ(tmp, "MT6885Z", "Dimensity 1000L", SOC_MTK_MT6885Z, soc, 7)
//SOC_EQ(tmp, "?", "Dimensity 700", SOC_MTK_, soc, 7)
SOC_EQ(tmp, "MT6853", "Dimensity 720", SOC_MTK_MT6853, soc, 7)
SOC_EQ(tmp, "MT6893", "Dimensity 1200", SOC_MTK_MT6893, soc, 6)
SOC_EQ(tmp, "MT6891", "Dimensity 1100", SOC_MTK_MT6891, soc, 6)
SOC_EQ(tmp, "MT6889", "Dimensity 1000", SOC_MTK_MT6889, soc, 7)
SOC_EQ(tmp, "MT6885Z", "Dimensity 1000L", SOC_MTK_MT6885Z, soc, 7)
//SOC_EQ(tmp, "?", "Dimensity 700", SOC_MTK_, soc, 7)
SOC_EQ(tmp, "MT6853", "Dimensity 720", SOC_MTK_MT6853, soc, 7)
SOC_EQ(tmp, "MT6873", "Dimensity 800", SOC_MTK_MT6873, soc, 7)
SOC_EQ(tmp, "MT6875", "Dimensity 820", SOC_MTK_MT6875, soc, 7)
// Helio //
// Helio //
SOC_EQ(tmp, "MT6761D", "Helio A20", SOC_MTK_MT6761D, soc, 12)
SOC_EQ(tmp, "MT6761", "Helio A22", SOC_MTK_MT6761, soc, 12)
SOC_EQ(tmp, "MT6762D", "Helio A25", SOC_MTK_MT6762D, soc, 12)
@@ -287,7 +313,7 @@ bool match_mediatek(char* soc_name, struct system_on_chip* soc) {
*
* If Qualcomm official website reports the SoC name without the initial two or three SKU name,
* we assume APQ if second number is 0, or MSM if second number is different than 0
*
*
* All SoC names here have been retrieved from official Qualcomm resources. However, Linux kernel
* and Android may report the SoC with slightly different. Therefore, this function needs some
* rework (e.g, debug with http://specdevice.com/unmoderated.php?lang=en)
@@ -299,11 +325,11 @@ bool match_qualcomm(char* soc_name, struct system_on_chip* soc) {
if((tmp = strstr(soc_name_upper, "MSM")) != NULL);
else if((tmp = strstr(soc_name_upper, "SDM")) != NULL);
else if((tmp = strstr(soc_name_upper, "APQ")) != NULL);
else if((tmp = strstr(soc_name_upper, "SM")) != NULL);
else if((tmp = strstr(soc_name_upper, "QM")) != NULL);
else if((tmp = strstr(soc_name_upper, "SM")) != NULL);
else if((tmp = strstr(soc_name_upper, "QM")) != NULL);
else if((tmp = strstr(soc_name_upper, "QSD")) != NULL);
else return false;
SOC_START
// Snapdragon S1 //
SOC_EQ(tmp, "QSD8650", "S1", SOC_SNAPD_QSD8650, soc, 65)
@@ -317,37 +343,37 @@ bool match_qualcomm(char* soc_name, struct system_on_chip* soc) {
SOC_EQ(tmp, "MSM7625A", "S1", SOC_SNAPD_MSM7625A, soc, 45)
SOC_EQ(tmp, "MSM7225A", "S1", SOC_SNAPD_MSM7225A, soc, 45)
// Snapdragon S2 //
SOC_EQ(tmp, "MSM8655", "S2", SOC_SNAPD_MSM8655, soc, 45)
SOC_EQ(tmp, "MSM8255", "S2", SOC_SNAPD_MSM8255, soc, 45)
SOC_EQ(tmp, "MSM8655", "S2", SOC_SNAPD_MSM8655, soc, 45)
SOC_EQ(tmp, "MSM8255", "S2", SOC_SNAPD_MSM8255, soc, 45)
SOC_EQ(tmp, "APQ8055", "S2", SOC_SNAPD_APQ8055, soc, 45)
SOC_EQ(tmp, "MSM7630", "S2", SOC_SNAPD_MSM7630, soc, 45)
SOC_EQ(tmp, "MSM7230", "S2", SOC_SNAPD_MSM7230, soc, 45)
SOC_EQ(tmp, "MSM7230", "S2", SOC_SNAPD_MSM7230, soc, 45)
// Snapdragon S3 //
SOC_EQ(tmp, "MSM8660", "S3", SOC_SNAPD_MSM8660, soc, 45)
SOC_EQ(tmp, "MSM8260", "S3", SOC_SNAPD_MSM8260, soc, 45)
SOC_EQ(tmp, "APQ8060", "S3", SOC_SNAPD_APQ8060, soc, 45)
SOC_EQ(tmp, "MSM8660", "S3", SOC_SNAPD_MSM8660, soc, 45)
SOC_EQ(tmp, "MSM8260", "S3", SOC_SNAPD_MSM8260, soc, 45)
SOC_EQ(tmp, "APQ8060", "S3", SOC_SNAPD_APQ8060, soc, 45)
// Snapdragon S4 //
SOC_EQ(tmp, "MSM8225", "S4 Play", SOC_SNAPD_MSM8225, soc, 45)
SOC_EQ(tmp, "MSM8625", "S4 Play", SOC_SNAPD_MSM8625, soc, 45)
SOC_EQ(tmp, "APQ8060A", "S4 Plus", SOC_SNAPD_APQ8060A, soc, 28)
SOC_EQ(tmp, "MSM8960", "S4 Plus", SOC_SNAPD_MSM8960, soc, 28)
SOC_EQ(tmp, "MSM8260A", "S4 Plus", SOC_SNAPD_MSM8260A, soc, 28)
SOC_EQ(tmp, "MSM8627", "S4 Plus", SOC_SNAPD_MSM8627, soc, 28)
SOC_EQ(tmp, "MSM8227", "S4 Plus", SOC_SNAPD_MSM8227, soc, 28)
SOC_EQ(tmp, "APQ8064", "S4 Pro", SOC_SNAPD_APQ8064, soc, 28)
SOC_EQ(tmp, "MSM8960T", "S4 Pro", SOC_SNAPD_MSM8960T, soc, 28)
SOC_EQ(tmp, "APQ8060A", "S4 Plus", SOC_SNAPD_APQ8060A, soc, 28)
SOC_EQ(tmp, "MSM8960", "S4 Plus", SOC_SNAPD_MSM8960, soc, 28)
SOC_EQ(tmp, "MSM8260A", "S4 Plus", SOC_SNAPD_MSM8260A, soc, 28)
SOC_EQ(tmp, "MSM8627", "S4 Plus", SOC_SNAPD_MSM8627, soc, 28)
SOC_EQ(tmp, "MSM8227", "S4 Plus", SOC_SNAPD_MSM8227, soc, 28)
SOC_EQ(tmp, "APQ8064", "S4 Pro", SOC_SNAPD_APQ8064, soc, 28)
SOC_EQ(tmp, "MSM8960T", "S4 Pro", SOC_SNAPD_MSM8960T, soc, 28)
// Snapdragon 2XX //
SOC_EQ(tmp, "MSM8110", "200", SOC_SNAPD_MSM8110, soc, 28)
SOC_EQ(tmp, "MSM8210", "200", SOC_SNAPD_MSM8210, soc, 28)
SOC_EQ(tmp, "MSM8610", "200", SOC_SNAPD_MSM8610, soc, 28)
SOC_EQ(tmp, "MSM8112", "200", SOC_SNAPD_MSM8112, soc, 28)
SOC_EQ(tmp, "MSM8212", "200", SOC_SNAPD_MSM8212, soc, 28)
SOC_EQ(tmp, "MSM8612", "200", SOC_SNAPD_MSM8612, soc, 28)
SOC_EQ(tmp, "MSM8225Q", "200", SOC_SNAPD_MSM8225Q, soc, 45)
SOC_EQ(tmp, "MSM8625Q", "200", SOC_SNAPD_MSM8625Q, soc, 45)
SOC_EQ(tmp, "MSM8208", "208", SOC_SNAPD_MSM8208, soc, 28)
SOC_EQ(tmp, "MSM8905", "205", SOC_SNAPD_MSM8905, soc, 28)
SOC_EQ(tmp, "MSM8909", "210 / 212", SOC_SNAPD_MSM8909, soc, 28) // In the future, we can differenciate them using frequency
SOC_EQ(tmp, "MSM8110", "200", SOC_SNAPD_MSM8110, soc, 28)
SOC_EQ(tmp, "MSM8210", "200", SOC_SNAPD_MSM8210, soc, 28)
SOC_EQ(tmp, "MSM8610", "200", SOC_SNAPD_MSM8610, soc, 28)
SOC_EQ(tmp, "MSM8112", "200", SOC_SNAPD_MSM8112, soc, 28)
SOC_EQ(tmp, "MSM8212", "200", SOC_SNAPD_MSM8212, soc, 28)
SOC_EQ(tmp, "MSM8612", "200", SOC_SNAPD_MSM8612, soc, 28)
SOC_EQ(tmp, "MSM8225Q", "200", SOC_SNAPD_MSM8225Q, soc, 45)
SOC_EQ(tmp, "MSM8625Q", "200", SOC_SNAPD_MSM8625Q, soc, 45)
SOC_EQ(tmp, "MSM8208", "208", SOC_SNAPD_MSM8208, soc, 28)
SOC_EQ(tmp, "MSM8905", "205", SOC_SNAPD_MSM8905, soc, 28)
SOC_EQ(tmp, "MSM8909", "210 / 212", SOC_SNAPD_MSM8909, soc, 28) // In the future, we can differentiate them using frequency
SOC_EQ(tmp, "QM215", "215", SOC_SNAPD_QM215, soc, 28)
// Snapdragon 4XX //
SOC_EQ(tmp, "APQ8028", "400", SOC_SNAPD_APQ8028, soc, 28)
@@ -424,6 +450,7 @@ bool match_qualcomm(char* soc_name, struct system_on_chip* soc) {
SOC_EQ(tmp, "SM8250", "865", SOC_SNAPD_SM8250, soc, 7)
SOC_EQ(tmp, "SM8250-AB", "865+", SOC_SNAPD_SM8250_AB, soc, 7)
SOC_EQ(tmp, "SM8350", "888", SOC_SNAPD_SM8350, soc, 5)
SOC_EQ(tmp, "SM8350-AC", "888+", SOC_SNAPD_SM8350, soc, 5)
SOC_END
}
@@ -450,21 +477,20 @@ struct system_on_chip* parse_soc_from_string(struct system_on_chip* soc) {
if(match_special(raw_name, soc))
return soc;
if (match_qualcomm(raw_name, soc))
return soc;
if(match_mediatek(raw_name, soc))
return soc;
if(match_exynos(raw_name, soc))
return soc;
if(match_hisilicon(raw_name, soc))
return soc;
match_broadcom(raw_name, soc);
return soc;
}
@@ -475,53 +501,122 @@ static inline int android_property_get(const char* key, char* value) {
return __system_property_get(key, value);
}
void try_parse_soc_from_string(struct system_on_chip* soc, int soc_len, char* soc_str) {
soc->raw_name = emalloc(sizeof(char) * (soc_len + 1));
strncpy(soc->raw_name, soc_str, soc_len + 1);
soc->raw_name[soc_len] = '\0';
soc->soc_vendor = SOC_VENDOR_UNKNOWN;
parse_soc_from_string(soc);
}
struct system_on_chip* guess_soc_from_android(struct system_on_chip* soc) {
char tmp[100];
int property_len = 0;
property_len = android_property_get("ro.mediatek.platform", (char *) &tmp);
if(property_len > 0) {
soc->raw_name = malloc(sizeof(char) * (property_len + 1));
strncpy(soc->raw_name, tmp, property_len + 1);
soc->raw_name[property_len] = '\0';
soc->soc_vendor = SOC_VENDOR_UNKNOWN;
return parse_soc_from_string(soc);
try_parse_soc_from_string(soc, property_len, tmp);
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) printWarn("SoC detection failed using Android property ro.mediatek.platform: %s", tmp);
else return soc;
}
property_len = android_property_get("ro.product.board", (char *) &tmp);
if(property_len > 0) {
soc->raw_name = malloc(sizeof(char) * (property_len + 1));
strncpy(soc->raw_name, tmp, property_len + 1);
soc->raw_name[property_len] = '\0';
soc->soc_vendor = SOC_VENDOR_UNKNOWN;
return parse_soc_from_string(soc);
}
if(property_len > 0) {
try_parse_soc_from_string(soc, property_len, tmp);
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) printWarn("SoC detection failed using Android property ro.product.board: %s", tmp);
else return soc;
}
property_len = android_property_get("ro.board.platform", (char *) &tmp);
if(property_len > 0) {
try_parse_soc_from_string(soc, property_len, tmp);
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) printWarn("SoC detection failed using Android property ro.board.platform: %s", tmp);
else return soc;
}
return soc;
}
#endif
struct system_on_chip* guess_soc_from_cpuinfo(struct system_on_chip* soc) {
char* tmp = get_hardware_from_cpuinfo(&strlen);
char* tmp = get_hardware_from_cpuinfo();
if(tmp != NULL) {
soc->raw_name = tmp;
return parse_soc_from_string(soc);
}
return soc;
}
int hex2int(char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return -1;
}
// https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
struct system_on_chip* guess_soc_raspbery_pi(struct system_on_chip* soc) {
char* revision = get_revision_from_cpuinfo();
if(revision == NULL) {
printWarn("[RPi] Couldn't find revision field in cpuinfo");
return soc;
}
if(strlen(revision) != 6) {
printWarn("[RPi] Found invalid RPi revision code: '%s'", revision);
return soc;
}
int arr_size = ARRAY_SIZE(soc_rpi_string);
int pppp = hex2int(revision[2]);
if(pppp == -1) {
printErr("[RPi] Found invalid RPi PPPP code: %s", revision[2]);
return soc;
}
if(pppp > arr_size) {
printErr("[RPi] Found invalid RPi PPPP code: %d while max is %d", pppp, arr_size);
return soc;
}
char* soc_raw_name = soc_rpi_string[pppp];
/*int soc_len = strlen(soc_raw_name);
soc->raw_name = emalloc(sizeof(char) * (soc_len + 1));
strncpy(soc->raw_name, soc_raw_name, soc_len + 1);*/
match_broadcom(soc_raw_name, soc);
return soc;
}
struct system_on_chip* get_soc() {
struct system_on_chip* soc = malloc(sizeof(struct system_on_chip));
struct system_on_chip* soc = emalloc(sizeof(struct system_on_chip));
soc->raw_name = NULL;
soc->soc_vendor = SOC_VENDOR_UNKNOWN;
soc->process = UNKNOWN;
#ifdef __linux__
bool isRPi = is_raspberry_pi();
if(isRPi) {
soc = guess_soc_raspbery_pi(soc);
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) {
printWarn("SoC detection failed using revision code");
}
else {
return soc;
}
}
soc = guess_soc_from_cpuinfo(soc);
if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) {
if(soc->raw_name != NULL)
printWarn("SoC detection failed using /proc/cpuinfo: Found '%s' string", soc->raw_name);
printWarn("SoC detection failed using /proc/cpuinfo: Found '%s' string", soc->raw_name);
else
printWarn("SoC detection failed using /proc/cpuinfo: No string found");
#ifdef __ANDROID__
@@ -529,16 +624,19 @@ struct system_on_chip* get_soc() {
if(soc->raw_name == NULL)
printWarn("SoC detection failed using Android: No string found");
else if(soc->soc_vendor == SOC_VENDOR_UNKNOWN)
printWarn("SoC detection failed using Android: Found '%s' string", soc->raw_name);
#endif
printWarn("SoC detection failed using Android: Found '%s' string", soc->raw_name);
#endif // ifdef __ANDROID__
}
#elif defined __APPLE__ || __MACH__
fill_soc(soc, "M1", SOC_APPLE_M1, 5);
#endif // ifdef __linux__
if(soc->raw_name == NULL) {
soc->raw_name = malloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
soc->raw_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
snprintf(soc->raw_name, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
}
return soc;
return soc;
}
char* get_soc_name(struct system_on_chip* soc) {
@@ -553,16 +651,15 @@ VENDOR get_soc_vendor(struct system_on_chip* soc) {
char* get_str_process(struct system_on_chip* soc) {
char* str;
if(soc->process == UNKNOWN) {
str = malloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
str = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
}
else {
str = malloc(sizeof(char) * 5);
str = emalloc(sizeof(char) * 5);
memset(str, 0, sizeof(char) * 5);
snprintf(str, 5, "%dnm", soc->process);
snprintf(str, 5, "%dnm", soc->process);
}
return str;
}

View File

@@ -12,7 +12,8 @@ enum {
SOC_VENDOR_MEDIATEK,
SOC_VENDOR_EXYNOS,
SOC_VENDOR_KIRIN,
SOC_VENDOR_BROADCOM
SOC_VENDOR_BROADCOM,
SOC_VENDOR_APPLE
};
struct system_on_chip {

View File

@@ -63,6 +63,8 @@ enum {
SOC_EXYNOS_980,
SOC_EXYNOS_880,
// Mediatek //
SOC_MTK_MT6893,
SOC_MTK_MT6891,
SOC_MTK_MT6889,
SOC_MTK_MT6885Z,
SOC_MTK_MT6853,
@@ -250,14 +252,17 @@ enum {
SOC_SNAPD_SM8250,
SOC_SNAPD_SM8250_AB,
SOC_SNAPD_SM8350,
// APPLE
SOC_APPLE_M1
};
inline static VENDOR get_soc_vendor_from_soc(SOC soc) {
if(soc >= SOC_BCM_2835 && soc <= SOC_BCM_21654) return SOC_VENDOR_BROADCOM;
else if(soc >= SOC_HISILICON_3620 && soc <= SOC_HISILICON_3690) return SOC_VENDOR_KIRIN;
else if(soc >= SOC_EXYNOS_3475 && soc <= SOC_EXYNOS_880) return SOC_VENDOR_EXYNOS;
else if(soc >= SOC_MTK_MT6889 && soc <= SOC_MTK_MT8783) return SOC_VENDOR_MEDIATEK;
else if(soc >= SOC_MTK_MT6893 && soc <= SOC_MTK_MT8783) return SOC_VENDOR_MEDIATEK;
else if(soc >= SOC_SNAPD_QSD8650 && soc <= SOC_SNAPD_SM8350) return SOC_VENDOR_SNAPDRAGON;
else if(soc >= SOC_APPLE_M1 && soc <= SOC_APPLE_M1) return SOC_VENDOR_APPLE;
return SOC_VENDOR_UNKNOWN;
}

25
src/arm/sysctl.c Normal file
View File

@@ -0,0 +1,25 @@
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "../common/global.h"
#include "../common/cpu.h"
uint32_t get_sys_info_by_name(char* name) {
size_t size = 0;
uint32_t ret = 0;
if (sysctlbyname(name, NULL, &size, NULL, 0) != 0) {
printWarn("sysctlbyname(%s) failed: %s", name, strerror(errno));
}
else if (size == sizeof(uint32_t)) {
sysctlbyname(name, &ret, &size, NULL, 0);
}
else {
printWarn("sysctl does not support non-integer lookup for '%s'", name);
}
return ret;
}

6
src/arm/sysctl.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef __SYSCTL__
#define __SYSCTL__
uint32_t get_sys_info_by_name(char* name);
#endif

View File

@@ -7,8 +7,6 @@
#include "uarch.h"
#include "../common/global.h"
#define STRING_UNKNOWN "Unknown"
// Data not available
#define NA -1
@@ -34,6 +32,7 @@ enum {
ISA_ARMv8_1_A,
ISA_ARMv8_2_A,
ISA_ARMv8_3_A,
ISA_ARMv8_4_A,
};
enum {
@@ -45,26 +44,27 @@ enum {
UARCH_ARM1156,
UARCH_ARM1176,
UARCH_ARM11MPCORE,
UARCH_CORTEX_A5,
UARCH_CORTEX_A7,
UARCH_CORTEX_A8,
UARCH_CORTEX_A9,
UARCH_CORTEX_A12,
UARCH_CORTEX_A15,
UARCH_CORTEX_A17,
UARCH_CORTEX_A32,
UARCH_CORTEX_A35,
UARCH_CORTEX_A53,
UARCH_CORTEX_A5,
UARCH_CORTEX_A7,
UARCH_CORTEX_A8,
UARCH_CORTEX_A9,
UARCH_CORTEX_A12,
UARCH_CORTEX_A15,
UARCH_CORTEX_A17,
UARCH_CORTEX_A32,
UARCH_CORTEX_A35,
UARCH_CORTEX_A53,
UARCH_CORTEX_A55r0, // ARM Cortex-A55 revision 0 (restricted dual-issue capabilities compared to revision 1+).
UARCH_CORTEX_A55,
UARCH_CORTEX_A57,
UARCH_CORTEX_A65,
UARCH_CORTEX_A72,
UARCH_CORTEX_A73,
UARCH_CORTEX_A75,
UARCH_CORTEX_A55,
UARCH_CORTEX_A57,
UARCH_CORTEX_A65,
UARCH_CORTEX_A72,
UARCH_CORTEX_A73,
UARCH_CORTEX_A75,
UARCH_CORTEX_A76,
UARCH_CORTEX_A77,
UARCH_CORTEX_A78,
UARCH_CORTEX_A78,
UARCH_CORTEX_X1,
UARCH_NEOVERSE_N1,
UARCH_NEOVERSE_E1,
UARCH_SCORPION,
@@ -93,6 +93,8 @@ enum {
UARCH_TEMPEST, // Apple A12 processor (big cores).
UARCH_LIGHTNING, // Apple A13 processor (big cores).
UARCH_THUNDER, // Apple A13 processor (little cores).
UARCH_ICESTORM, // Apple M1 processor (little cores).
UARCH_FIRESTORM, // Apple M1 processor (big cores).
// CAVIUM
UARCH_THUNDERX, // Cavium ThunderX
UARCH_THUNDERX2, // Cavium ThunderX2 (originally Broadcom Vulkan).
@@ -118,17 +120,18 @@ static const ISA isas_uarch[] = {
[UARCH_CORTEX_A17] = ISA_ARMv7_A,
[UARCH_CORTEX_A32] = ISA_ARMv8_A_AArch32,
[UARCH_CORTEX_A35] = ISA_ARMv8_A,
[UARCH_CORTEX_A53] = ISA_ARMv8_A,
[UARCH_CORTEX_A53] = ISA_ARMv8_A,
[UARCH_CORTEX_A55r0] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A55] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A57] = ISA_ARMv8_A,
[UARCH_CORTEX_A65] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A65] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A72] = ISA_ARMv8_A,
[UARCH_CORTEX_A73] = ISA_ARMv8_A,
[UARCH_CORTEX_A75] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A76] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A76] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A77] = ISA_ARMv8_2_A,
[UARCH_CORTEX_A78] = ISA_ARMv8_2_A,
[UARCH_CORTEX_X1] = ISA_ARMv8_2_A,
[UARCH_NEOVERSE_N1] = ISA_ARMv8_2_A,
[UARCH_NEOVERSE_E1] = ISA_ARMv8_2_A,
[UARCH_BRAHMA_B15] = ISA_ARMv7_A, // Same as Cortex-A15
@@ -150,6 +153,8 @@ static const ISA isas_uarch[] = {
[UARCH_EXYNOS_M3] = ISA_ARMv8_A,
[UARCH_EXYNOS_M4] = ISA_ARMv8_2_A,
[UARCH_EXYNOS_M5] = ISA_ARMv8_2_A,
[UARCH_ICESTORM] = ISA_ARMv8_4_A,
[UARCH_FIRESTORM] = ISA_ARMv8_4_A,
[UARCH_PJ4] = ISA_ARMv7_A,
};
@@ -164,24 +169,25 @@ static char* isas_string[] = {
[ISA_ARMv8_1_A] = "ARMv8.1",
[ISA_ARMv8_2_A] = "ARMv8.2",
[ISA_ARMv8_3_A] = "ARMv8.3",
[ISA_ARMv8_4_A] = "ARMv8.4"
};
#define UARCH_START if (false) {}
#define CHECK_UARCH(arch, cpu, im_, p_, v_, r_, str, uarch, vendor) \
else if (im_ == im && p_ == p && (v_ == NA || v_ == v) && (r_ == NA || r_ == r)) fill_uarch(arch, cpu, str, uarch, vendor);
#define UARCH_END else { printBug("Unknown microarchitecture detected: IM=0x%.8X P=0x%.8X V=0x%.8X R=0x%.8X", im, p, v, r); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u, VENDOR vendor) {
arch->uarch = u;
arch->uarch = u;
arch->isa = isas_uarch[arch->uarch];
cpu->cpu_vendor = vendor;
arch->uarch_str = malloc(sizeof(char) * (strlen(str)+1));
arch->uarch_str = emalloc(sizeof(char) * (strlen(str)+1));
strcpy(arch->uarch_str, str);
arch->isa_str = malloc(sizeof(char) * (strlen(isas_string[arch->isa])+1));
strcpy(arch->isa_str, isas_string[arch->isa]);
}
arch->isa_str = emalloc(sizeof(char) * (strlen(isas_string[arch->isa])+1));
strcpy(arch->isa_str, isas_string[arch->isa]);
}
/*
* Codes are based on pytorch/cpuinfo, more precisely:
@@ -191,7 +197,7 @@ void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u,
* - https://elixir.bootlin.com/linux/latest/source/arch/arm/include/asm/cputype.h
*/
struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
struct uarch* arch = malloc(sizeof(struct uarch));
struct uarch* arch = emalloc(sizeof(struct uarch));
uint32_t im = midr_get_implementer(midr);
uint32_t p = midr_get_part(midr);
uint32_t v = midr_get_variant(midr);
@@ -221,7 +227,7 @@ struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
CHECK_UARCH(arch, cpu, 'A', 0xD03, NA, NA, "Cortex-A53", UARCH_CORTEX_A53, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD04, NA, NA, "Cortex-A35", UARCH_CORTEX_A35, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD05, NA, 0, "Cortex-A55", UARCH_CORTEX_A55r0, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD05, NA, NA, "Cortex-A55", UARCH_CORTEX_A55, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD05, NA, NA, "Cortex-A55", UARCH_CORTEX_A55, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD06, NA, NA, "Cortex-A65", UARCH_CORTEX_A65, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD07, NA, NA, "Cortex-A57", UARCH_CORTEX_A57, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD08, NA, NA, "Cortex-A72", UARCH_CORTEX_A72, CPU_VENDOR_ARM)
@@ -232,27 +238,28 @@ struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
CHECK_UARCH(arch, cpu, 'A', 0xD0D, NA, NA, "Cortex-A77", UARCH_CORTEX_A77, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD0E, NA, NA, "Cortex-A76", UARCH_CORTEX_A76, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD41, NA, NA, "Cortex-A78", UARCH_CORTEX_A78, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD44, NA, NA, "Cortex-X1", UARCH_CORTEX_X1, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'A', 0xD4A, NA, NA, "Neoverse E1", UARCH_NEOVERSE_E1, CPU_VENDOR_ARM)
CHECK_UARCH(arch, cpu, 'B', 0x00F, NA, NA, "Brahma B15", UARCH_BRAHMA_B15, CPU_VENDOR_BROADCOM)
CHECK_UARCH(arch, cpu, 'B', 0x100, NA, NA, "Brahma B53", UARCH_BRAHMA_B53, CPU_VENDOR_BROADCOM)
CHECK_UARCH(arch, cpu, 'B', 0x516, NA, NA, "ThunderX2", UARCH_THUNDERX2, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'C', 0x0A0, NA, NA, "ThunderX", UARCH_THUNDERX, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'C', 0x0A1, NA, NA, "ThunderX 88XX", UARCH_THUNDERX, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'C', 0x0A2, NA, NA, "ThunderX 81XX", UARCH_THUNDERX, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'C', 0x0A3, NA, NA, "ThunderX 81XX", UARCH_THUNDERX, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'C', 0x0AF, NA, NA, "ThunderX2 99XX", UARCH_THUNDERX2, CPU_VENDOR_CAVIUM)
CHECK_UARCH(arch, cpu, 'H', 0xD01, NA, NA, "TaiShan v110", UARCH_TAISHAN_V110, CPU_VENDOR_HUAWUEI) // Kunpeng 920 series
CHECK_UARCH(arch, cpu, 'H', 0xD40, NA, NA, "Cortex-A76", UARCH_CORTEX_A76, CPU_VENDOR_ARM) // Kirin 980 Big/Medium cores -> Cortex-A76
CHECK_UARCH(arch, cpu, 'N', 0x000, NA, NA, "Denver", UARCH_DENVER, CPU_VENDOR_NVIDIA)
CHECK_UARCH(arch, cpu, 'N', 0x003, NA, NA, "Denver2", UARCH_DENVER2, CPU_VENDOR_NVIDIA)
CHECK_UARCH(arch, cpu, 'N', 0x004, NA, NA, "Carmel", UARCH_CARMEL, CPU_VENDOR_NVIDIA)
CHECK_UARCH(arch, cpu, 'P', 0x000, NA, NA, "Xgene", UARCH_XGENE, CPU_VENDOR_APM)
CHECK_UARCH(arch, cpu, 'Q', 0x00F, NA, NA, "Scorpion", UARCH_SCORPION, CPU_VENDOR_QUALCOMM)
CHECK_UARCH(arch, cpu, 'Q', 0x02D, NA, NA, "Scorpion", UARCH_KRAIT, CPU_VENDOR_QUALCOMM)
CHECK_UARCH(arch, cpu, 'Q', 0x04D, 1, 0, "Krait 200", UARCH_KRAIT, CPU_VENDOR_QUALCOMM)
@@ -273,29 +280,31 @@ struct uarch* get_uarch_from_midr(uint32_t midr, struct cpuInfo* cpu) {
CHECK_UARCH(arch, cpu, 'Q', 0x803, NA, NA, "Kryo 385 Silver", UARCH_CORTEX_A55r0, CPU_VENDOR_ARM) // Low-power Kryo 385 "Silver" -> Cortex-A55r0
CHECK_UARCH(arch, cpu, 'Q', 0x804, NA, NA, "Kryo 485 Gold", UARCH_CORTEX_A76, CPU_VENDOR_ARM) // High-performance Kryo 485 "Gold" / "Gold Prime" -> Cortex-A76
CHECK_UARCH(arch, cpu, 'Q', 0x805, NA, NA, "Kryo 485 Silver", UARCH_CORTEX_A55, CPU_VENDOR_ARM) // Low-performance Kryo 485 "Silver" -> Cortex-A55
CHECK_UARCH(arch, cpu, 'Q', 0xC00, NA, NA, "Falkor", UARCH_FALKOR, CPU_VENDOR_QUALCOMM)
CHECK_UARCH(arch, cpu, 'Q', 0xC01, NA, NA, "Saphira", UARCH_SAPHIRA, CPU_VENDOR_QUALCOMM)
CHECK_UARCH(arch, cpu, 'Q', 0xC00, NA, NA, "Falkor", UARCH_FALKOR, CPU_VENDOR_QUALCOMM)
CHECK_UARCH(arch, cpu, 'Q', 0xC01, NA, NA, "Saphira", UARCH_SAPHIRA, CPU_VENDOR_QUALCOMM)
CHECK_UARCH(arch, cpu, 'S', 0x001, 1, NA, "Exynos M1", UARCH_EXYNOS_M1, CPU_VENDOR_SAMSUNG) // Exynos 8890
CHECK_UARCH(arch, cpu, 'S', 0x001, 4, NA, "Exynos M2", UARCH_EXYNOS_M2, CPU_VENDOR_SAMSUNG) // Exynos 8895
CHECK_UARCH(arch, cpu, 'S', 0x002, 1, NA, "Exynos M3", UARCH_EXYNOS_M3, CPU_VENDOR_SAMSUNG) // Exynos 9810
CHECK_UARCH(arch, cpu, 'S', 0x003, 1, NA, "Exynos M4", UARCH_EXYNOS_M4, CPU_VENDOR_SAMSUNG) // Exynos 9820
CHECK_UARCH(arch, cpu, 'S', 0x004, 1, NA, "Exynos M5", UARCH_EXYNOS_M5, CPU_VENDOR_SAMSUNG) // Exynos 9820 (this one looks wrong at uarch.c ...)
CHECK_UARCH(arch, cpu, 'a', 0x022, NA, NA, "Icestorm", UARCH_ICESTORM, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'a', 0x023, NA, NA, "Firestorm", UARCH_FIRESTORM, CPU_VENDOR_APPLE)
CHECK_UARCH(arch, cpu, 'V', 0x581, NA, NA, "PJ4", UARCH_PJ4, CPU_VENDOR_MARVELL)
CHECK_UARCH(arch, cpu, 'V', 0x584, NA, NA, "PJ4B-MP", UARCH_PJ4, CPU_VENDOR_MARVELL)
UARCH_END
return arch;
}
char* get_str_uarch(struct cpuInfo* cpu) {
return cpu->arch->uarch_str;
return cpu->arch->uarch_str;
}
void free_uarch_struct(struct uarch* arch) {
void free_uarch_struct(struct uarch* arch) {
free(arch->uarch_str);
free(arch);
}

View File

@@ -1,6 +1,8 @@
#include "../common/global.h"
#include "udev.h"
#include "midr.h"
#define _PATH_DEVICETREE_MODEL "/sys/firmware/devicetree/base/model"
#define _PATH_CPUS_PRESENT _PATH_SYS_SYSTEM _PATH_SYS_CPU "/present"
#define _PATH_CPUINFO "/proc/cpuinfo"
//#define _PATH_CPUINFO "cpuinfo_debug"
@@ -11,6 +13,7 @@
#define CPUINFO_CPU_PART_STR "CPU part\t: "
#define CPUINFO_CPU_REVISION_STR "CPU revision\t: "
#define CPUINFO_HARDWARE_STR "Hardware\t: "
#define CPUINFO_REVISION_STR "Revision\t: "
#define CPUINFO_CPU_STRING "processor"
@@ -24,7 +27,7 @@ int get_ncores_from_cpuinfo() {
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUS_PRESENT, &filelen)) == NULL) {
perror("open");
printWarn("read_file: %s: %s\n", _PATH_CPUS_PRESENT, strerror(errno));
return UNKNOWN;
}
@@ -47,7 +50,7 @@ int get_ncores_from_cpuinfo() {
errno = 0;
ncores = strtol(ncores_str, &end, 10) + 1;
if(errno != 0) {
perror("strtol");
printWarn("strtol: %s:\n", strerror(errno));
return UNKNOWN;
}
@@ -65,7 +68,7 @@ long parse_cpuinfo_field(char* buf, char* field_str, int field_base) {
errno = 0;
long ret = strtol(tmp, &end, field_base);
if(errno != 0) {
perror("strtol");
printWarn("strtol: %s:\n", strerror(errno));
return -1;
}
@@ -78,9 +81,9 @@ uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success) {
char* buf;
*success = true;
if((buf = read_file(_PATH_CPUINFO, &filelen)) == NULL) {
perror("open");
*success = false;
return 0;
printWarn("read_file: %s: %s\n", _PATH_CPUINFO, strerror(errno));
*success = false;
return 0;
}
char* tmp = strstr(buf, CPUINFO_CPU_STRING);
@@ -90,9 +93,9 @@ uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success) {
current_core++;
tmp = strstr(tmp, CPUINFO_CPU_STRING);
}
if(tmp == NULL) {
*success = false;
*success = false;
return 0;
}
@@ -105,36 +108,36 @@ uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success) {
long ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_IMPLEMENTER_STR, 16)) < 0) {
printf("Failed parsing cpu_implementer\n");
*success = false;
printBug("get_midr_from_cpuinfo: Failed parsing cpu_implementer\n");
*success = false;
return 0;
}
cpu_implementer = (uint32_t) ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_ARCHITECTURE_STR, 10)) < 0) {
printf("Failed parsing cpu_architecture\n");
*success = false;
printBug("get_midr_from_cpuinfo: Failed parsing cpu_architecture\n");
*success = false;
return 0;
}
cpu_architecture = (uint32_t) 0xF; // Why?
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_VARIANT_STR, 16)) < 0) {
printf("Failed parsing cpu_variant\n");
*success = false;
printBug("get_midr_from_cpuinfo: Failed parsing cpu_variant\n");
*success = false;
return 0;
}
cpu_variant = (uint32_t) ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_PART_STR, 16)) < 0) {
printf("Failed parsing cpu_part\n");
*success = false;
printBug("get_midr_from_cpuinfo: Failed parsing cpu_part\n");
*success = false;
return 0;
}
cpu_part = (uint32_t) ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_REVISION_STR, 10)) < 0) {
printf("Failed parsing cpu_revision\n");
*success = false;
printBug("get_midr_from_cpuinfo: Failed parsing cpu_revision\n");
*success = false;
return 0;
}
cpu_revision = (uint32_t) ret;
@@ -148,24 +151,45 @@ uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success) {
return midr;
}
char* get_hardware_from_cpuinfo() {
char* get_field_from_cpuinfo(char* CPUINFO_FIELD) {
int filelen;
char* buf;
if((buf = read_file(_PATH_CPUINFO, &filelen)) == NULL) {
perror("open");
return NULL;
printWarn("read_file: %s: %s:\n", _PATH_CPUINFO, strerror(errno));
return NULL;
}
char* tmp1 = strstr(buf, CPUINFO_HARDWARE_STR);
char* tmp1 = strstr(buf, CPUINFO_FIELD);
if(tmp1 == NULL) return NULL;
tmp1 = tmp1 + strlen(CPUINFO_HARDWARE_STR);
tmp1 = tmp1 + strlen(CPUINFO_FIELD);
char* tmp2 = strstr(tmp1, "\n");
int strlen = (1 + (tmp2-tmp1));
char* hardware = malloc(sizeof(char) * strlen);
char* hardware = emalloc(sizeof(char) * strlen);
memset(hardware, 0, sizeof(char) * strlen);
strncpy(hardware, tmp1, tmp2-tmp1);
return hardware;
}
char* get_hardware_from_cpuinfo() {
return get_field_from_cpuinfo(CPUINFO_HARDWARE_STR);
}
char* get_revision_from_cpuinfo() {
return get_field_from_cpuinfo(CPUINFO_REVISION_STR);
}
bool is_raspberry_pi() {
int filelen;
char* buf;
if((buf = read_file(_PATH_DEVICETREE_MODEL, &filelen)) == NULL) {
return false;
}
char* tmp;
if((tmp = strstr(buf, "Raspberry Pi")) == NULL) {
return false;
}
return true;
}

View File

@@ -7,6 +7,8 @@
int get_ncores_from_cpuinfo();
uint32_t get_midr_from_cpuinfo(uint32_t core, bool* success);
char* get_hardware_from_cpuinfo();
char* get_revision_from_cpuinfo();
bool is_raspberry_pi();
#endif

View File

@@ -5,9 +5,13 @@
#include "args.h"
#include "global.h"
#define COLOR_STR_INTEL "intel"
#define COLOR_STR_AMD "amd"
#define COLOR_STR_ARM "arm"
#define NUM_COLORS 5
#define COLOR_STR_INTEL "intel"
#define COLOR_STR_INTEL_NEW "intel-new"
#define COLOR_STR_AMD "amd"
#define COLOR_STR_IBM "ibm"
#define COLOR_STR_ARM "arm"
static const char *SYTLES_STR_LIST[] = {
[STYLE_EMPTY] = NULL,
@@ -21,30 +25,48 @@ struct args_struct {
bool debug_flag;
bool help_flag;
bool raw_flag;
bool accurate_pp;
bool full_cpu_name_flag;
bool logo_long;
bool logo_short;
bool logo_intel_new;
bool logo_intel_old;
bool verbose_flag;
bool version_flag;
STYLE style;
struct colors* colors;
struct color** colors;
};
const char args_chr[] = {
/* [ARG_CHAR_STYLE] = */ 's',
/* [ARG_CHAR_COLOR] = */ 'c',
/* [ARG_CHAR_HELP] = */ 'h',
/* [ARG_CHAR_RAW] = */ 'r',
/* [ARG_CHAR_DEBUG] = */ 'd',
/* [ARG_CHAR_VERBOSE] = */ 'v',
/* [ARG_CHAR_VERSION] = */ 'V',
/* [ARG_STYLE] = */ 's',
/* [ARG_COLOR] = */ 'c',
/* [ARG_HELP] = */ 'h',
/* [ARG_RAW] = */ 'r',
/* [ARG_FULLCPUNAME] = */ 'F',
/* [ARG_LOGO_LONG] = */ 1,
/* [ARG_LOGO_SHORT] = */ 2,
/* [ARG_LOGO_INTEL_NEW] = */ 3,
/* [ARG_LOGO_INTEL_OLD] = */ 4,
/* [ARG_ACCURATE_PP] = */ 5,
/* [ARG_DEBUG] = */ 'd',
/* [ARG_VERBOSE] = */ 'v',
/* [ARG_VERSION] = */ 'V',
};
const char *args_str[] = {
/* [ARG_CHAR_STYLE] = */ "style",
/* [ARG_CHAR_COLOR] = */ "color",
/* [ARG_CHAR_HELP] = */ "help",
/* [ARG_CHAR_RAW] = */ "raw",
/* [ARG_CHAR_DEBUG] = */ "debug",
/* [ARG_CHAR_VERBOSE] = */ "verbose",
/* [ARG_CHAR_VERSION] = */ "version",
/* [ARG_STYLE] = */ "style",
/* [ARG_COLOR] = */ "color",
/* [ARG_HELP] = */ "help",
/* [ARG_RAW] = */ "raw",
/* [ARG_FULLCPUNAME] = */ "full-cpu-name",
/* [ARG_LOGO_LONG] = */ "logo-long",
/* [ARG_LOGO_SHORT] = */ "logo-short",
/* [ARG_LOGO_INTEL_NEW] = */ "logo-intel-new",
/* [ARG_LOGO_INTEL_OLD] = */ "logo-intel-old",
/* [ARG_ACCURATE_PP] = */ "accurate-pp",
/* [ARG_DEBUG] = */ "debug",
/* [ARG_VERBOSE] = */ "verbose",
/* [ARG_VERSION] = */ "version",
};
static struct args_struct args;
@@ -53,7 +75,7 @@ STYLE get_style() {
return args.style;
}
struct colors* get_colors() {
struct color** get_colors() {
return args.colors;
}
@@ -70,7 +92,31 @@ bool show_debug() {
}
bool show_raw() {
return args.raw_flag;
return args.raw_flag;
}
bool accurate_pp() {
return args.accurate_pp;
}
bool show_full_cpu_name() {
return args.full_cpu_name_flag;
}
bool show_logo_long() {
return args.logo_long;
}
bool show_logo_short() {
return args.logo_short;
}
bool show_logo_intel_new() {
return args.logo_intel_new;
}
bool show_logo_intel_old() {
return args.logo_intel_old;
}
bool verbose_enabled() {
@@ -82,121 +128,109 @@ int max_arg_str_length() {
int len = sizeof(args_str) / sizeof(args_str[0]);
for(int i=0; i < len; i++) {
max_len = max(max_len, (int) strlen(args_str[i]));
}
}
return max_len;
}
STYLE parse_style(char* style) {
uint8_t i = 0;
uint8_t styles_count = sizeof(SYTLES_STR_LIST) / sizeof(SYTLES_STR_LIST[0]);
while(i != styles_count && (SYTLES_STR_LIST[i] == NULL || strcmp(SYTLES_STR_LIST[i], style) != 0))
i++;
if(i == styles_count)
return STYLE_INVALID;
return i;
}
void free_colors_struct(struct colors* cs) {
free(cs->c1);
free(cs->c2);
free(cs->c3);
free(cs->c4);
void free_colors_struct(struct color** cs) {
for(int i=0; i < NUM_COLORS; i++) {
free(cs[i]);
}
free(cs);
}
bool parse_color(char* optarg_str, struct colors** cs) {
*cs = malloc(sizeof(struct colors));
(*cs)->c1 = malloc(sizeof(struct color));
(*cs)->c2 = malloc(sizeof(struct color));
(*cs)->c3 = malloc(sizeof(struct color));
(*cs)->c4 = malloc(sizeof(struct color));
struct color** c1 = &((*cs)->c1);
struct color** c2 = &((*cs)->c2);
struct color** c3 = &((*cs)->c3);
struct color** c4 = &((*cs)->c4);
bool parse_color(char* optarg_str, struct color*** cs) {
for(int i=0; i < NUM_COLORS; i++) {
(*cs)[i] = emalloc(sizeof(struct color));
}
struct color** c = *cs;
int32_t ret;
char* str_to_parse = NULL;
bool free_ptr;
if(strcmp(optarg_str, COLOR_STR_INTEL) == 0) {
str_to_parse = malloc(sizeof(char) * 46);
strcpy(str_to_parse, COLOR_DEFAULT_INTEL);
free_ptr = true;
}
else if(strcmp(optarg_str, COLOR_STR_AMD) == 0) {
str_to_parse = malloc(sizeof(char) * 44);
strcpy(str_to_parse, COLOR_DEFAULT_AMD);
free_ptr = true;
}
else if(strcmp(optarg_str, COLOR_STR_ARM) == 0) {
str_to_parse = malloc(sizeof(char) * 46);
strcpy(str_to_parse, COLOR_DEFAULT_ARM);
free_ptr = true;
}
else {
char* color_to_copy = NULL;
bool free_ptr = true;
if(strcmp(optarg_str, COLOR_STR_INTEL) == 0) color_to_copy = COLOR_DEFAULT_INTEL;
else if(strcmp(optarg_str, COLOR_STR_INTEL_NEW) == 0) color_to_copy = COLOR_DEFAULT_INTEL_NEW;
else if(strcmp(optarg_str, COLOR_STR_AMD) == 0) color_to_copy = COLOR_DEFAULT_AMD;
else if(strcmp(optarg_str, COLOR_STR_IBM) == 0) color_to_copy = COLOR_DEFAULT_IBM;
else if(strcmp(optarg_str, COLOR_STR_ARM) == 0) color_to_copy = COLOR_DEFAULT_ARM;
else {
str_to_parse = optarg_str;
free_ptr = false;
}
ret = sscanf(str_to_parse, "%d,%d,%d:%d,%d,%d:%d,%d,%d:%d,%d,%d",
&(*c1)->R, &(*c1)->G, &(*c1)->B,
&(*c2)->R, &(*c2)->G, &(*c2)->B,
&(*c3)->R, &(*c3)->G, &(*c3)->B,
&(*c4)->R, &(*c4)->G, &(*c4)->B);
if(ret != 12) {
printErr("Expected to read 12 values for color but read %d", ret);
return false;
if(str_to_parse == NULL) {
str_to_parse = emalloc(sizeof(char) * (strlen(color_to_copy) + 1));
strcpy(str_to_parse, color_to_copy);
}
//TODO: Refactor c1->R c2->R ... to c[i]->R
if((*c1)->R < 0 || (*c1)->R > 255) {
printErr("Red in color 1 is invalid. Must be in range (0, 255)");
ret = sscanf(str_to_parse, "%d,%d,%d:%d,%d,%d:%d,%d,%d:%d,%d,%d:%d,%d,%d",
&c[0]->R, &c[0]->G, &c[0]->B,
&c[1]->R, &c[1]->G, &c[1]->B,
&c[2]->R, &c[2]->G, &c[2]->B,
&c[3]->R, &c[3]->G, &c[3]->B,
&c[4]->R, &c[4]->G, &c[4]->B);
int expected_colors = 3 * NUM_COLORS;
if(ret != expected_colors) {
printErr("Expected to read %d values for color but read %d", expected_colors, ret);
return false;
}
if((*c1)->G < 0 || (*c1)->G > 255) {
printErr("Green in color 1 is invalid. Must be in range (0, 255)");
return false;
for(int i=0; i < NUM_COLORS; i++) {
if(c[i]->R < 0 || c[i]->R > 255) {
printErr("Red in color %d is invalid: %d; must be in range (0, 255)", i+1, c[i]->R);
return false;
}
if(c[i]->G < 0 || c[i]->G > 255) {
printErr("Green in color %d is invalid: %d; must be in range (0, 255)", i+1, c[i]->G);
return false;
}
if(c[i]->B < 0 || c[i]->B > 255) {
printErr("Blue in color %d is invalid: %d; must be in range (0, 255)", i+1, c[i]->B);
return false;
}
}
if((*c1)->B < 0 || (*c1)->B > 255) {
printErr("Blue in color 1 is invalid. Must be in range (0, 255)");
return false;
}
if((*c2)->R < 0 || (*c2)->R > 255) {
printErr("Red in color 2 is invalid. Must be in range (0, 255)");
return false;
}
if((*c2)->G < 0 || (*c2)->G > 255) {
printErr("Green in color 2 is invalid. Must be in range (0, 255)");
return false;
}
if((*c2)->B < 0 || (*c2)->B > 255) {
printErr("Blue in color 2 is invalid. Must be in range (0, 255)");
return false;
}
if(free_ptr) free (str_to_parse);
return true;
return true;
}
char* build_short_options() {
const char *c = args_chr;
int len = sizeof(args_chr) / sizeof(args_chr[0]);
char* str = (char *) malloc(sizeof(char) * (len*2 + 1));
char* str = (char *) emalloc(sizeof(char) * (len*2 + 1));
memset(str, 0, sizeof(char) * (len*2 + 1));
#ifdef ARCH_X86
sprintf(str, "%c:%c:%c%c%c%c%c",
c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP], c[ARG_RAW],
c[ARG_DEBUG], c[ARG_VERBOSE], c[ARG_VERSION]);
#else
sprintf(str, "%c:%c:%c%c%c%c",
sprintf(str, "%c:%c:%c%c%c%c%c%c%c%c%c%c%c",
c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP],
c[ARG_DEBUG], c[ARG_VERBOSE], c[ARG_VERSION]);
c[ARG_RAW], c[ARG_FULLCPUNAME],
c[ARG_LOGO_SHORT], c[ARG_LOGO_LONG],
c[ARG_LOGO_INTEL_NEW], c[ARG_LOGO_INTEL_OLD],
c[ARG_ACCURATE_PP], c[ARG_DEBUG], c[ARG_VERBOSE],
c[ARG_VERSION]);
#else
sprintf(str, "%c:%c:%c%c%c%c%c%c",
c[ARG_STYLE], c[ARG_COLOR], c[ARG_HELP],
c[ARG_LOGO_SHORT], c[ARG_LOGO_LONG],
c[ARG_DEBUG], c[ARG_VERBOSE],
c[ARG_VERSION]);
#endif
return str;
@@ -204,27 +238,42 @@ char* build_short_options() {
bool parse_args(int argc, char* argv[]) {
int opt;
int option_index = 0;
int option_index = 0;
opterr = 0;
bool color_flag = false;
args.debug_flag = false;
args.accurate_pp = false;
args.full_cpu_name_flag = false;
args.raw_flag = false;
args.verbose_flag = false;
args.logo_long = false;
args.logo_short = false;
args.logo_intel_new = false;
args.logo_intel_old = false;
args.help_flag = false;
args.style = STYLE_EMPTY;
args.colors = NULL;
// Temporary enable verbose level to allow printing warnings inside parse_args
set_log_level(true);
const struct option long_options[] = {
{args_str[ARG_STYLE], required_argument, 0, args_chr[ARG_STYLE] },
{args_str[ARG_COLOR], required_argument, 0, args_chr[ARG_COLOR] },
{args_str[ARG_HELP], no_argument, 0, args_chr[ARG_HELP] },
{args_str[ARG_STYLE], required_argument, 0, args_chr[ARG_STYLE] },
{args_str[ARG_COLOR], required_argument, 0, args_chr[ARG_COLOR] },
{args_str[ARG_HELP], no_argument, 0, args_chr[ARG_HELP] },
#ifdef ARCH_X86
{args_str[ARG_RAW], no_argument, 0, args_chr[ARG_RAW] },
{args_str[ARG_LOGO_INTEL_NEW], no_argument, 0, args_chr[ARG_LOGO_INTEL_NEW] },
{args_str[ARG_LOGO_INTEL_OLD], no_argument, 0, args_chr[ARG_LOGO_INTEL_OLD] },
{args_str[ARG_ACCURATE_PP], no_argument, 0, args_chr[ARG_ACCURATE_PP] },
{args_str[ARG_FULLCPUNAME], no_argument, 0, args_chr[ARG_FULLCPUNAME] },
{args_str[ARG_RAW], no_argument, 0, args_chr[ARG_RAW] },
#endif
{args_str[ARG_DEBUG], no_argument, 0, args_chr[ARG_DEBUG] },
{args_str[ARG_VERBOSE], no_argument, 0, args_chr[ARG_VERBOSE] },
{args_str[ARG_VERSION], no_argument, 0, args_chr[ARG_VERSION] },
{args_str[ARG_LOGO_SHORT], no_argument, 0, args_chr[ARG_LOGO_SHORT] },
{args_str[ARG_LOGO_LONG], no_argument, 0, args_chr[ARG_LOGO_LONG] },
{args_str[ARG_DEBUG], no_argument, 0, args_chr[ARG_DEBUG] },
{args_str[ARG_VERBOSE], no_argument, 0, args_chr[ARG_VERBOSE] },
{args_str[ARG_VERSION], no_argument, 0, args_chr[ARG_VERSION] },
{0, 0, 0, 0}
};
@@ -237,9 +286,9 @@ bool parse_args(int argc, char* argv[]) {
printErr("Color option specified more than once");
return false;
}
color_flag = true;
color_flag = true;
args.colors = emalloc(sizeof(struct color *) * NUM_COLORS);
if(!parse_color(optarg, &args.colors)) {
printErr("Color parsing failed");
return false;
}
}
@@ -253,11 +302,28 @@ bool parse_args(int argc, char* argv[]) {
printErr("Invalid style '%s'",optarg);
return false;
}
break;
}
else if(opt == args_chr[ARG_HELP]) {
args.help_flag = true;
}
else if(opt == args_chr[ARG_ACCURATE_PP]) {
args.accurate_pp = true;
}
else if(opt == args_chr[ARG_FULLCPUNAME]) {
args.full_cpu_name_flag = true;
}
else if(opt == args_chr[ARG_LOGO_SHORT]) {
args.logo_short = true;
}
else if(opt == args_chr[ARG_LOGO_LONG]) {
args.logo_long = true;
}
else if(opt == args_chr[ARG_LOGO_INTEL_NEW]) {
args.logo_intel_new = true;
}
else if(opt == args_chr[ARG_LOGO_INTEL_OLD]) {
args.logo_intel_old = true;
}
else if(opt == args_chr[ARG_RAW]) {
args.raw_flag = true;
}
@@ -270,7 +336,7 @@ bool parse_args(int argc, char* argv[]) {
else if(opt == args_chr[ARG_VERSION]) {
args.version_flag = true;
}
else {
else {
printWarn("Invalid options");
args.help_flag = true;
}
@@ -284,10 +350,27 @@ bool parse_args(int argc, char* argv[]) {
args.help_flag = true;
}
if((args.help_flag + args.version_flag + color_flag) > 1) {
printWarn("You should specify just one option");
if(args.logo_intel_new && args.logo_intel_old) {
printWarn("%s and %s cannot be specified together", args_str[ARG_LOGO_INTEL_NEW], args_str[ARG_LOGO_INTEL_OLD]);
args.logo_intel_new = false;
args.logo_intel_old = false;
}
if(args.logo_short && args.logo_long) {
printWarn("%s and %s cannot be specified together", args_str[ARG_LOGO_SHORT], args_str[ARG_LOGO_LONG]);
args.logo_short = false;
args.logo_long = false;
}
#if defined(ARCH_X86) && ! defined(__linux__)
if(args.accurate_pp) {
printWarn("%s option is valid only in Linux x86_64", args_str[ARG_ACCURATE_PP]);
args.help_flag = true;
}
#endif
// Leave log level untouched after returning
set_log_level(false);
return true;
}

View File

@@ -10,17 +10,9 @@ struct color {
int32_t B;
};
struct colors {
struct color* c1;
struct color* c2;
struct color* c3;
struct color* c4;
};
enum {
STYLE_EMPTY,
STYLE_FANCY,
STYLE_WILD,
STYLE_RETRO,
STYLE_LEGACY,
STYLE_INVALID
@@ -31,6 +23,12 @@ enum {
ARG_COLOR,
ARG_HELP,
ARG_RAW,
ARG_FULLCPUNAME,
ARG_LOGO_LONG,
ARG_LOGO_SHORT,
ARG_LOGO_INTEL_NEW,
ARG_LOGO_INTEL_OLD,
ARG_ACCURATE_PP,
ARG_DEBUG,
ARG_VERBOSE,
ARG_VERSION
@@ -44,12 +42,18 @@ extern const char *args_str[];
int max_arg_str_length();
bool parse_args(int argc, char* argv[]);
bool show_help();
bool accurate_pp();
bool show_full_cpu_name();
bool show_logo_long();
bool show_logo_short();
bool show_logo_intel_new();
bool show_logo_intel_old();
bool show_raw();
bool show_debug();
bool show_version();
bool verbose_enabled();
void free_colors_struct(struct colors* cs);
struct colors* get_colors();
void free_colors_struct(struct color** cs);
struct color** get_colors();
STYLE get_style();
#endif

View File

@@ -1,208 +1,329 @@
#ifndef __ASCII__
#define __ASCII__
#define NUMBER_OF_LINES 19
#define LINE_SIZE 62
#define COLOR_NONE ""
#define C_FG_BLACK "\x1b[30;1m"
#define C_FG_RED "\x1b[31;1m"
#define C_FG_GREEN "\x1b[32;1m"
#define C_FG_YELLOW "\x1b[33;1m"
#define C_FG_BLUE "\x1b[34;1m"
#define C_FG_MAGENTA "\x1b[35;1m"
#define C_FG_CYAN "\x1b[36;1m"
#define C_FG_WHITE "\x1b[37;1m"
#define C_BG_BLACK "\x1b[40;1m"
#define C_BG_RED "\x1b[41;1m"
#define C_BG_GREEN "\x1b[42;1m"
#define C_BG_YELLOW "\x1b[43;1m"
#define C_BG_BLUE "\x1b[44;1m"
#define C_BG_MAGENTA "\x1b[45;1m"
#define C_BG_CYAN "\x1b[46;1m"
#define C_BG_WHITE "\x1b[47;1m"
#define C_FG_B_BLACK "\x1b[90;1m"
#define C_FG_B_RED "\x1b[91;1m"
#define C_FG_B_GREEN "\x1b[92;1m"
#define C_FG_B_YELLOW "\x1b[93;1m"
#define C_FG_B_BLUE "\x1b[94;1m"
#define C_FG_B_MAGENTA "\x1b[95;1m"
#define C_FG_B_CYAN "\x1b[96;1m"
#define C_FG_B_WHITE "\x1b[97;1m"
#define COLOR_RESET "\x1b[m"
#define AMD_ASCII \
" \
\
\
\
\
\
@@@@ @@@ @@@ @@@@@@@@ ############ \
@@@@@@ @@@@@ @@@@@ @@@ @@@ ########## \
@@@ @@@ @@@@@@@@@@@@@ @@@ @@ # ##### \
@@@ @@@ @@@ @@@ @@@ @@@ @@ ### ##### \
@@@@@@@@@@@@ @@@ @@@ @@@ @@@ ######### ### \
@@@ @@@ @@@ @@@ @@@@@@@@@ ######## ## \
\
\
\
\
\
\
"
struct ascii_logo {
char* art;
uint32_t width;
uint32_t height;
bool replace_blocks;
char color_ascii[3][100];
char color_text[2][100];
};
#define INTEL_ASCII \
" ################ \
####### ####### \
#### #### \
### #### \
### ### \
### ### \
# ### ### ### \
## ### ######### ###### ###### ### ### \
## ### ### ### ### #### #### ### ### \
## ### ### ### ### ### ### ### ### \
## ### ### ### ### ########## ### #### \
## ### ### ### ### ### ### ##### \
## ## ### ### ##### ######### ## ### \
### \
### \
#### #### \
##### ########## \
########## ################ \
############################### "
#define SNAPDRAGON_ASCII \
" \
@@######## \
@@@@@########### \
@@ @@@@@################# \
@@@@@@@@@@#################### \
@@@@@@@@@@@@##################### \
@@@@@@@@@@@@@@@#################### \
@@@@@@@@@@@@@@@@@################### \
@@@@@@@@@@@@@@@@@@@@################ \
@@@@@@@@@@@@@@@@@@@@############# \
@@@@@@@@@@@@@@@@@@############ \
@ @@@@@@@@@@@@@@@########### \
@@@@@ @@@@@@@@@@@@@########## \
@@@@@@@@@ @@@@@@@@@@@@######## \
@@@@@@@@@ @@@@@@@@@@####### \
@@@@@@@@@@@@@@@@####### \
@@@@########### \
\
"
#define MEDIATEK_ASCII \
" \
\
\
\
\
\
## ## ###### ###### # ### @@@@@@ @@@@@@ @@ @@ \
### ### # # # # #### @@ @ @@ @@ \
######## # ### # # # ## ## @@ @ @@@ @@@@ \
## ### ## # # # # ## ## @@ @ @@ @@ \
## ## ## ###### ##### # ## ## @@ @@@@@@ @@ @@ \
\
\
\
\
\
\
\
"
/*
* ASCII logos brief documentation
* ----------------------------------------------------
* C1, C2, ...: ColorN, gets replaced by printer.c with
* the color in ascii_logo->color_ascii[N]
* CR: Color reset, gets replaced by the reset
* color by printer.c
*
* Logos with replace_blocks=true are replaced by character
* blocks (actually, spaces with background color), so
* the color in the structure must be C_BG_XXX. When
* replace_blocks is true, the characters '#' are replaced
* by spaces printed with color_ascii[0], and '@' are
* printed with color_ascii[1]. If replace_blocks=true,
* color format specified in ASCIIs ($C1, $C2) are ignored.
*
* In any case, '$' is a illegal character to be used in
* the ascii logos because it is used to parse colors
*
* LONG_LOGOS will be printed only if the fit in the screen,
* otherwise SHORT_LOGOS will be used
*/
#define EXYNOS_ASCII \
" \
\
\
\
\
\
## ## ## \
## ## \
## \
## ## \
## ## ## \
\
SAMSUNG \
Exynos \
\
\
\
\
"
#define KIRIN_ASCII \
" \
\
\
\
\
####### \
##### #################### \
###################################### \
####################################### \
####################################### \
############################## \
########################## \
######################### \
######################## \
######################## \
######################### \
######################### \
\
"
#define BROADCOM_ASCII \
" \
################ \
######################### \
############################### \
################@@@@################ \
################@@@@@@################ \
#################@@@@@@################ \
#################@@@@@@@@################# \
#################@@@@@@@@################# \
#################@@@@##@@@@################ \
################@@@@##@@@@################ \
###############@@@@####@@@@############### \
@@@@@@@@@@####@@@@####@@@@####@@@@@@@@@@ \
######@@@@@@@@@@######@@@@@@@@@@###### \
################################## \
############################## \
######################## \
############### \
"
#define ARM_ASCII \
" \
\
\
\
\
\
############ ########## #### ###### ######## \
############### ######### ####################### \
#### #### #### ##### ####### ##### \
#### #### #### #### ##### #### \
#### #### #### #### #### #### \
#### ##### #### #### #### #### \
############### #### #### #### #### \
######## #### #### #### #### #### \
\
\
\
\
"
// SHORT LOGOS //
#define ASCII_AMD \
"$C2 '############### \
$C2 ,############# \
$C2 .#### \
$C2 #. .#### \
$C2 :##. .#### \
$C2 :###. .#### \
$C2 #########. :## \
$C2 #######. ; \
$C1 \
$C1 ### ### ### ####### \
$C1 ## ## ##### ##### ## ## \
$C1 ## ## ### #### ### ## ## \
$C1 ######### ### ## ### ## ## \
$C1## ## ### ### ## ## \
$C1## ## ### ### ####### "
#define UNKNOWN_ASCII \
" \
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
"
static const char* ASCII_ARRAY [] = {
AMD_ASCII,
INTEL_ASCII,
ARM_ASCII,
SNAPDRAGON_ASCII,
MEDIATEK_ASCII,
EXYNOS_ASCII,
KIRIN_ASCII,
BROADCOM_ASCII,
UNKNOWN_ASCII
};
#define ASCII_INTEL \
"$C1 .#################. \
$C1 .#### ####. \
$C1 .## ### \
$C1 ## :## ### \
$C1 # ## :## ## \
$C1 ## ## ######. #### ###### :## ## \
$C1 ## ## ##: ##: ## ## ### :## ### \
$C1## ## ##: ##: ## :######## :## ## \
$C1## ## ##: ##: ## ##. . :## #### \
$C1## # ##: ##: #### #####: ## \
$C1 ## \
$C1 ###. ..o####. \
$C1 ######oo... ..oo####### \
$C1 o###############o "
#define ASCII_INTEL_NEW \
"$C1 MMM oddl MMN \
$C1 MMM dMMN MMN \
$C1 ... .... ... dMMM.. .cc. NMN \
$C1 MMM :MMMdWMMMMMX. dMMMMM, .XMMMMMMNo MMN \
$C1 MMM :MMMp dMMM dMMX .NMW WMN. MMN \
$C1 MMM :MMM WMM dMMK kMMXooooooNMMx MMN \
$C1 MMM :MMM NMM dMMK dMMX MMN \
$C1 MMM :MMM NMM dMMMoo OMM0....:Nx. MMN \
$C1 MMM :WWW XWW lONMM 'xXMMMMNOc MMN "
#define ASCII_SNAPD \
" $C1@@$C2######## \
$C1@@@@@$C2########### \
$C1@@ @@@@@$C2################# \
$C1@@@@@@@@@@$C2#################### \
$C1@@@@@@@@@@@@$C2##################### \
$C1@@@@@@@@@@@@@@@$C2#################### \
$C1@@@@@@@@@@@@@@@@@$C2################### \
$C1@@@@@@@@@@@@@@@@@@@@$C2################ \
$C1@@@@@@@@@@@@@@@@@@@@$C2############# \
$C1@@@@@@@@@@@@@@@@@@$C2############ \
$C1@ @@@@@@@@@@@@@@@$C2########### \
$C1@@@@@ @@@@@@@@@@@@@$C2########## \
$C1@@@@@@@@@ @@@@@@@@@@@@$C2######## \
$C1@@@@@@@@@ @@@@@@@@@@$C2####### \
$C1@@@@@@@@@@@@@@@@$C2####### \
$C1@@@@$C2########### "
#define ASCII_MTK \
"$C1 ## ## ###### ###### # ### $C2@@@@@@ @@@@@@ @@ @@ \
$C1 ### ### # # # # #### $C2@@ @ @@ @@ \
$C1 ######## # ### # # # ## ## $C2@@ @ @@@ @@@@ \
$C1 ## ### ## # # # # ## ## $C2@@ @ @@ @@ \
$C1## ## ## ###### ##### # ## ## $C2@@ @@@@@@ @@ @@ "
#define ASCII_EXYNOS \
"$C2 \
$C2 \
$C2 \
$C1##$CR $C1##$CR $C1##$CR \
$C1##$CR $C1##$CR \
$C1##$CR \
$C1##$CR $C1##$CR \
$C1##$CR $C1##$CR $C1##$CR \
$C2 \
$C2 SAMSUNG \
$C2 Exynos \
$C2 \
$C2 "
#define ASCII_KIRIN \
"$C1 ####### \
$C1 ##### #################### \
$C1 ###################################### \
$C1 ####################################### \
$C1 ####################################### \
$C1 ############################## \
$C1 ########################## \
$C1 ######################### \
$C1 ######################## \
$C1 ######################## \
$C1 ######################### \
$C1######################### "
#define ASCII_BROADCOM \
"$C2 \
$C2 ################ \
$C2 ########################## \
$C2 ################################ \
$C2 ################$C1@@@@$C2################ \
$C2 ################$C1@@@@@@$C2################ \
$C2 #################$C1@@@@@@$C2################# \
$C2#################$C1@@@@@@@@$C2################# \
$C2#################$C1@@@@@@@@$C2################# \
$C2################$C1@@@@$C2##$C1@@@@$C2################ \
$C2################$C1@@@@$C2##$C1@@@@$C2################ \
$C2###############$C1@@@@$C2####$C1@@@@$C2############### \
$C1 @@@@@@@@@@$C2####$C1@@@@$C2####$C1@@@@$C2####$C1@@@@@@@@@@ \
$C2 ######$C1@@@@@@@@@@$C2######$C1@@@@@@@@@@$C2###### \
$C2 ################################## \
$C2 ############################## \
$C2 ######################## \
$C2 ############### \
$C2 "
#define ASCII_ARM \
"$C1 ##### ## # ##### ## #### ###### \
$C1 ### #### ### #### ### ### \
$C1### ## ### ### ## ### \
$C1 ### #### ### ### ## ### \
$C1 ###### ## ### ### ## ### "
#define ASCII_IBM \
"$C1######## ########## ###### ###### \
$C1######## ########### ####### ####### \
$C1 #### ### #### ###### ###### \
$C1 #### ### ### ####### ####### \
$C1 #### ######## ############### \
$C1 #### ### ### #### ##### #### \
$C1 #### ### #### #### ### #### \
$C1######## ########### ###### # ###### \
$C1######## ########## ###### ###### "
// inspired by the neofetch mac logo
#define ASCII_APPLE \
"$C1 .\"c. \
$C1 ,xNMM. \
$C1 .lMM\" \
$C1 MM* \
$C1 .;loddo;:. olloddol;. \
$C1 cKMMMMMMMMMMNWMMMMMMMMMMM0: \
$C1 .KMMMMMMMMMMMMMMMMMMMMMMMW* \
$C1 XMMMMMMMMMMMMMMMMMMMMMMMX. \
$C1;MMMMMMMMMMMMMMMMMMMMMMMM: \
$C1:MMMMMMMMMMMMMMMMMMMMMMMM: \
$C1.MMMMMMMMMMMMMMMMMMMMMMMMX. \
$C1 kMMMMMMMMMMMMMMMMMMMMMMMMWd. \
$C1 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk \
$C1 'XMMMMMMMMMMMMMMMMMMMMMMMMK. \
$C1 kMMMMMMMMMMMMMMMMMMMMMMd \
$C1 'KMMMMMMMWXXWMMMMMMMk. \
$C1 \"cooc\"* \"*coo'\" "
// --------------------- LONG LOGOS ------------------------- //
#define ASCII_AMD_L \
"$C1 \
$C1 \
$C1 \
$C1 \
$C1 \
$C1 \
$C1 @@@@ @@@ @@@ @@@@@@@@ $C2 ############ \
$C1 @@@@@@ @@@@@ @@@@@ @@@ @@@ $C2 ########## \
$C1 @@@ @@@ @@@@@@@@@@@@@ @@@ @@ $C2 # ##### \
$C1 @@@ @@@ @@@ @@@ @@@ @@@ @@ $C2 ### ##### \
$C1 @@@@@@@@@@@@ @@@ @@@ @@@ @@@ $C2######### ### \
$C1 @@@ @@@ @@@ @@@ @@@@@@@@@ $C2######## ## \
$C1 \
$C1 \
$C1 \
$C1 \
$C1 \
$C1 \
$C1 "
#define ASCII_INTEL_L \
"$C1 ###############@ \
$C1 ######@ ######@ \
$C1 ###@ ###@ \
$C1 ##@ ###@ \
$C1 ##@ ##@ \
$C1 ##@ ##@ \
$C1 @ ##@ ##@ ##@ \
$C1 #@ ##@ ########@ #####@ #####@ ##@ ##@ \
$C1 #@ ##@ ##@ ##@ ##@ ###@ ###@ ##@ ##@ \
$C1 #@ ##@ ##@ ##@ ##@ ##@ ##@ ##@ ##@ \
$C1 #@ ##@ ##@ ##@ ##@ #########@ ##@ ###@ \
$C1 #@ ##@ ##@ ##@ ##@ ##@ ##@ ####@ \
$C1 #@ #@ ##@ ##@ ####@ ########@ #@ ##@ \
$C1 ##@ \
$C1 ##@ \
$C1 ###@ ###@ \
$C1 ####@ #########@ \
$C1 #########@ ###############@ \
$C1 ##############################@ "
#define ASCII_INTEL_L_NEW \
" ####################################################### \
####################################################### \
####%%%#################@@@#####################@@@#### \
####%%%#################@@@#####################@@@#### \
########################@@@#####################@@@#### \
####@@@##@@@#@@@@@@@####@@@@@@####@@@@@@@@@#####@@@#### \
####@@@##@@@@@@@@@@@@###@@@@@@##@@@@#####@@@@###@@@#### \
####@@@##@@@@#####@@@@##@@@####@@@@#######@@@@##@@@#### \
####@@@##@@@#######@@@##@@@####@@@@@@@@@@@@@@@##@@@#### \
####@@@##@@@#######@@@##@@@####@@@@#############@@@#### \
####@@@##@@@#######@@@##@@@@@@##@@@@#####@@@@###@@@#### \
####@@@##@@@#######@@@###@@@@@####@@@@@@@@@#####@@@#### \
####################################################### \
####################################################### "
#define ASCII_ARM_L \
"$C1 ############ ########## #### ####### ######## \
$C1 ############### ######### ######################## \
$C1 #### #### #### ##### ######## ##### \
$C1#### #### #### #### ###### #### \
$C1#### #### #### #### #### #### \
$C1 #### ##### #### #### #### #### \
$C1 ############### #### #### #### #### \
$C1 ######## #### #### #### #### #### "
#define ASCII_IBM_L \
"$C1 ############ ################ ########## ########## \
$C1 \
$C1 ############ ################## ############ ############ \
$C1 \
$C1 ###### ###### ###### #################### \
$C1 \
$C1 ###### ############## #################### \
$C1 \
$C1 ###### ###### ###### ##### ###### ##### \
$C1 \
$C1 ############ ################## ######### #### ######### \
$C1 \
$C1 ############ ################ ######### ## ######### "
typedef struct ascii_logo asciiL;
// ------------------------------------------------------------------------------------------------------+
// | LOGO | W | H | REPLACE | COLORS LOGO (>0 && <10) | COLORS TEXT (=2) |
// ------------------------------------------------------------------------------------------------------+
asciiL logo_amd = { ASCII_AMD, 39, 15, false, {C_FG_WHITE, C_FG_GREEN}, {C_FG_WHITE, C_FG_GREEN} };
asciiL logo_intel = { ASCII_INTEL, 48, 14, false, {C_FG_CYAN}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_intel_new = { ASCII_INTEL_NEW, 51, 9, false, {C_FG_CYAN}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_snapd = { ASCII_SNAPD, 39, 16, false, {C_FG_RED, C_FG_WHITE}, {C_FG_RED, C_FG_WHITE} };
asciiL logo_mtk = { ASCII_MTK, 59, 5, false, {C_FG_BLUE, C_FG_YELLOW}, {C_FG_BLUE, C_FG_YELLOW} };
asciiL logo_exynos = { ASCII_EXYNOS, 22, 13, true, {C_BG_BLUE, C_FG_WHITE}, {C_FG_BLUE, C_FG_WHITE} };
asciiL logo_kirin = { ASCII_KIRIN, 53, 12, false, {C_FG_RED}, {C_FG_WHITE, C_FG_RED} };
asciiL logo_broadcom = { ASCII_BROADCOM, 44, 19, false, {C_FG_WHITE, C_FG_RED}, {C_FG_WHITE, C_FG_RED} };
asciiL logo_arm = { ASCII_ARM, 42, 5, false, {C_FG_CYAN}, {C_FG_WHITE, C_FG_CYAN} };
asciiL logo_ibm = { ASCII_IBM, 42, 9, false, {C_FG_CYAN, C_FG_WHITE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_apple = { ASCII_APPLE, 32, 17, false, {C_FG_WHITE}, {C_FG_B_BLACK, C_FG_B_WHITE} };
// Long variants | ----------------------------------------------------------------------------------------------------|
asciiL logo_amd_l = { ASCII_AMD_L, 62, 19, true, {C_BG_WHITE, C_BG_GREEN}, {C_FG_WHITE, C_FG_GREEN} };
asciiL logo_intel_l = { ASCII_INTEL_L, 62, 19, true, {C_BG_CYAN, C_BG_WHITE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_intel_l_new = { ASCII_INTEL_L_NEW, 57, 14, true, {C_BG_CYAN, C_BG_WHITE, C_BG_BLUE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_arm_l = { ASCII_ARM_L, 60, 8, true, {C_BG_CYAN}, {C_FG_WHITE, C_FG_CYAN} };
asciiL logo_ibm_l = { ASCII_IBM_L, 62, 13, true, {C_BG_CYAN, C_FG_WHITE}, {C_FG_CYAN, C_FG_WHITE} };
asciiL logo_unknown = { NULL, 0, 0, false, {COLOR_NONE}, {COLOR_NONE, COLOR_NONE} };
#endif

View File

@@ -9,11 +9,15 @@
#ifdef ARCH_X86
#include "../x86/uarch.h"
#include "../x86/apic.h"
#elif ARCH_PPC
#include "../ppc/uarch.h"
#elif ARCH_ARM
#include "../arm/uarch.h"
#endif
#define STRING_UNKNOWN "Unknown"
#define UNUSED(x) (void)(x)
#define STRING_YES "Yes"
#define STRING_NO "No"
#define STRING_NONE "None"
@@ -30,13 +34,20 @@ int64_t get_freq(struct frequency* freq) {
return freq->max;
}
#ifdef ARCH_X86
char* get_str_cpu_name(struct cpuInfo* cpu) {
return cpu->cpu_name;
#if defined(ARCH_X86) || defined(ARCH_PPC)
char* get_str_cpu_name(struct cpuInfo* cpu, bool fcpuname) {
#ifdef ARCH_X86
if(!fcpuname) {
return get_str_cpu_name_abbreviated(cpu);
}
#elif ARCH_PPC
UNUSED(fcpuname);
#endif
return cpu->cpu_name;
}
char* get_str_sockets(struct topology* topo) {
char* string = malloc(sizeof(char) * 2);
char* string = emalloc(sizeof(char) * 2);
int32_t sanity_ret = snprintf(string, 2, "%d", topo->sockets);
if(sanity_ret < 0) {
printBug("get_str_sockets: snprintf returned a negative value for input: '%d'", topo->sockets);
@@ -51,71 +62,58 @@ uint32_t get_nsockets(struct topology* topo) {
#endif
int32_t get_value_as_smallest_unit(char ** str, uint32_t value) {
int32_t sanity_ret;
*str = malloc(sizeof(char)* 11); //8 for digits, 2 for units
int32_t ret;
int max_len = 10; // Max is 8 for digits, 2 for units
*str = emalloc(sizeof(char)* (max_len + 1));
if(value/1024 >= 1024)
sanity_ret = snprintf(*str, 10,"%.4g"STRING_MEGABYTES, (double)value/(1<<20));
ret = snprintf(*str, max_len, "%.4g"STRING_MEGABYTES, (double)value/(1<<20));
else
sanity_ret = snprintf(*str, 10,"%.4g"STRING_KILOBYTES, (double)value/(1<<10));
return sanity_ret;
ret = snprintf(*str, max_len, "%.4g"STRING_KILOBYTES, (double)value/(1<<10));
return ret;
}
// String functions
// String functions
char* get_str_cache_two(int32_t cache_size, uint32_t physical_cores) {
// 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)'
uint32_t max_size = 4+2 + 2 + 4+2 + 7 + 1;
int32_t sanity_ret;
char* string = malloc(sizeof(char) * max_size);
char* tmp1;
char* tmp2;
char* tmp2;
int32_t tmp1_len = get_value_as_smallest_unit(&tmp1, cache_size);
int32_t tmp2_len = get_value_as_smallest_unit(&tmp2, cache_size * physical_cores);
// tmp1_len for first output, 2 for ' (', tmp2_len for second output and 7 for ' Total)'
uint32_t size = tmp1_len + 2 + tmp2_len + 7 + 1;
char* string = emalloc(sizeof(char) * size);
if(tmp1_len < 0) {
printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size);
return NULL;
printBug("get_value_as_smallest_unit: snprintf failed for input: %d\n", cache_size);
return NULL;
}
if(tmp2_len < 0) {
printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size * physical_cores);
return NULL;
printBug("get_value_as_smallest_unit: snprintf failed for input: %d\n", cache_size * physical_cores);
return NULL;
}
uint32_t size = tmp1_len + 2 + tmp2_len + 7 + 1;
sanity_ret = snprintf(string, size, "%s (%s Total)", tmp1, tmp2);
if(sanity_ret < 0) {
printBug("get_str_cache_two: snprintf returned a negative value for input: '%s' and '%s'\n", tmp1, tmp2);
return NULL;
if(snprintf(string, size, "%s (%s Total)", tmp1, tmp2) < 0) {
printBug("get_str_cache_two: snprintf failed for input: '%s' and '%s'\n", tmp1, tmp2);
return NULL;
}
free(tmp1);
free(tmp2);
return string;
}
char* get_str_cache_one(int32_t cache_size) {
// 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)'
uint32_t max_size = 4+2 + 1;
int32_t sanity_ret;
char* string = malloc(sizeof(char) * max_size);
char* tmp;
int32_t tmp_len = get_value_as_smallest_unit(&tmp, cache_size);
if(tmp_len < 0) {
printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d", cache_size);
return NULL;
char* string;
int32_t str_len = get_value_as_smallest_unit(&string, cache_size);
if(str_len < 0) {
printBug("get_value_as_smallest_unit: snprintf failed for input: %d", cache_size);
return NULL;
}
uint32_t size = tmp_len + 1;
sanity_ret = snprintf(string, size, "%s", tmp);
if(sanity_ret < 0) {
printBug("get_str_cache_one: snprintf returned a negative value for input: '%s'", tmp);
return NULL;
}
free(tmp);
return string;
}
@@ -141,7 +139,7 @@ char* get_str_l2(struct cache* cach) {
char* get_str_l3(struct cache* cach) {
if(!cach->L3->exists)
return NULL;
return NULL;
return get_str_cache(cach->L3->size, cach->L3->num_caches);
}
@@ -149,7 +147,7 @@ char* get_str_freq(struct frequency* freq) {
//Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0'
uint32_t size = (5+1+3+1);
assert(strlen(STRING_UNKNOWN)+1 <= size);
char* string = malloc(sizeof(char)*size);
char* string = emalloc(sizeof(char)*size);
memset(string, 0, sizeof(char)*size);
if(freq->max == UNKNOWN_FREQ || freq->max < 0)
@@ -162,6 +160,64 @@ char* get_str_freq(struct frequency* freq) {
return string;
}
char* get_str_peak_performance(int64_t flops) {
char* str;
if(flops == -1) {
str = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN) + 1));
strncpy(str, STRING_UNKNOWN, strlen(STRING_UNKNOWN) + 1);
return str;
}
// 7 for digits (e.g, XXXX.XX), 7 for XFLOP/s
double flopsd = (double) flops;
uint32_t max_size = 7+1+7+1;
str = ecalloc(max_size, sizeof(char));
if(flopsd >= (double)1000000000000.0)
snprintf(str, max_size, "%.2f TFLOP/s", flopsd/1000000000000);
else if(flopsd >= 1000000000.0)
snprintf(str, max_size, "%.2f GFLOP/s", flopsd/1000000000);
else
snprintf(str, max_size, "%.2f MFLOP/s", flopsd/1000000);
return str;
}
void init_topology_struct(struct topology* topo, struct cache* cach) {
topo->total_cores = 0;
topo->cach = cach;
#if defined(ARCH_X86) || defined(ARCH_PPC)
topo->physical_cores = 0;
topo->logical_cores = 0;
topo->smt_supported = 0;
topo->sockets = 0;
#ifdef ARCH_X86
topo->smt_available = 0;
topo->apic = emalloc(sizeof(struct apic));
#endif
#endif
}
void init_cache_struct(struct cache* cach) {
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;
cach->L2->exists = false;
cach->L3->exists = false;
}
void free_cache_struct(struct cache* cach) {
for(int i=0; i < 4; i++) free(cach->cach_arr[i]);
free(cach->cach_arr);

View File

@@ -10,6 +10,7 @@ enum {
CPU_VENDOR_AMD,
// ARCH_ARM
CPU_VENDOR_ARM,
CPU_VENDOR_APPLE,
CPU_VENDOR_BROADCOM,
CPU_VENDOR_CAVIUM,
CPU_VENDOR_NVIDIA,
@@ -69,14 +70,16 @@ struct cache {
struct topology {
int32_t total_cores;
struct cache* cach;
#ifdef ARCH_X86
uint32_t physical_cores;
#if defined(ARCH_X86) || defined(ARCH_PPC)
uint32_t physical_cores;
uint32_t logical_cores;
uint32_t smt_available; // Number of SMT that is currently enabled
uint32_t smt_supported; // Number of SMT that CPU supports (equal to smt_available if SMT is enabled)
uint32_t sockets;
uint32_t smt_supported; // Number of SMT that CPU supports (equal to smt_available if SMT is enabled)
#ifdef ARCH_X86
uint32_t smt_available; // Number of SMT that is currently enabled
struct apic* apic;
#endif
#endif
};
struct features {
@@ -94,7 +97,9 @@ struct features {
bool SSE4_2;
bool FMA3;
bool FMA4;
bool SHA;
bool SHA;
#elif ARCH_PPC
bool altivec;
#elif ARCH_ARM
bool NEON;
bool SHA1;
@@ -111,16 +116,22 @@ struct cpuInfo {
struct cache* cach;
struct topology* topo;
struct features* feat;
#ifdef ARCH_X86
int64_t peak_performance;
#if defined(ARCH_X86) || defined(ARCH_PPC)
// CPU name from model
char* cpu_name;
#endif
#ifdef ARCH_X86
// Max cpuids levels
uint32_t maxLevels;
// Max cpuids extended levels
uint32_t maxExtendedLevels;
// Topology Extensions (AMD only)
bool topology_extensions;
#elif ARCH_PPC
uint32_t pvr;
#elif ARCH_ARM
// Main ID register
uint32_t midr;
@@ -136,8 +147,8 @@ struct cpuInfo {
#endif
};
#ifdef ARCH_X86
char* get_str_cpu_name(struct cpuInfo* cpu);
#if defined(ARCH_X86) || defined(ARCH_PPC)
char* get_str_cpu_name(struct cpuInfo* cpu, bool fcpuname);
char* get_str_sockets(struct topology* topo);
uint32_t get_nsockets(struct topology* topo);
#endif
@@ -152,6 +163,10 @@ char* get_str_l1d(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(int64_t flops);
void init_topology_struct(struct topology* topo, struct cache* cach);
void init_cache_struct(struct cache* cach);
void free_cache_struct(struct cache* cach);
void free_freq_struct(struct frequency* freq);

View File

@@ -1,5 +1,9 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "global.h"
#ifdef _WIN32
@@ -53,10 +57,10 @@ void printBug(const char *fmt, ...) {
vsnprintf(buffer,buffer_size, fmt, args);
va_end(args);
fprintf(stderr,RED "[ERROR]: "RESET "%s\n",buffer);
#ifdef ARCH_X86
fprintf(stderr,"Please, create a new issue with this error message and the output of 'cpufetch --debug' in https://github.com/Dr-Noob/cpufetch/issues\n");
#if defined(ARCH_X86) || defined(ARCH_PPC)
fprintf(stderr, "Please, create a new issue with this error message, the output of 'cpufetch' and 'cpufetch --debug' on https://github.com/Dr-Noob/cpufetch/issues\n");
#elif ARCH_ARM
fprintf(stderr,"Please, create a new issue with this error message, your smartphone/computer model and the output of 'cpufetch --debug' in https://github.com/Dr-Noob/cpufetch/issues\n");
fprintf(stderr, "Please, create a new issue with this error message, your smartphone/computer model, the output of 'cpufetch' and 'cpufetch --debug' on https://github.com/Dr-Noob/cpufetch/issues\n");
#endif
}
@@ -68,3 +72,42 @@ void set_log_level(bool verbose) {
int max(int a, int b) {
return a > b ? a : b;
}
int min(int a, int b) {
return a < b ? a : b;
}
char *strremove(char *str, const char *sub) {
char *p, *q, *r;
if (*sub && (q = r = strstr(str, sub)) != NULL) {
size_t len = strlen(sub);
while ((r = strstr(p = r + len, sub)) != NULL) {
memmove(q, p, r - p);
q += r - p;
}
memmove(q, p, strlen(p) + 1);
}
return str;
}
void* emalloc(size_t size) {
void* ptr = malloc(size);
if(ptr == NULL) {
printErr("malloc failed: %s", strerror(errno));
exit(1);
}
return ptr;
}
void* ecalloc(size_t nmemb, size_t size) {
void* ptr = calloc(nmemb, size);
if(ptr == NULL) {
printErr("calloc failed: %s", strerror(errno));
exit(1);
}
return ptr;
}

View File

@@ -2,11 +2,18 @@
#define __GLOBAL__
#include <stdbool.h>
#include <stddef.h>
#define STRING_UNKNOWN "Unknown"
void set_log_level(bool verbose);
void printWarn(const char *fmt, ...);
void printErr(const char *fmt, ...);
void printBug(const char *fmt, ...);
int min(int a, int b);
int max(int a, int b);
char *strremove(char *str, const char *sub);
void* emalloc(size_t size);
void* ecalloc(size_t nmemb, size_t size);
#endif

View File

@@ -9,67 +9,105 @@
#ifdef ARCH_X86
static const char* ARCH_STR = "x86_64 build";
#include "../x86/cpuid.h"
#elif ARCH_PPC
static const char* ARCH_STR = "PowerPC build";
#include "../ppc/ppc.h"
#elif ARCH_ARM
static const char* ARCH_STR = "ARM build";
#include "../arm/midr.h"
#endif
static const char* VERSION = "0.97";
#ifdef __linux__
#ifdef __ANDROID__
static const char* OS_STR = "Android";
#else
static const char* OS_STR = "Linux";
#endif
#elif __FreeBSD__
static const char* OS_STR = "FreeBSD";
#elif _WIN32
static const char* OS_STR = "Windows";
#elif defined __APPLE__ || __MACH__
static const char* OS_STR = "macOS";
#else
static const char* OS_STR = "Unknown OS";
#endif
static const char* VERSION = "1.00";
void print_help(char *argv[]) {
const char **t = args_str;
const char *c = args_chr;
const char *c = args_chr;
int max_len = max_arg_str_length();
printf("Usage: %s [OPTION]...\n", argv[0]);
printf("Simple yet fancy CPU architecture fetching tool\n\n");
printf("Options: \n");
printf("OPTIONS: \n");
printf(" -%c, --%s %*s Set the color scheme (by default, cpufetch uses the system color scheme)\n", c[ARG_COLOR], t[ARG_COLOR], (int) (max_len-strlen(t[ARG_COLOR])), "");
printf(" -%c, --%s %*s Set the style of CPU art\n", c[ARG_STYLE], t[ARG_STYLE], (int) (max_len-strlen(t[ARG_STYLE])), "");
printf(" -%c, --%s %*s Set the style of CPU logo\n", c[ARG_STYLE], t[ARG_STYLE], (int) (max_len-strlen(t[ARG_STYLE])), "");
#ifdef ARCH_X86
printf(" -%c, --%s %*s Prints CPU model and cpuid levels (debug purposes)\n", c[ARG_DEBUG], t[ARG_DEBUG], (int) (max_len-strlen(t[ARG_DEBUG])), "");
printf(" -%c, --%s %*s Print CPU model and cpuid levels (debug purposes)\n", c[ARG_DEBUG], t[ARG_DEBUG], (int) (max_len-strlen(t[ARG_DEBUG])), "");
#elif ARCH_PPC
printf(" -%c, --%s %*s Print PVR register (debug purposes)\n", c[ARG_DEBUG], t[ARG_DEBUG], (int) (max_len-strlen(t[ARG_DEBUG])), "");
#elif ARCH_ARM
printf(" -%c, --%s %*s Prints main ID register values for all cores (debug purposes)\n", c[ARG_DEBUG], t[ARG_DEBUG], (int) (max_len-strlen(t[ARG_DEBUG])), "");
printf(" -%c, --%s %*s Print main ID register values (debug purposes)\n", c[ARG_DEBUG], t[ARG_DEBUG], (int) (max_len-strlen(t[ARG_DEBUG])), "");
#endif
printf(" -%c, --%s %*s Prints extra information (if available) about how cpufetch tried fetching information\n", c[ARG_VERBOSE], t[ARG_VERBOSE], (int) (max_len-strlen(t[ARG_VERBOSE])), "");
printf(" --%s %*s Show the short version of the logo\n", t[ARG_LOGO_SHORT], (int) (max_len-strlen(t[ARG_LOGO_SHORT])), "");
printf(" --%s %*s Show the long version of the logo\n", t[ARG_LOGO_LONG], (int) (max_len-strlen(t[ARG_LOGO_LONG])), "");
printf(" -%c, --%s %*s Print extra information (if available) about how cpufetch tried fetching information\n", c[ARG_VERBOSE], t[ARG_VERBOSE], (int) (max_len-strlen(t[ARG_VERBOSE])), "");
#ifdef ARCH_X86
printf(" -%c, --%s %*s Prints raw cpuid data\n", c[ARG_RAW], t[ARG_RAW], (int) (max_len-strlen(t[ARG_RAW])), "");
#ifdef __linux__
printf(" --%s %*s Compute the peak performance accurately (measure the CPU frequency instead of using the maximum)\n", t[ARG_ACCURATE_PP], (int) (max_len-strlen(t[ARG_ACCURATE_PP])), "");
#endif
printf(" -%c, --%s %*s Prints this help and exit\n", c[ARG_HELP], t[ARG_HELP], (int) (max_len-strlen(t[ARG_HELP])), "");
printf(" -%c, --%s %*s Prints cpufetch version and exit\n", c[ARG_VERSION], t[ARG_VERSION], (int) (max_len-strlen(t[ARG_VERSION])), "");
printf(" --%s %*s Show the old Intel logo\n", t[ARG_LOGO_INTEL_OLD], (int) (max_len-strlen(t[ARG_LOGO_INTEL_OLD])), "");
printf(" --%s %*s Show the new Intel logo\n", t[ARG_LOGO_INTEL_NEW], (int) (max_len-strlen(t[ARG_LOGO_INTEL_NEW])), "");
printf(" -%c, --%s %*s Show the full CPU name (do not abbreviate it)\n", c[ARG_FULLCPUNAME], t[ARG_FULLCPUNAME], (int) (max_len-strlen(t[ARG_FULLCPUNAME])), "");
printf(" -%c, --%s %*s Print raw cpuid data (debug purposes)\n", c[ARG_RAW], t[ARG_RAW], (int) (max_len-strlen(t[ARG_RAW])), "");
#endif
printf(" -%c, --%s %*s Print this help and exit\n", c[ARG_HELP], t[ARG_HELP], (int) (max_len-strlen(t[ARG_HELP])), "");
printf(" -%c, --%s %*s Print cpufetch version and exit\n", c[ARG_VERSION], t[ARG_VERSION], (int) (max_len-strlen(t[ARG_VERSION])), "");
printf("\nCOLORS: \n");
printf(" * \"intel\": Use Intel default color scheme \n");
printf(" * \"amd\": Use AMD default color scheme \n");
printf(" * \"ibm\", Use IBM default color scheme \n");
printf(" * \"arm\": Use ARM default color scheme \n");
printf(" * custom: If color argument do not match \"intel\", \"amd\" or \"arm\", a custom scheme can be specified.\n");
printf(" 4 colors must be given in RGB with the format: R,G,B:R,G,B:...\n");
printf(" The first 2 colors are the CPU art color and the next 2 colors are the text colors\n");
printf(" * custom: If the argument of --color does not match any of the previous strings, a custom scheme can be specified.\n");
printf(" 5 colors must be given in RGB with the format: R,G,B:R,G,B:...\n");
printf(" The first 3 colors are the CPU art color and the next 2 colors are the text colors\n");
printf("\nSTYLES: \n");
printf(" * \"fancy\": Default style\n");
printf(" * \"retro\": Old cpufetch style\n");
printf(" * \"legacy\": Fallback style for terminals that do not support colors\n");
printf("\nLOGOS: \n");
printf(" cpufetch will try to adapt the logo size and the text to the terminal width. When the output (logo and text) is wider than\n");
printf(" the terminal width, cpufetch will print a smaller version of the logo (if it exists). This behavior can be overridden by\n");
printf(" --logo-short and --logo-long, which always sets the logo size as specified by the user, even if it is too big. After the\n");
printf(" logo selection (either automatically or set by the user), cpufetch will check again if the output fits in the terminal.\n");
printf(" If not, it will use a shorter name for the fields (the left part of the text). If, after all of this, the output still does\n");
printf(" not fit, cpufetch will cut the text and will only print the text until there is no space left in each line\n");
printf("\nEXAMPLES: \n");
printf(" Run cpufetch with Intel color scheme:\n");
printf(" ./cpufetch --color intel\n");
printf(" Run cpufetch with a custom color scheme:\n");
printf(" ./cpufetch --color 239,90,45:210,200,200:100,200,45:0,200,200\n");
printf(" Run cpufetch with Intel color scheme:\n");
printf(" ./cpufetch --color intel\n");
printf(" Run cpufetch with a custom color scheme:\n");
printf(" ./cpufetch --color 239,90,45:210,200,200:0,0,0:100,200,45:0,200,200\n");
printf("\nBUGS: \n");
printf(" Report bugs to https://github.com/Dr-Noob/cpufetch/issues\n");
printf("\nNOTE: \n");
printf(" Peak performance information is NOT accurate. cpufetch computes peak performance using the max\n");
printf(" frequency. However, to properly compute peak performance, you need to know the frequency of the\n");
printf(" CPU running AVX code, which is not be fetched by cpufetch since it depends on each specific CPU.\n");
printf(" For peak performance measurement see: https://github.com/Dr-Noob/peakperf\n");
printf(" frequency of the CPU. However, to compute the peak performance, you need to know the frequency of the\n");
printf(" CPU running AVX code. This value is not be fetched by cpufetch since it depends on each specific CPU.\n");
printf(" To correctly measure peak performance, see: https://github.com/Dr-Noob/peakperf\n");
}
void print_version() {
printf("cpufetch v%s (%s)\n",VERSION, ARCH_STR);
printf("cpufetch v%s (%s %s)\n",VERSION, OS_STR, ARCH_STR);
}
int main(int argc, char* argv[]) {
@@ -97,7 +135,8 @@ int main(int argc, char* argv[]) {
print_debug(cpu);
return EXIT_SUCCESS;
}
// TODO: This should be moved to the end of args.c
if(show_raw()) {
#ifdef ARCH_X86
print_version();
@@ -108,8 +147,8 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE;
#endif
}
if(print_cpufetch(cpu, get_style(), get_colors()))
if(print_cpufetch(cpu, get_style(), get_colors(), show_full_cpu_name()))
return EXIT_SUCCESS;
else
return EXIT_FAILURE;

File diff suppressed because it is too large Load Diff

View File

@@ -7,18 +7,25 @@ typedef int STYLE;
#ifdef ARCH_X86
#include "../x86/cpuid.h"
#else
#elif ARCH_PPC
#include "../ppc/ppc.h"
#elif ARCH_ARM
#include "../arm/midr.h"
#endif
#define COLOR_DEFAULT_INTEL "15,125,194:230,230,230:40,150,220:230,230,230"
#define COLOR_DEFAULT_AMD "250,250,250:0,154,102:250,250,250:0,154,102"
#define COLOR_DEFAULT_ARM "0,145,189:0,145,189:240,240,240:0,145,189"
// +-----------------------------------+-----------------------+
// | Color logo | Color text |
// | Color 1 | Color 2 | Color 3 | Color 1 | Color 2 |
#define COLOR_DEFAULT_INTEL "015,125,194:230,230,230:000,000,000:040,150,220:230,230,230"
#define COLOR_DEFAULT_INTEL_NEW "030,204,251:250,250,250:000,104,181:230,230,230:030,204,251"
#define COLOR_DEFAULT_AMD "250,250,250:000,154,102:000,000,000:250,250,250:000,154,102"
#define COLOR_DEFAULT_IBM "092,119,172:092,119,172:000,000,000:240,240,240:092,119,172"
#define COLOR_DEFAULT_ARM "000,145,189:000,145,189:000,000,000:240,240,240:000,145,189"
#ifdef ARCH_X86
void print_levels(struct cpuInfo* cpu);
#endif
bool print_cpufetch(struct cpuInfo* cpu, STYLE s, struct colors* cs);
bool print_cpufetch(struct cpuInfo* cpu, STYLE s, struct color** cs, bool fcpuname);
#endif

View File

@@ -4,7 +4,7 @@
char* read_file(char* path, int* len) {
int fd = open(path, O_RDONLY);
if(fd == -1) {
return NULL;
}
@@ -13,30 +13,26 @@ char* read_file(char* path, int* len) {
int bytes_read = 0;
int offset = 0;
int block = 128;
char* buf = malloc(sizeof(char)*DEFAULT_FILE_SIZE);
char* buf = emalloc(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;
}
}
if (close(fd) == -1) {
return NULL;
}
*len = offset;
return buf;
}
long get_freq_from_file(char* path, bool hv_present) {
long get_freq_from_file(char* path) {
int filelen;
char* buf;
if((buf = read_file(path, &filelen)) == NULL) {
if(hv_present)
printWarn("Could not open '%s' (HV is present)", path);
else
printWarn("Could not open '%s'", path);
printWarn("Could not open '%s'", path);
return UNKNOWN_FREQ;
}
@@ -44,12 +40,11 @@ long get_freq_from_file(char* path, bool hv_present) {
errno = 0;
long ret = strtol(buf, &end, 10);
if(errno != 0) {
perror("strtol");
printBug("Failed parsing '%s' file. Read data was: '%s'", path, buf);
printBug("strtol: %s", strerror(errno));
free(buf);
return UNKNOWN_FREQ;
}
// 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
@@ -57,20 +52,145 @@ long get_freq_from_file(char* path, bool hv_present) {
printBug("Invalid data was read from file '%s': %ld\n", path, ret);
return UNKNOWN_FREQ;
}
free(buf);
return ret/1000;
}
long get_max_freq_from_file(uint32_t core, bool hv_present) {
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, hv_present);
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_min_freq_from_file(uint32_t core, bool hv_present) {
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, hv_present);
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;
}

View File

@@ -17,12 +17,24 @@
#define _PATH_FREQUENCY "/cpufreq"
#define _PATH_FREQUENCY_MAX "/cpuinfo_max_freq"
#define _PATH_FREQUENCY_MIN "/cpuinfo_min_freq"
#define _PATH_CACHE_L1D "/cache/index0"
#define _PATH_CACHE_L1I "/cache/index1"
#define _PATH_CACHE_L2 "/cache/index2"
#define _PATH_CACHE_L3 "/cache/index3"
#define _PATH_CACHE_SIZE "/size"
#define _PATH_CACHE_SHARED_MAP "/shared_cpu_map"
#define _PATH_FREQUENCY_MAX_LEN 100
#define _PATH_CACHE_MAX_LEN 200
#define DEFAULT_FILE_SIZE 4096
char* read_file(char* path, int* len);
long get_max_freq_from_file(uint32_t core, bool hv_present);
long get_min_freq_from_file(uint32_t core, bool hv_present);
long get_max_freq_from_file(uint32_t core);
long get_min_freq_from_file(uint32_t core);
long get_l1i_cache_size(uint32_t core);
long get_l1d_cache_size(uint32_t core);
long get_l2_cache_size(uint32_t core);
long get_l3_cache_size(uint32_t core);
int get_num_caches_by_level(struct cpuInfo* cpu, uint32_t level);
#endif

223
src/ppc/ppc.c Normal file
View File

@@ -0,0 +1,223 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include "ppc.h"
#include "uarch.h"
#include "udev.h"
#include "../common/udev.h"
#include "../common/global.h"
struct cache* get_cache_info(struct cpuInfo* cpu) {
struct cache* cach = emalloc(sizeof(struct cache));
init_cache_struct(cach);
cach->L1i->size = get_l1i_cache_size(0);
cach->L1d->size = get_l1d_cache_size(0);
cach->L2->size = get_l2_cache_size(0);
cach->L3->size = get_l3_cache_size(0);
if(cach->L1i->size > 0) {
cach->L1i->exists = true;
cach->L1i->num_caches = get_num_caches_by_level(cpu, 0);
cach->max_cache_level = 1;
}
if(cach->L1d->size > 0) {
cach->L1d->exists = true;
cach->L1d->num_caches = get_num_caches_by_level(cpu, 1);
cach->max_cache_level = 2;
}
if(cach->L2->size > 0) {
cach->L2->exists = true;
cach->L2->num_caches = get_num_caches_by_level(cpu, 2);
cach->max_cache_level = 3;
}
if(cach->L3->size > 0) {
cach->L3->exists = true;
cach->L3->num_caches = get_num_caches_by_level(cpu, 3);
cach->max_cache_level = 4;
}
return cach;
}
struct topology* get_topology_info(struct cache* cach) {
struct topology* topo = emalloc(sizeof(struct topology));
init_topology_struct(topo, cach);
// 1. Total cores detection
if((topo->total_cores = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
printWarn("sysconf(_SC_NPROCESSORS_ONLN): %s", strerror(errno));
topo->total_cores = 1; // fallback
}
// To find physical cores, we use topo->total_cores and core_ids
// To find number of sockets, we use package_ids
int* core_ids = emalloc(sizeof(int) * topo->total_cores);
int* package_ids = emalloc(sizeof(int) * topo->total_cores);
if(!fill_core_ids_from_sys(core_ids, topo->total_cores)) {
printWarn("fill_core_ids_from_sys failed, output may be incomplete/invalid");
for(int i=0; i < topo->total_cores; i++) core_ids[i] = 0;
}
if(!fill_package_ids_from_sys(package_ids, topo->total_cores)) {
printWarn("fill_package_ids_from_sys failed, output may be incomplete/invalid");
for(int i=0; i < topo->total_cores; i++) package_ids[i] = 0;
}
// 2. Socket detection
int *package_ids_count = emalloc(sizeof(int) * topo->total_cores);
for(int i=0; i < topo->total_cores; i++) {
package_ids_count[i] = 0;
}
for(int i=0; i < topo->total_cores; i++) {
package_ids_count[package_ids[i]]++;
}
for(int i=0; i < topo->total_cores; i++) {
if(package_ids_count[i] != 0) {
topo->sockets++;
}
}
// 3. Physical cores detection
int *core_ids_unified = emalloc(sizeof(int) * topo->total_cores);
for(int i=0; i < topo->total_cores; i++) {
core_ids_unified[i] = -1;
}
bool found = false;
for(int i=0; i < topo->total_cores; i++) {
for(int j=0; j < topo->total_cores && !found; j++) {
if(core_ids_unified[j] == core_ids[i]) found = true;
}
if(!found) {
core_ids_unified[topo->physical_cores] = core_ids[i];
topo->physical_cores++;
}
found = false;
}
topo->physical_cores = topo->physical_cores / topo->sockets; // only count cores on one socket
topo->logical_cores = topo->total_cores / topo->sockets; // only count threads on one socket
topo->smt_supported = topo->logical_cores / topo->physical_cores;
free(core_ids);
free(package_ids);
free(package_ids_count);
free(core_ids_unified);
return topo;
}
static inline uint32_t mfpvr() {
uint32_t pvr;
asm ("mfpvr %0"
: "=r"(pvr));
return pvr;
}
struct uarch* get_cpu_uarch(struct cpuInfo* cpu) {
return get_uarch_from_pvr(cpu->pvr);
}
struct frequency* get_frequency_info() {
struct frequency* freq = emalloc(sizeof(struct frequency));
freq->max = get_max_freq_from_file(0);
freq->base = get_min_freq_from_file(0);
return freq;
}
int64_t get_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq) {
/*
* Not sure about this
* PP(SP) = N_CORES * FREQUENCY * 4(If altivec)
*/
//First check we have consistent data
if(freq == UNKNOWN_FREQ) {
return -1;
}
struct features* feat = cpu->feat;
int64_t flops = topo->physical_cores * topo->sockets * (freq * 1000000);
if(feat->altivec) flops = flops * 4;
// POWER9 has the concept called "slices". Each SMT4 core has two super-slices,
// and each super-slice is capable of doing two FLOPS per cycle. In the case of
// SMT8, it has 4 super-slices, thus four FLOPS per cycle.
if(is_power9(cpu->arch)) {
int threads_per_core = topo->logical_cores / topo->physical_cores;
flops = flops * (threads_per_core / 2);
}
return flops;
}
struct cpuInfo* get_cpu_info() {
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;
}
int len;
char* path = emalloc(sizeof(char) * (strlen(_PATH_DT) + strlen(_PATH_DT_PART) + 1));
sprintf(path, "%s%s", _PATH_DT, _PATH_DT_PART);
cpu->cpu_name = read_file(path, &len);
cpu->pvr = mfpvr();
cpu->arch = get_cpu_uarch(cpu);
cpu->freq = get_frequency_info();
cpu->topo = get_topology_info(cpu->cach);
cpu->cach = get_cache_info(cpu);
feat->altivec = has_altivec(cpu->arch);
cpu->peak_performance = get_peak_performance(cpu, cpu->topo, get_freq(cpu->freq));
if(cpu->cach == NULL || cpu->topo == NULL) {
return NULL;
}
return cpu;
}
char* get_str_altivec(struct cpuInfo* cpu) {
char* string = ecalloc(4, sizeof(char));
if(cpu->feat->altivec) strcpy(string, "Yes");
else strcpy(string, "No");
return string;
}
char* get_str_topology(struct topology* topo, bool dual_socket) {
char* string;
if(topo->smt_supported > 1) {
uint32_t size = 3+3+17+1;
string = emalloc(sizeof(char)*size);
if(dual_socket)
snprintf(string, size, "%d cores (%d threads)", topo->physical_cores * topo->sockets, topo->logical_cores * topo->sockets);
else
snprintf(string, size, "%d cores (%d threads)",topo->physical_cores,topo->logical_cores);
}
else {
uint32_t size = 3+7+1;
string = emalloc(sizeof(char)*size);
if(dual_socket)
snprintf(string, size, "%d cores",topo->physical_cores * topo->sockets);
else
snprintf(string, size, "%d cores",topo->physical_cores);
}
return string;
}
void print_debug(struct cpuInfo* cpu) {
printf("PVR: 0x%.8X\n", cpu->pvr);
}

11
src/ppc/ppc.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef __POWERPC__
#define __POWERPC__
#include "../common/cpu.h"
struct cpuInfo* get_cpu_info();
char* get_str_altivec(struct cpuInfo* cpu);
char* get_str_topology(struct topology* topo, bool dual_socket);
void print_debug(struct cpuInfo* cpu);
#endif

28
src/ppc/pvr_kern_to_cpufetch.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
# This script takes as input cputable.c from linux kernel
# and generates a valid output for cpufetch in src/ppc/uarch.c
CPUTABLE_PATH="linux-5.13.7/arch/powerpc/kernel/cputable.c"
raw_values=$(grep '\.pvr_value' "$CPUTABLE_PATH" | grep -oP "= .*," | cut -d' ' -f2 | tr -d ',')
raw_masks=$(grep '\.pvr_mask' "$CPUTABLE_PATH" | grep -oE "0x........")
raw_v_len=$(echo "$raw_values" | wc -l)
raw_m_len=$(echo "$raw_masks" | wc -l)
if [ $raw_v_len -ne $raw_m_len ]
then
echo "Lengths do not match!"
echo "values length: $raw_v_len"
echo "masks length: $raw_m_len"
exit 1
fi
IFS=$'\n' read -r -d ' ' -a values <<< "$raw_values"
IFS=$'\n' read -r -d ' ' -a masks <<< "$raw_masks"
for i in "${!values[@]}"
do
echo ' CHECK_UARCH(arch, pvr, '"${masks[i]}"', '"${values[i]}"', "POWERX", UARCH_POWERX, -1)'
done

286
src/ppc/uarch.c Normal file
View File

@@ -0,0 +1,286 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/auxv.h>
#include <errno.h>
#include "uarch.h"
#include "../common/global.h"
typedef uint32_t MICROARCH;
// Data not available
#define NA -1
// Unknown manufacturing process
#define UNK -1
enum {
UARCH_UNKNOWN,
UARCH_PPC604,
UARCH_PPCG3,
UARCH_PPCG4,
UARCH_PPC405,
UARCH_PPC603,
UARCH_PPC440,
UARCH_PPC470,
UARCH_PPC970,
UARCH_PPC970FX,
UARCH_PPC970MP,
UARCH_CELLBE,
UARCH_POWER5,
UARCH_POWER5PLUS,
UARCH_POWER6,
UARCH_POWER7,
UARCH_POWER7PLUS,
UARCH_POWER8,
UARCH_POWER9,
UARCH_POWER9_DD20,
UARCH_POWER9_DD21,
UARCH_POWER9_DD22,
UARCH_POWER9_DD23,
UARCH_POWER10,
};
struct uarch {
MICROARCH uarch;
char* uarch_str;
int32_t process; // measured in nanometers
};
#define UARCH_START if (false) {}
#define CHECK_UARCH(arch, cpu_pvr, pvr_mask, pvr_value, uarch) \
else if ((cpu_pvr & pvr_mask) == pvr_value) fill_uarch(arch, uarch);
#define UARCH_END else { printBug("Unknown microarchitecture detected: 0x%.8X", pvr); fill_uarch(arch, UARCH_UNKNOWN); }
#define FILL_START if (false) {}
#define FILL_UARCH(u, uarch, uarch_str, uarch_process) \
else if(u == uarch) { fill = true; str = uarch_str; process = uarch_process; }
#define FILL_END else { printBug("Found invalid microarchitecture: %d", u); }
void fill_uarch(struct uarch* arch, MICROARCH u) {
arch->uarch = u;
char* str = NULL;
int32_t process = UNK;
bool fill = false;
FILL_START
FILL_UARCH(arch->uarch, UARCH_UNKNOWN, STRING_UNKNOWN, UNK)
FILL_UARCH(arch->uarch, UARCH_PPC604, "PowerPC 604", 500)
FILL_UARCH(arch->uarch, UARCH_PPCG3, "PowerPC G3", UNK) // varies
FILL_UARCH(arch->uarch, UARCH_PPCG4, "PowerPC G4", UNK) // varies
FILL_UARCH(arch->uarch, UARCH_PPC405, "PowerPC 405", UNK)
FILL_UARCH(arch->uarch, UARCH_PPC603, "PowerPC 603", UNK) // varies
FILL_UARCH(arch->uarch, UARCH_PPC440, "PowerPC 440", UNK)
FILL_UARCH(arch->uarch, UARCH_PPC470, "PowerPC 470", 45) // strange...
FILL_UARCH(arch->uarch, UARCH_PPC970, "PowerPC 970", 130)
FILL_UARCH(arch->uarch, UARCH_PPC970FX, "PowerPC 970FX", 90)
FILL_UARCH(arch->uarch, UARCH_PPC970MP, "PowerPC 970MP", 90)
FILL_UARCH(arch->uarch, UARCH_CELLBE, "Cell BE", UNK) // varies depending on manufacturer
FILL_UARCH(arch->uarch, UARCH_POWER5, "POWER5", 130)
FILL_UARCH(arch->uarch, UARCH_POWER5PLUS, "POWER5+", 90)
FILL_UARCH(arch->uarch, UARCH_POWER6, "POWER6", 65)
FILL_UARCH(arch->uarch, UARCH_POWER7, "POWER7", 45)
FILL_UARCH(arch->uarch, UARCH_POWER7PLUS, "POWER7+", 32)
FILL_UARCH(arch->uarch, UARCH_POWER8, "POWER8", 22)
FILL_UARCH(arch->uarch, UARCH_POWER9, "POWER9", 14)
FILL_UARCH(arch->uarch, UARCH_POWER9_DD20, "POWER9 (DD2.0)", 14)
FILL_UARCH(arch->uarch, UARCH_POWER9_DD21, "POWER9 (DD2.1)", 14)
FILL_UARCH(arch->uarch, UARCH_POWER9_DD22, "POWER9 (DD2.2)", 14)
FILL_UARCH(arch->uarch, UARCH_POWER9_DD23, "POWER9 (DD2.3)", 14)
FILL_UARCH(arch->uarch, UARCH_POWER10, "POWER10", 7)
FILL_END
if(fill) {
arch->uarch_str = emalloc(sizeof(char) * (strlen(str)+1));
strcpy(arch->uarch_str, str);
arch->process= process;
}
}
/*
* PVR masks/values from arch/powerpc/kernel/cputable.c (Linux kernel)
* This list may be incorrect, incomplete or overly simplified,
* specially in the case of 32 bit entries
*/
struct uarch* get_uarch_from_pvr(uint32_t pvr) {
struct uarch* arch = emalloc(sizeof(struct uarch));
UARCH_START
// 64 bit
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00390000, UARCH_PPC970)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x003c0000, UARCH_PPC970FX)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x00440100, UARCH_PPC970MP)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00440000, UARCH_PPC970MP)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x003a0000, UARCH_POWER5)
CHECK_UARCH(arch, pvr, 0xffffff00, 0x003b0300, UARCH_POWER5PLUS)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x003b0000, UARCH_POWER5)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000001, UARCH_POWER5)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x003e0000, UARCH_POWER6)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000002, UARCH_POWER6)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000003, UARCH_POWER7)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000004, UARCH_POWER8)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000005, UARCH_POWER9)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x0f000006, UARCH_POWER10)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x003f0000, UARCH_POWER7)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004A0000, UARCH_POWER7PLUS)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004b0000, UARCH_POWER8)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004c0000, UARCH_POWER8)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x004d0000, UARCH_POWER8)
CHECK_UARCH(arch, pvr, 0xffffefff, 0x004e0200, UARCH_POWER9_DD20)
CHECK_UARCH(arch, pvr, 0xffffefff, 0x004e0201, UARCH_POWER9_DD21)
CHECK_UARCH(arch, pvr, 0xffffefff, 0x004e0202, UARCH_POWER9_DD22)
CHECK_UARCH(arch, pvr, 0xffffefff, 0x004e0203, UARCH_POWER9_DD23)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00800000, UARCH_POWER10)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00700000, UARCH_CELLBE)
// 32 bit
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00040000, UARCH_PPC604)
CHECK_UARCH(arch, pvr, 0xfffff000, 0x00090000, UARCH_PPC604)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00090000, UARCH_PPC604)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x000a0000, UARCH_PPC604)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x00084202, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xfffffff0, 0x00080100, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xfffffff0, 0x00082200, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xfffffff0, 0x00082210, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x00083214, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xfffff0e0, 0x00087000, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xfffff000, 0x00083000, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xffffff00, 0x70000100, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x70000200, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x70000000, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x70020000, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00080000, UARCH_PPCG3)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x000c1101, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x000c0000, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x800c0000, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x80000200, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x80000201, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x80000000, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffffff00, 0x80010100, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x80010200, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x80010000, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x80020100, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x80020101, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x80020000, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x80030000, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x80040000, UARCH_PPCG4)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00030000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00060000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00070000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0x7fff0000, 0x00810000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0x7fff0000, 0x00820000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0x7fff0000, 0x00830000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0x7fff0000, 0x00840000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0x7fff0000, 0x00850000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0x7fff0000, 0x00860000, UARCH_PPC603)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x41810000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x41610000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x40B10000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x41410000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x50910000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x51510000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x41F10000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x51210000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x12910007, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x1291000d, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x1291000f, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x12910003, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x12910005, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x12910001, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x12910009, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x1291000b, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x12910000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff000f, 0x12910002, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x41510000, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x7ff11432, UARCH_PPC405)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x40000850, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x40000858, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x400008d3, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000ff7, 0x400008d4, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x400008db, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000ffb, 0x200008D0, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000ffb, 0x200008D8, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x40000440, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x40000481, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x50000850, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x50000851, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x50000892, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xf0000fff, 0x50000894, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xfff00fff, 0x53200891, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xfff00fff, 0x53400890, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xfff00fff, 0x53400891, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xffff0006, 0x13020002, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xffff0007, 0x13020004, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xffff0006, 0x13020000, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xffff0007, 0x13020005, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xffffff00, 0x13541800, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xfffffff0, 0x12C41C80, UARCH_PPC440)
CHECK_UARCH(arch, pvr, 0xffffffff, 0x11a52080, UARCH_PPC470)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x7ff50000, UARCH_PPC470)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x00050000, UARCH_PPC470)
CHECK_UARCH(arch, pvr, 0xffff0000, 0x11a50000, UARCH_PPC470)
UARCH_END
return arch;
}
bool has_altivec(struct uarch* arch) {
switch(arch->uarch) {
case UARCH_PPC970FX:
case UARCH_PPC970MP:
case UARCH_CELLBE:
case UARCH_POWER6:
case UARCH_POWER7:
case UARCH_POWER7PLUS:
case UARCH_POWER8:
case UARCH_POWER9:
case UARCH_POWER9_DD20:
case UARCH_POWER9_DD21:
case UARCH_POWER9_DD22:
case UARCH_POWER9_DD23:
case UARCH_POWER10:
return true;
default:
return false;
}
}
bool is_power9(struct uarch* arch) {
return arch->uarch == UARCH_POWER9 ||
arch->uarch == UARCH_POWER9_DD20 ||
arch->uarch == UARCH_POWER9_DD21 ||
arch->uarch == UARCH_POWER9_DD22 ||
arch->uarch == UARCH_POWER9_DD23;
}
char* get_str_uarch(struct cpuInfo* cpu) {
return cpu->arch->uarch_str;
}
char* get_str_process(struct cpuInfo* cpu) {
char* str = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
int32_t process = cpu->arch->process;
if(process == UNK) {
snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
}
else if(process > 100) {
sprintf(str, "%.2fum", (double)process/100);
}
else if(process > 0){
sprintf(str, "%dnm", process);
}
else {
snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
printBug("Found invalid process: '%d'", process);
}
return str;
}
void free_uarch_struct(struct uarch* arch) {
free(arch->uarch_str);
free(arch);
}

16
src/ppc/uarch.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __UARCH__
#define __UARCH__
#include <stdint.h>
#include "ppc.h"
struct uarch;
struct uarch* get_uarch_from_pvr(uint32_t pvr);
bool has_altivec(struct uarch* arch);
bool is_power9(struct uarch* arch);
char* get_str_uarch(struct cpuInfo* cpu);
char* get_str_process(struct cpuInfo* cpu);
void free_uarch_struct(struct uarch* arch);
#endif

40
src/ppc/udev.c Normal file
View File

@@ -0,0 +1,40 @@
#include <errno.h>
#include "../common/global.h"
#include "udev.h"
#define _PATH_TOPO_CORE_ID "topology/core_id"
#define _PATH_TOPO_PACKAGE_ID "topology/physical_package_id"
bool fill_array_from_sys(int *core_ids, int total_cores, char* SYS_PATH) {
int filelen;
char* buf;
char* end;
char path[128];
for(int i=0; i < total_cores; i++) {
sprintf(path, "%s%s/cpu%d/%s", _PATH_SYS_SYSTEM, _PATH_SYS_CPU, i, SYS_PATH);
if((buf = read_file(path, &filelen)) == NULL) {
printWarn("fill_array_from_sys: %s: %s", path, strerror(errno));
return false;
}
errno = 0;
core_ids[i] = strtol(buf, &end, 10);
if(errno != 0) {
printWarn("fill_array_from_sys: %s:", strerror(errno));
return false;
}
free(buf);
}
return true;
}
bool fill_core_ids_from_sys(int *core_ids, int total_cores) {
return fill_array_from_sys(core_ids, total_cores, _PATH_TOPO_CORE_ID);
}
bool fill_package_ids_from_sys(int* package_ids, int total_cores) {
return fill_array_from_sys(package_ids, total_cores, _PATH_TOPO_PACKAGE_ID);
}

11
src/ppc/udev.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef __UDEV_PPC__
#define __UDEV_PPC__
#include "../common/udev.h"
#define _PATH_DT "/proc/device-tree/vpd/root-node-vpd@a000/enclosure@1e00/backplane@800/processor@1000"
#define _PATH_DT_PART "/part-number"
bool fill_core_ids_from_sys(int *core_ids, int total_cores);
bool fill_package_ids_from_sys(int* package_ids, int total_cores);
#endif

View File

@@ -4,6 +4,9 @@
#elif defined __linux__
#define _GNU_SOURCE
#include <sched.h>
#elif defined __FreeBSD__
#include <sys/param.h>
#include <sys/cpuset.h>
#elif defined __APPLE__
#define UNUSED(x) (void)(x)
#endif
@@ -13,6 +16,7 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include "apic.h"
#include "cpuid_asm.h"
@@ -24,7 +28,7 @@
*/
unsigned char bit_scan_reverse(uint32_t* index, uint64_t mask) {
for(uint64_t i = (8 * sizeof(uint64_t)); i > 0; i--) {
if((mask & (1LL << (i-1))) != 0) {
if((mask & (1ULL << (i-1))) != 0) {
*index = (uint64_t) (i-1);
break;
}
@@ -57,7 +61,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);
@@ -76,16 +80,25 @@ bool bind_to_cpu(int cpu_id) {
HANDLE process = GetCurrentProcess();
DWORD_PTR processAffinityMask = 1 << cpu_id;
return SetProcessAffinityMask(process, processAffinityMask);
#else
#elif defined __linux__
cpu_set_t currentCPU;
CPU_ZERO(&currentCPU);
CPU_SET(cpu_id, &currentCPU);
if (sched_setaffinity (0, sizeof(currentCPU), &currentCPU) == -1) {
perror("sched_setaffinity");
printWarn("sched_setaffinity: %s", strerror(errno));
return false;
}
return true;
#endif
#elif defined __FreeBSD__
cpuset_t currentCPU;
CPU_ZERO(&currentCPU);
CPU_SET(cpu_id, &currentCPU);
if(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &currentCPU) == -1) {
printWarn("cpuset_setaffinity: %s", strerror(errno));
return false;
}
return true;
#endif
}
#endif
@@ -97,51 +110,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;
@@ -158,10 +171,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;
}
@@ -182,13 +195,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;
@@ -196,15 +209,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;
@@ -216,45 +229,43 @@ 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++;
}
printf("[i=%d]: %p\n", i, (void *) topo->cach->cach_arr[i]);
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);
@@ -278,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;
@@ -295,12 +306,21 @@ 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
#ifdef __linux__
// In Linux we reset the affinity; first we get the original mask
cpu_set_t original_mask;
if(sched_getaffinity(0, sizeof(original_mask), &original_mask) == -1) {
printWarn("sched_getaffinity: %s", strerror(errno));
return false;
}
#endif
for(int i=0; i < n; i++) {
if(!bind_to_cpu(i)) {
printErr("Failed binding to CPU %d", i);
@@ -308,18 +328,27 @@ bool fill_apic_ids(uint32_t* apic_ids, int n, bool x2apic_id) {
}
apic_ids[i] = get_apic_id(x2apic_id);
}
#ifdef __linux__
// With the original mask previosly retrieved, we reset the affinity
if (sched_setaffinity (0, sizeof(original_mask), &original_mask) == -1) {
printWarn("sched_setaffinity: %s", strerror(errno));
return false;
}
#endif
#endif
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) {
@@ -336,48 +365,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");
@@ -386,16 +415,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);
@@ -405,17 +434,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);
@@ -424,7 +453,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
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ char* get_str_avx(struct cpuInfo* cpu);
char* get_str_sse(struct cpuInfo* cpu);
char* get_str_fma(struct cpuInfo* cpu);
char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket);
char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq);
char* get_str_cpu_name_abbreviated(struct cpuInfo* cpu);
void print_debug(struct cpuInfo* cpu);
void print_raw(struct cpuInfo* cpu);

158
src/x86/freq.c Normal file
View File

@@ -0,0 +1,158 @@
#define _GNU_SOURCE
#include <stdio.h>
#include "freq.h"
#include "../common/global.h"
#include <immintrin.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#define MEASURE_TIME_SECONDS 5
#define MAX_NUMBER_THREADS 512
#define FREQ_VECTOR_SIZE 1<<16
#define LOOP_ITERS 100000000
struct freq_thread {
bool end;
bool measure;
double freq;
};
double vector_average_harmonic(double* v, int len) {
double acc = 0.0;
for(int i=0; i < len; i++) {
acc += 1 / v[i];
}
return len / acc;
}
void sleep_ms(int64_t ms) {
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&ts, &ts);
}
void* measure_freq(void *freq_ptr) {
struct freq_thread* freq = (struct freq_thread*) freq_ptr;
char* end = NULL;
char* line = NULL;
size_t len = 0;
ssize_t read;
int v = 0;
double* freq_vector = malloc(sizeof(double) * FREQ_VECTOR_SIZE);
while(!freq->end) {
if(!freq->measure) continue;
FILE* fp = fopen("/proc/cpuinfo", "r");
if(fp == NULL) return NULL;
while ((read = getline(&line, &len, fp)) != -1) {
if((line = strstr(line, "cpu MHz")) != NULL) {
line = strstr(line, "\t: ");
if(line == NULL) return NULL;
line += sizeof("\t: ") - 1;
double f = strtold(line, &end);
if(errno != 0) {
printf("strtol: %s", strerror(errno));
return NULL;
}
freq_vector[v] = f;
v++;
}
}
fclose(fp);
sleep_ms(500);
}
freq->freq = vector_average_harmonic(freq_vector, v);
printWarn("AVX2 measured freq=%f\n", freq->freq);
return NULL;
}
void* compute_avx() {
bool end = false;
struct timeval begin, now;
__m256 a = _mm256_set1_ps(1.5);
__m256 b = _mm256_set1_ps(1.2);
__m256 c = _mm256_set1_ps(0.0);
gettimeofday(&begin, NULL);
while(!end) {
for(uint64_t i=0; i < LOOP_ITERS; i++) {
c = _mm256_fmadd_ps(a, b, c);
}
gettimeofday(&now, NULL);
double elapsed = (now.tv_sec - begin.tv_sec) + ((now.tv_usec - begin.tv_usec)/1000000.0);
end = elapsed >= (double) MEASURE_TIME_SECONDS;
}
FILE* fp = fopen("/dev/null", "w");
if(fp == NULL) {
printf("fopen: %s", strerror(errno));
}
else {
fprintf(fp, "%f", c[0]);
fclose(fp);
}
return NULL;
}
int64_t measure_avx_frequency(struct cpuInfo* cpu) {
int ret;
struct freq_thread* freq_struct = malloc(sizeof(struct freq_thread));
freq_struct->end = false;
freq_struct->measure = false;
pthread_t freq_t;
if(pthread_create(&freq_t, NULL, measure_freq, freq_struct)) {
fprintf(stderr, "Error creating thread\n");
return -1;
}
pthread_t* compute_th = malloc(sizeof(pthread_t) * cpu->topo->total_cores);
for(int i=0; i < cpu->topo->total_cores; i++) {
ret = pthread_create(&compute_th[i], NULL, compute_avx, NULL);
if(ret != 0) {
fprintf(stderr, "Error creating thread\n");
return -1;
}
}
printf("cpufetch is measuring AVX2 frequency...");
fflush(stdout);
sleep_ms(500);
freq_struct->measure = true;
for(int i=0; i < cpu->topo->total_cores; i++) {
if(pthread_join(compute_th[i], NULL)) {
fprintf(stderr, "Error joining thread\n");
return -1;
}
freq_struct->end = true;
}
if(pthread_join(freq_t, NULL)) {
fprintf(stderr, "Error joining thread\n");
return -1;
}
printf("\r ");
return freq_struct->freq;
}

9
src/x86/freq.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef __FREQ__
#define __FREQ__
#include <stdint.h>
#include "../common/cpu.h"
int64_t measure_avx_frequency(struct cpuInfo* cpu);
#endif

View File

@@ -38,8 +38,6 @@
typedef uint32_t MICROARCH;
#define STRING_UNKNOWN "Unknown"
// Data not available
#define NA -1
@@ -80,7 +78,7 @@ enum {
UARCH_SUNNY_COVE,
UARCH_GOLDMONT_PLUS,
UARCH_TREMONT,
UARCH_WILLOW_COVE,
UARCH_LAKEMONT,
UARCH_COFFE_LAKE,
UARCH_ITANIUM,
UARCH_KNIGHTS_FERRY,
@@ -91,6 +89,7 @@ enum {
UARCH_CEDAR_MILL,
UARCH_ITANIUM2,
UARCH_ICE_LAKE,
UARCH_TIGER_LAKE,
// AMD //
UARCH_AM486,
UARCH_AM5X86,
@@ -121,10 +120,10 @@ struct uarch {
#define UARCH_START if (false) {}
#define CHECK_UARCH(arch, ef_, f_, em_, m_, s_, str, uarch, process) \
else if (ef_ == ef && f_ == f && (em_ == NA || em_ == em) && (m_ == NA || m_ == m) && (s_ == NA || s_ == s)) fill_uarch(arch, str, uarch, process);
#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); }
#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, STRING_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 +131,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 //
@@ -149,7 +148,9 @@ struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, u
CHECK_UARCH(arch, 0, 5, 0, 4, NA, "P5 MMX", UARCH_P5, UNK)
CHECK_UARCH(arch, 0, 5, 0, 7, NA, "P5 MMX", UARCH_P5, UNK)
CHECK_UARCH(arch, 0, 5, 0, 8, NA, "P5 MMX", UARCH_P5, 250)
CHECK_UARCH(arch, 0, 5, 0, 9, 0, "Lakemont", UARCH_LAKEMONT, 32)
CHECK_UARCH(arch, 0, 5, 0, 9, NA, "P5 MMX", UARCH_P5, UNK)
CHECK_UARCH(arch, 0, 5, 0, 10, 0, "Lakemont", UARCH_LAKEMONT, 32)
CHECK_UARCH(arch, 0, 6, 0, 0, NA, "P6 Pentium II", UARCH_P6, UNK)
CHECK_UARCH(arch, 0, 6, 0, 1, NA, "P6 Pentium II", UARCH_P6, UNK) // process depends on core
CHECK_UARCH(arch, 0, 6, 0, 2, NA, "P6 Pentium II", UARCH_P6, UNK)
@@ -220,13 +221,14 @@ struct uarch* get_uarch_from_cpuid_intel(uint32_t ef, uint32_t f, uint32_t em, u
CHECK_UARCH(arch, 0, 6, 8, 5, NA, "Knights Mill", UARCH_KNIGHTS_MILL, 14) // no spec update; only MSR_CPUID_table* so far
CHECK_UARCH(arch, 0, 6, 8, 6, NA, "Tremont", UARCH_TREMONT, 10) // LX*
CHECK_UARCH(arch, 0, 6, 8, 10, NA, "Tremont", UARCH_TREMONT, 10) // no spec update; only geekbench.com example
CHECK_UARCH(arch, 0, 6, 8, 12, NA, "Willow Cove", UARCH_WILLOW_COVE, 10) // found only on en.wikichip.org
CHECK_UARCH(arch, 0, 6, 8, 13, NA, "Willow Cove", UARCH_WILLOW_COVE, 10) // LX*
CHECK_UARCH(arch, 0, 6, 8, 14, 9, "Amber Lake", UARCH_AMBER_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 6, 8, 12, NA, "Tiger Lake", UARCH_TIGER_LAKE, 10) // instlatx64
CHECK_UARCH(arch, 0, 6, 8, 13, NA, "Tiger Lake", UARCH_TIGER_LAKE, 10) // instlatx64
// CHECK_UARCH(arch, 0, 6, 8, 14, 9, ...) It is not possible to determine uarch only from CPUID dump (can be Kaby Lake or Amber Lake)
CHECK_UARCH(arch, 0, 6, 8, 14, 10, "Kaby Lake", UARCH_KABY_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 6, 8, 14, 11, "Whiskey Lake", UARCH_WHISKEY_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 6, 8, 14, 12, "Comet Lake", UARCH_COMET_LAKE, 14) // wikichip
CHECK_UARCH(arch, 0, 6, 9, 6, NA, "Tremont", UARCH_TREMONT, 10) // LX*
CHECK_UARCH(arch, 0, 6, 9, 10, NA, "Tremont", UARCH_TREMONT, 10) // instlatx64
CHECK_UARCH(arch, 0, 6, 9, 12, NA, "Tremont", UARCH_TREMONT, 10) // LX*
CHECK_UARCH(arch, 0, 6, 9, 13, NA, "Sunny Cove", UARCH_SUNNY_COVE, 10) // LX*
CHECK_UARCH(arch, 0, 6, 9, 14, 9, "Kaby Lake", UARCH_KABY_LAKE, 14)
@@ -249,14 +251,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 +266,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)
@@ -272,7 +274,8 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
CHECK_UARCH(arch, 0, 4, NA, NA, NA, "Am5x86", UARCH_AM5X86, UNK)
CHECK_UARCH(arch, 0, 5, 0, 6, NA, "K6", UARCH_K6, 300)
CHECK_UARCH(arch, 0, 5, 0, 7, NA, "K6", UARCH_K6, 250) // *p from sandpile.org
CHECK_UARCH(arch, 0, 5, 0, 13, NA, "K6", UARCH_K6, 80) // *p from sandpile.org
CHECK_UARCH(arch, 0, 5, 0, 10, NA, "K7", UARCH_K7, 130) // Geode NX
CHECK_UARCH(arch, 0, 5, 0, 13, NA, "K6", UARCH_K6, 80) // *p from sandpile.org
CHECK_UARCH(arch, 0, 5, NA, NA, NA, "K6", UARCH_K6, UNK)
CHECK_UARCH(arch, 0, 6, 0, 1, NA, "K7", UARCH_K7, 250)
CHECK_UARCH(arch, 0, 6, 0, 2, NA, "K7", UARCH_K7, 180)
@@ -327,7 +330,7 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
CHECK_UARCH(arch, 2, 15, NA, NA, NA, "Puma 2008", UARCH_PUMA_2008, 65)
CHECK_UARCH(arch, 3, 15, NA, NA, NA, "K10", UARCH_K10, 32)
CHECK_UARCH(arch, 5, 15, NA, NA, NA, "Bobcat", UARCH_BOBCAT, 40)
CHECK_UARCH(arch, 6, 15, 0, 0, NA, "Bulldozer", UARCH_BULLDOZER, 32) // iNAtlatx64 engr sample
CHECK_UARCH(arch, 6, 15, 0, 0, NA, "Bulldozer", UARCH_BULLDOZER, 32) // instlatx64 engr sample
CHECK_UARCH(arch, 6, 15, 0, 1, NA, "Bulldozer", UARCH_BULLDOZER, 32)
CHECK_UARCH(arch, 6, 15, 0, 2, NA, "Piledriver", UARCH_PILEDRIVER, 32)
CHECK_UARCH(arch, 6, 15, 1, 0, NA, "Piledriver", UARCH_PILEDRIVER, 32)
@@ -335,76 +338,108 @@ struct uarch* get_uarch_from_cpuid_amd(uint32_t ef, uint32_t f, uint32_t em, uin
CHECK_UARCH(arch, 6, 15, 3, 0, NA, "Steamroller", UARCH_STEAMROLLER, 28)
CHECK_UARCH(arch, 6, 15, 3, 8, NA, "Steamroller", UARCH_STEAMROLLER, 28)
CHECK_UARCH(arch, 6, 15, 4, 0, NA, "Steamroller", UARCH_STEAMROLLER, 28) // Software Optimization Guide (15h) says it has the same iNAt latencies as (6,15),(3,x).
CHECK_UARCH(arch, 6, 15, 6, 0, NA, "Excavator", UARCH_EXCAVATOR, 28) // undocumented, but iNAtlatx64 samples
CHECK_UARCH(arch, 6, 15, 6, 0, NA, "Excavator", UARCH_EXCAVATOR, 28) // undocumented, but instlatx64 samples
CHECK_UARCH(arch, 6, 15, 6, 5, NA, "Excavator", UARCH_EXCAVATOR, 28) // undocumented, but sample from Alexandros Couloumbis
CHECK_UARCH(arch, 6, 15, 7, 0, NA, "Excavator", UARCH_EXCAVATOR, 28)
CHECK_UARCH(arch, 7, 15, 0, 0, NA, "Jaguar", UARCH_JAGUAR, 28)
CHECK_UARCH(arch, 7, 15, 2, 6, NA, "Jaguar", UARCH_JAGUAR, 28) // AMD Cato (Xbox One?)
CHECK_UARCH(arch, 7, 15, 3, 0, NA, "Puma 2014", UARCH_PUMA_2014, 28)
CHECK_UARCH(arch, 8, 15, 0, 0, NA, "Zen", UARCH_ZEN, 14) // iNAtlatx64 engr sample
CHECK_UARCH(arch, 8, 15, 0, 0, NA, "Zen", UARCH_ZEN, 14) // instlatx64 engr sample
CHECK_UARCH(arch, 8, 15, 0, 1, NA, "Zen", UARCH_ZEN, 14)
CHECK_UARCH(arch, 8, 15, 0, 8, NA, "Zen+", UARCH_ZEN_PLUS, 12)
CHECK_UARCH(arch, 8, 15, 1, 1, NA, "Zen", UARCH_ZEN, 14) // found only on en.wikichip.org & iNAtlatx64 examples
CHECK_UARCH(arch, 8, 15, 1, 1, NA, "Zen", UARCH_ZEN, 14) // found only on en.wikichip.org & instlatx64 examples
CHECK_UARCH(arch, 8, 15, 1, 8, NA, "Zen+", UARCH_ZEN_PLUS, 12) // found only on en.wikichip.org
CHECK_UARCH(arch, 8, 15, 2, 0, NA, "Zen", UARCH_ZEN, 14) // Dali, found on instlatx64 and en.wikichip.org
CHECK_UARCH(arch, 8, 15, 3, 1, NA, "Zen 2", UARCH_ZEN2, 7) // found only on en.wikichip.org
CHECK_UARCH(arch, 8, 15, 4, 7, NA, "Zen 2", UARCH_ZEN2, 7) // instlatx64 example (AMD 4700S)
CHECK_UARCH(arch, 8, 15, 5, 0, NA, "Zen", UARCH_ZEN, 14) // instlatx64 example (Subor Z+)
CHECK_UARCH(arch, 8, 15, 6, 0, NA, "Zen 2", UARCH_ZEN2, 7) // undocumented, geekbench.com example
CHECK_UARCH(arch, 8, 15, 7, 1, NA, "Zen 2", UARCH_ZEN2, 7) // undocumented, but samples from Steven Noonan
CHECK_UARCH(arch, 10, 15, NA, NA, NA, "Zen 3", UARCH_ZEN3, 7) // undocumented, LX*
CHECK_UARCH(arch, 8, 15, 6, 8, NA, "Zen 2", UARCH_ZEN2, 7) // found on instlatx64
CHECK_UARCH(arch, 8, 15, 7, 1, NA, "Zen 2", UARCH_ZEN2, 7) // samples from Steven Noonan and instlatx64
CHECK_UARCH(arch, 10, 15, 0, 1, NA, "Zen 3", UARCH_ZEN3, 7) // instlatx64
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)
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t dump, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s) {
if(cpu->cpu_vendor == CPU_VENDOR_INTEL) {
if(dump == 0x000806E9) {
// It is not possible to determine uarch only from CPUID dump (can be Kaby Lake or Amber Lake)
struct uarch* arch = emalloc(sizeof(struct uarch));
if(strstr(cpu->cpu_name, "Y") != NULL) {
fill_uarch(arch, "Amber Lake", UARCH_AMBER_LAKE, 14);
}
else {
fill_uarch(arch, "Kaby Lake", UARCH_KABY_LAKE, 14);
}
return arch;
}
return get_uarch_from_cpuid_intel(ef, f, em, m, s);
else
}
else
return get_uarch_from_cpuid_amd(ef, f, em, m, s);
}
bool vpus_are_AVX512(struct cpuInfo* cpu) {
return cpu->arch->uarch != UARCH_ICE_LAKE;
return cpu->arch->uarch != UARCH_ICE_LAKE && cpu->arch->uarch != UARCH_TIGER_LAKE;
}
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:
case UARCH_TIGER_LAKE:
// AMD
case UARCH_ZEN2:
case UARCH_ZEN3:
case UARCH_ZEN3:
return 2;
default:
return 1;
}
}
bool choose_new_intel_logo_uarch(struct cpuInfo* cpu) {
switch(cpu->arch->uarch) {
case UARCH_ROCKET_LAKE:
case UARCH_TIGER_LAKE:
return true;
default:
return false;
}
}
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) {
@@ -424,7 +459,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);
}

View File

@@ -7,10 +7,11 @@
struct uarch;
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s);
struct uarch* get_uarch_from_cpuid(struct cpuInfo* cpu, uint32_t dump, uint32_t ef, uint32_t f, uint32_t em, uint32_t m, int s);
bool vpus_are_AVX512(struct cpuInfo* cpu);
bool is_knights_landing(struct cpuInfo* cpu);
int get_number_of_vpus(struct cpuInfo* cpu);
bool choose_new_intel_logo_uarch(struct cpuInfo* cpu);
char* get_str_uarch(struct cpuInfo* cpu);
char* get_str_process(struct cpuInfo* cpu);
void free_uarch_struct(struct uarch* arch);

23
src/x86/uarch_decode.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/bash -u
CPUID=0x00A50F00
efamily=$(((${CPUID}>>20)&0xFF))
family=$(((${CPUID}>>8)&0xF))
emodel=$(((${CPUID}>>16)&0xF))
model=$(((${CPUID}>>4)&0xF))
stepping=$((${CPUID}&0xF))
printf 'CPUID: 0x%.8X\n' $CPUID
printf -- '- EF = 0x%X (%d)\n' $efamily $efamily
printf -- '- F = 0x%X (%d)\n' $family $family
printf -- '- EM = 0x%X (%d)\n' $emodel $emodel
printf -- '- M = 0x%X (%d)\n' $model $model
printf -- '- S = 0x%X (%d)\n' $stepping $stepping
#EF=$efamily
#F=$family
#EM=$emodel
#M=$model
#S=$stepping
#grep -E "\s*CHECK_UARCH\(arch,\s*${EF},\s*${F},\s*(${EM}|NA),\s*(${M}|NA),\s*(${S}|NA)" uarch.c