mirror of
https://github.com/Dr-Noob/cpufetch.git
synced 2026-03-25 16:00:39 +01:00
Add support to detect if HT/SMT is enabled or disabled
This commit is contained in:
148
src/cpuid.c
148
src/cpuid.c
@@ -1,16 +1,18 @@
|
|||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <sched.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "udev.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "udev.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
#include "cpuid_asm.h"
|
#include "cpuid_asm.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
@@ -79,7 +81,8 @@ struct topology {
|
|||||||
uint32_t logical_cores;
|
uint32_t logical_cores;
|
||||||
uint32_t smt;
|
uint32_t smt;
|
||||||
uint32_t sockets;
|
uint32_t sockets;
|
||||||
bool ht;
|
bool smt_available;
|
||||||
|
bool smt_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_cpu_info(struct cpuInfo* cpu) {
|
void init_cpu_info(struct cpuInfo* cpu) {
|
||||||
@@ -258,7 +261,47 @@ struct cpuInfo* get_cpu_info() {
|
|||||||
return cpu;
|
return cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 80/2/20
|
bool bind_to_cpu(int cpu_id) {
|
||||||
|
#ifdef _WIN32 // TODO
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
cpu_set_t currentCPU;
|
||||||
|
CPU_ZERO(¤tCPU);
|
||||||
|
CPU_SET(cpu_id, ¤tCPU);
|
||||||
|
if (sched_setaffinity (0, sizeof(currentCPU), ¤tCPU) == -1) {
|
||||||
|
perror("sched_setaffinity");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t apic_id(int cpu_id) {
|
||||||
|
uint32_t eax = 0x0000000B;
|
||||||
|
uint32_t ebx = 0;
|
||||||
|
uint32_t ecx = 0;
|
||||||
|
uint32_t edx = 0;
|
||||||
|
|
||||||
|
cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
|
return edx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_smt_enabled(struct topology* topo) {
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
|
for(int i = 0; i < topo->total_cores; i++) {
|
||||||
|
if(!bind_to_cpu(i)) {
|
||||||
|
printErr("Failed binding to CPU %d", i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
id = apic_id(i) & 1; // get the last bit
|
||||||
|
if(id == 1) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct topology* get_topology_info(struct cpuInfo* cpu) {
|
struct topology* get_topology_info(struct cpuInfo* cpu) {
|
||||||
struct topology* topo = malloc(sizeof(struct topology));
|
struct topology* topo = malloc(sizeof(struct topology));
|
||||||
uint32_t eax = 0;
|
uint32_t eax = 0;
|
||||||
@@ -270,12 +313,27 @@ struct topology* get_topology_info(struct cpuInfo* cpu) {
|
|||||||
if (cpu->maxLevels >= 0x00000001) {
|
if (cpu->maxLevels >= 0x00000001) {
|
||||||
eax = 0x00000001;
|
eax = 0x00000001;
|
||||||
cpuid(&eax, &ebx, &ecx, &edx);
|
cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
topo->ht = edx & (1 << 28);
|
topo->smt_available = edx & (1 << 28);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printWarn("Can't read HT information from cpuid (needed level is 0x%.8X, max is 0x%.8X). Assuming HT is disabled", 0x00000001, cpu->maxLevels);
|
printWarn("Can't read HT information from cpuid (needed level is 0x%.8X, max is 0x%.8X). Assuming HT is not available", 0x00000001, cpu->maxLevels);
|
||||||
topo->ht = false;
|
topo->smt_available = false;
|
||||||
|
topo->smt_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ask the OS the total number of cores it sees
|
||||||
|
// If we have one socket, it will be same as the cpuid,
|
||||||
|
// but in dual socket it will not!
|
||||||
|
#ifdef _WIN32
|
||||||
|
SYSTEM_INFO info;
|
||||||
|
GetSystemInfo(&info);
|
||||||
|
topo->total_cores = info.dwNumberOfProcessors;
|
||||||
|
#else
|
||||||
|
if((topo->total_cores = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
|
||||||
|
perror("sysconf");
|
||||||
|
topo->total_cores = topo->logical_cores; // fallback
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
switch(cpu->cpu_vendor) {
|
switch(cpu->cpu_vendor) {
|
||||||
case VENDOR_INTEL:
|
case VENDOR_INTEL:
|
||||||
@@ -300,12 +358,14 @@ struct topology* get_topology_info(struct cpuInfo* cpu) {
|
|||||||
}
|
}
|
||||||
topo->logical_cores = ebx & 0xFFFF;
|
topo->logical_cores = ebx & 0xFFFF;
|
||||||
topo->physical_cores = topo->logical_cores / topo->smt;
|
topo->physical_cores = topo->logical_cores / topo->smt;
|
||||||
|
topo->smt_enabled = is_smt_enabled(topo);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels);
|
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x0000000B, cpu->maxLevels);
|
||||||
topo->physical_cores = 1;
|
topo->physical_cores = 1;
|
||||||
topo->logical_cores = 1;
|
topo->logical_cores = 1;
|
||||||
topo->smt = 1;
|
topo->smt = 1;
|
||||||
|
topo->smt_enabled = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VENDOR_AMD:
|
case VENDOR_AMD:
|
||||||
@@ -320,37 +380,34 @@ struct topology* get_topology_info(struct cpuInfo* cpu) {
|
|||||||
topo->smt = ((ebx >> 8) & 0x03) + 1;
|
topo->smt = ((ebx >> 8) & 0x03) + 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x8000001E, cpu->maxLevels);
|
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x8000001E, cpu->maxExtendedLevels);
|
||||||
topo->smt = 1;
|
topo->smt = 1;
|
||||||
}
|
}
|
||||||
topo->physical_cores = topo->logical_cores / topo->smt;
|
topo->physical_cores = topo->logical_cores / topo->smt;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxLevels);
|
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxExtendedLevels);
|
||||||
topo->physical_cores = 1;
|
topo->physical_cores = 1;
|
||||||
topo->logical_cores = 1;
|
topo->logical_cores = 1;
|
||||||
topo->smt = 1;
|
topo->smt = 1;
|
||||||
}
|
}
|
||||||
|
if (cpu->maxLevels >= 0x0000000B) {
|
||||||
|
topo->smt_enabled = is_smt_enabled(topo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printWarn("Can't read topology information from cpuid (needed level is 0x%.8X, max is 0x%.8X)", 0x80000008, cpu->maxLevels);
|
||||||
|
topo->smt_enabled = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printBug("Cant get topology because VENDOR is empty");
|
printBug("Cant get topology because VENDOR is empty");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask the OS the total number of cores it sees
|
if(topo->smt_enabled)
|
||||||
// If we have one socket, it will be same as the cpuid,
|
topo->sockets = topo->total_cores / topo->smt / topo->physical_cores; // Idea borrowed from lscpu
|
||||||
// but in dual socket it will not!
|
else
|
||||||
#ifdef _WIN32
|
topo->sockets = topo->total_cores / topo->physical_cores;
|
||||||
SYSTEM_INFO info;
|
|
||||||
GetSystemInfo(&info);
|
|
||||||
topo->total_cores = info.dwNumberOfProcessors;
|
|
||||||
#else
|
|
||||||
if((topo->total_cores = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
|
|
||||||
perror("sysconf");
|
|
||||||
topo->total_cores = topo->logical_cores; // fallback
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
topo->sockets = topo->total_cores / topo->smt / topo->physical_cores; // Idea borrowed from lscpu
|
|
||||||
|
|
||||||
return topo;
|
return topo;
|
||||||
}
|
}
|
||||||
@@ -594,16 +651,33 @@ char* get_str_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* get_str_topology(struct topology* topo, bool dual_socket) {
|
// TODO: Refactoring
|
||||||
|
char* get_str_topology(struct cpuInfo* cpu, struct topology* topo, bool dual_socket) {
|
||||||
char* string;
|
char* string;
|
||||||
if(topo->smt > 1) {
|
if(topo->smt > 1) {
|
||||||
//3 for digits, 8 for ' cores (', 3 for digits, 9 for ' threads)'
|
//3 for digits, 21 for ' cores (SMT disabled)' which is the longest possible output
|
||||||
uint32_t size = 3+8+3+9+1;
|
uint32_t size = 3+21+1;
|
||||||
string = malloc(sizeof(char)*size);
|
string = malloc(sizeof(char)*size);
|
||||||
if(dual_socket)
|
if(dual_socket) {
|
||||||
snprintf(string, size, "%d cores (%d threads)",topo->physical_cores * topo->sockets, topo->logical_cores * topo->sockets);
|
if(topo->smt_enabled)
|
||||||
else
|
snprintf(string, size, "%d cores (%d threads)",topo->physical_cores * topo->sockets, topo->logical_cores * topo->sockets);
|
||||||
snprintf(string, size, "%d cores (%d threads)",topo->physical_cores,topo->logical_cores);
|
else {
|
||||||
|
if(cpu->cpu_vendor == VENDOR_AMD)
|
||||||
|
snprintf(string, size, "%d cores (SMT disabled)",topo->physical_cores * topo->sockets);
|
||||||
|
else
|
||||||
|
snprintf(string, size, "%d cores (HT disabled)",topo->physical_cores * topo->sockets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(topo->smt_enabled)
|
||||||
|
snprintf(string, size, "%d cores (%d threads)",topo->physical_cores,topo->logical_cores);
|
||||||
|
else {
|
||||||
|
if(cpu->cpu_vendor == VENDOR_AMD)
|
||||||
|
snprintf(string, size, "%d cores (SMT disabled)",topo->physical_cores);
|
||||||
|
else
|
||||||
|
snprintf(string, size, "%d cores (HT disabled)",topo->physical_cores);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uint32_t size = 3+7+1;
|
uint32_t size = 3+7+1;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ char* get_str_l3(struct cache* cach, struct topology* topo);
|
|||||||
char* get_str_freq(struct frequency* freq);
|
char* get_str_freq(struct frequency* freq);
|
||||||
|
|
||||||
char* get_str_sockets(struct topology* topo);
|
char* get_str_sockets(struct topology* topo);
|
||||||
char* get_str_topology(struct topology* topo, bool dual_socket);
|
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_peak_performance(struct cpuInfo* cpu, struct topology* topo, int64_t freq);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
static const char* VERSION = "0.53";
|
static const char* VERSION = "0.54";
|
||||||
|
|
||||||
void print_help(char *argv[]) {
|
void print_help(char *argv[]) {
|
||||||
printf("Usage: %s [--version] [--help] [--levels] [--style fancy|retro] [--color 'R,G,B:R,G,B:R,G,B:R,G,B']\n\
|
printf("Usage: %s [--version] [--help] [--levels] [--style fancy|retro] [--color 'R,G,B:R,G,B:R,G,B:R,G,B']\n\
|
||||||
|
|||||||
@@ -309,8 +309,8 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
|
|||||||
char* cpu_name = get_str_cpu_name(cpu);
|
char* cpu_name = get_str_cpu_name(cpu);
|
||||||
char* sockets = get_str_sockets(topo);
|
char* sockets = get_str_sockets(topo);
|
||||||
char* max_frequency = get_str_freq(freq);
|
char* max_frequency = get_str_freq(freq);
|
||||||
char* n_cores = get_str_topology(topo, false);
|
char* n_cores = get_str_topology(cpu, topo, false);
|
||||||
char* n_cores_dual = get_str_topology(topo, true);
|
char* n_cores_dual = get_str_topology(cpu, topo, true);
|
||||||
char* avx = get_str_avx(cpu);
|
char* avx = get_str_avx(cpu);
|
||||||
char* sse = get_str_sse(cpu);
|
char* sse = get_str_sse(cpu);
|
||||||
char* fma = get_str_fma(cpu);
|
char* fma = get_str_fma(cpu);
|
||||||
|
|||||||
Reference in New Issue
Block a user