Files
fastfetch/src/detection/cpu/cpu_linux.c
T

232 lines
7.0 KiB
C
Raw Normal View History

2022-09-04 22:20:12 +02:00
#include "cpu.h"
#include "common/io/io.h"
#include "common/processing.h"
2022-09-04 22:20:12 +02:00
#include "common/properties.h"
2022-09-25 15:23:00 +08:00
#include "detection/temps/temps_linux.h"
2023-07-27 16:16:09 +08:00
#include "util/mallocHelper.h"
2022-09-04 22:20:12 +02:00
2022-12-28 17:18:08 +08:00
#include <sys/sysinfo.h>
2022-09-04 22:20:12 +02:00
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
2022-09-04 22:20:12 +02:00
2023-07-27 19:35:55 +08:00
#ifdef __ANDROID__
#include "common/settings.h"
static void detectAndroid(FFCPUResult* cpu)
{
if (cpu->name.length == 0)
ffSettingsGetAndroidProperty("ro.soc.model", &cpu->name);
if (cpu->vendor.length == 0)
{
if (!ffSettingsGetAndroidProperty("ro.soc.manufacturer", &cpu->vendor))
ffSettingsGetAndroidProperty("ro.product.product.manufacturer", &cpu->vendor);
}
}
#endif
2023-06-12 09:56:03 +08:00
static const char* parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer, FFstrbuf* cpuMHz, FFstrbuf* cpuIsa, FFstrbuf* cpuUarch)
2022-09-04 22:20:12 +02:00
{
2023-07-27 16:16:09 +08:00
FF_AUTO_CLOSE_FILE FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
2022-09-04 22:20:12 +02:00
if(cpuinfo == NULL)
2023-06-12 09:56:03 +08:00
return "fopen(\"/proc/cpuinfo\", \"r\") failed";
2022-09-04 22:20:12 +02:00
2023-07-27 16:16:09 +08:00
FF_AUTO_FREE char* line = NULL;
2022-09-04 22:20:12 +02:00
size_t len = 0;
while(getline(&line, &len, cpuinfo) != -1)
{
//Stop after the first CPU
if(*line == '\0' || *line == '\n')
2022-09-04 22:20:12 +02:00
break;
(void)(
ffParsePropLine(line, "model name :", &cpu->name) ||
ffParsePropLine(line, "vendor_id :", &cpu->vendor) ||
ffParsePropLine(line, "cpu cores :", physicalCoresBuffer) ||
2022-11-24 23:29:46 +08:00
ffParsePropLine(line, "cpu MHz :", cpuMHz) ||
ffParsePropLine(line, "isa :", cpuIsa) ||
ffParsePropLine(line, "uarch :", cpuUarch) ||
2023-07-12 11:38:56 +02:00
(cpu->name.length == 0 && ffParsePropLine(line, "Hardware :", &cpu->name)) || //For Android devices
(cpu->name.length == 0 && ffParsePropLine(line, "cpu :", &cpu->name)) || //For POWER
(cpu->name.length == 0 && ffParsePropLine(line, "cpu model :", &cpu->name)) //For MIPS
2022-09-04 22:20:12 +02:00
);
}
2023-06-12 09:56:03 +08:00
return NULL;
2022-09-04 22:20:12 +02:00
}
static double getGHz(const char* file)
{
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
2022-11-24 23:29:46 +08:00
if(ffAppendFileBuffer(file, &content))
{
double herz = ffStrbufToDouble(&content);
2022-09-04 22:20:12 +02:00
2022-11-24 23:29:46 +08:00
//ffStrbufToDouble failed
if(herz != herz)
return 0;
2022-09-04 22:20:12 +02:00
2022-11-24 23:29:46 +08:00
herz /= 1000.0; //to MHz
return herz / 1000.0; //to GHz
}
return 0;
2022-09-04 22:20:12 +02:00
}
static double getFrequency(const char* info, const char* scaling)
{
double frequency = getGHz(info);
if(frequency > 0.0)
return frequency;
return getGHz(scaling);
}
2023-01-21 14:03:57 +08:00
static double detectCPUTemp(void)
2022-09-04 22:20:12 +02:00
{
const FFlist* tempsResult = ffDetectTemps();
2022-09-04 22:20:12 +02:00
FF_LIST_FOR_EACH(FFTempValue, value, *tempsResult)
2022-09-04 22:20:12 +02:00
{
if(
ffStrbufFirstIndexS(&value->name, "cpu") < value->name.length ||
ffStrbufCompS(&value->name, "k10temp") == 0 ||
ffStrbufCompS(&value->name, "coretemp") == 0
) return value->value;
}
return FF_CPU_TEMP_UNSET;
}
static void parseIsa(FFstrbuf* cpuIsa)
{
if(ffStrbufStartsWithS(cpuIsa, "rv"))
{
// RISC-V ISA string example: "rv64imafdch_zicsr_zifencei".
// The _z parts are not important for CPU showcasing, so we remove them.
if(ffStrbufContainC(cpuIsa, '_'))
ffStrbufSubstrBeforeFirstC(cpuIsa, '_');
// Then we replace "imafd" with "g" since "g" is a shorthand.
if(ffStrbufContainS(cpuIsa, "imafd"))
{
// Remove 4 of the 5 characters and replace the remaining one with "g".
ffStrbufRemoveSubstr(cpuIsa, 4, 8);
cpuIsa->chars[4] = 'g';
}
// The final ISA output of the above example is "rv64gch".
}
if(ffStrbufStartsWithS(cpuIsa, "mips"))
{
ffStrbufSubstrAfterLastC(cpuIsa, ' ');
}
}
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
2022-09-04 22:20:12 +02:00
{
2023-06-12 09:56:03 +08:00
cpu->temperature = options->temp ? detectCPUTemp() : FF_CPU_TEMP_UNSET;
FF_STRBUF_AUTO_DESTROY physicalCoresBuffer = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY cpuMHz = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY cpuIsa = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY cpuUarch = ffStrbufCreate();
2023-06-12 09:56:03 +08:00
const char* error = parseCpuInfo(cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch);
if (error) return error;
2022-09-04 22:20:12 +02:00
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, 1);
2022-09-19 19:31:29 +02:00
2022-12-28 17:18:08 +08:00
cpu->coresLogical = (uint16_t) get_nprocs_conf();
cpu->coresOnline = (uint16_t) get_nprocs();
2022-09-04 22:20:12 +02:00
#define BP "/sys/devices/system/cpu/cpufreq/policy0/"
if(ffPathExists(BP, FF_PATHTYPE_DIRECTORY))
2022-11-24 23:29:46 +08:00
{
cpu->frequencyMin = getFrequency(BP"cpuinfo_min_freq", BP"scaling_min_freq");
cpu->frequencyMax = getFrequency(BP"cpuinfo_max_freq", BP"scaling_max_freq");
}
else
{
cpu->frequencyMin = cpu->frequencyMax = ffStrbufToDouble(&cpuMHz) / 1000;
}
2022-09-04 22:20:12 +02:00
if(cpuUarch.length > 0)
{
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuUarch);
}
if(cpuIsa.length > 0)
{
parseIsa(&cpuIsa);
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuIsa);
}
2023-06-12 09:56:03 +08:00
2023-07-27 19:35:55 +08:00
#ifdef __ANDROID__
detectAndroid(cpu);
#endif
2023-09-27 15:11:05 +08:00
if (cpu->name.length == 0)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
if (ffProcessAppendStdOut(&buffer, (char *const[]) { "lscpu", NULL }) == NULL)
2023-09-27 15:11:05 +08:00
{
char* pstart = buffer.chars;
2023-12-26 13:32:55 +08:00
if (cpu->vendor.length == 0)
{
pstart = strstr(pstart, "Vendor ID:");
if (pstart)
{
pstart += strlen("Vendor ID:");
while (isspace(*pstart)) ++pstart;
if (*pstart)
{
char* pend = strchr(pstart, '\n');
if (pend != NULL)
ffStrbufAppendNS(&cpu->vendor, (uint32_t) (pend - pstart), pstart);
else
{
ffStrbufAppendS(&cpu->vendor, pstart);
}
pstart = pend + 1;
}
}
}
while ((pstart = strstr(pstart, "Model name:")))
{
pstart += strlen("Model name:");
while (isspace(*pstart)) ++pstart;
if (*pstart == '\0')
break;
if (cpu->name.length > 0)
ffStrbufAppendS(&cpu->name, " + ");
2023-12-26 13:32:55 +08:00
if (*pstart == '-')
{
ffStrbufAppendS(&cpu->name, "Unknown");
++pstart;
continue;
}
char* pend = strchr(pstart, '\n');
if (pend != NULL)
ffStrbufAppendNS(&cpu->name, (uint32_t) (pend - pstart), pstart);
else
{
ffStrbufAppendS(&cpu->name, pstart);
break;
}
pstart = pend + 1;
}
2023-09-27 15:11:05 +08:00
}
}
2023-06-12 09:56:03 +08:00
return NULL;
2022-09-04 22:20:12 +02:00
}