2022-09-04 22:20:12 +02:00
|
|
|
#include "cpu.h"
|
2023-01-28 12:40:12 +01:00
|
|
|
#include "common/io/io.h"
|
2023-09-27 15:03:28 +08:00
|
|
|
#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"
|
2024-01-31 14:36:00 +08:00
|
|
|
#include "util/stringUtils.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>
|
2023-12-26 11:20:40 +08:00
|
|
|
#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)
|
2024-03-17 19:11:55 +08:00
|
|
|
{
|
2023-07-27 19:35:55 +08:00
|
|
|
ffSettingsGetAndroidProperty("ro.soc.model", &cpu->name);
|
2024-03-17 19:11:55 +08:00
|
|
|
ffStrbufClear(&cpu->vendor); // We usually detect the vendor of CPU core as ARM, but instead we want the vendor of SOC
|
|
|
|
|
}
|
2023-07-27 19:35:55 +08:00
|
|
|
if (cpu->vendor.length == 0)
|
|
|
|
|
{
|
|
|
|
|
if (!ffSettingsGetAndroidProperty("ro.soc.manufacturer", &cpu->vendor))
|
|
|
|
|
ffSettingsGetAndroidProperty("ro.product.product.manufacturer", &cpu->vendor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-03-14 20:40:40 +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;
|
|
|
|
|
|
2024-01-31 13:28:18 +08:00
|
|
|
#ifdef __aarch64__
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY implementer = ffStrbufCreate();
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-09-04 22:20:12 +02:00
|
|
|
while(getline(&line, &len, cpuinfo) != -1)
|
|
|
|
|
{
|
|
|
|
|
//Stop after the first CPU
|
2023-01-08 02:33:35 -06:00
|
|
|
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) ||
|
2024-03-14 20:40:40 +08:00
|
|
|
ffParsePropLine(line, "cpu MHz :", cpuMHz) ||
|
2023-01-08 02:33:35 -06:00
|
|
|
ffParsePropLine(line, "isa :", cpuIsa) ||
|
|
|
|
|
ffParsePropLine(line, "uarch :", cpuUarch) ||
|
2024-01-31 13:28:18 +08:00
|
|
|
|
|
|
|
|
#ifdef __aarch64__
|
|
|
|
|
(cpu->vendor.length == 0 && ffParsePropLine(line, "CPU implementer :", &implementer)) ||
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-07-12 11:38:56 +02:00
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "Hardware :", &cpu->name)) || //For Android devices
|
2023-10-22 23:09:43 -04:00
|
|
|
(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
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-31 13:28:18 +08:00
|
|
|
#ifdef __aarch64__
|
|
|
|
|
// https://github.com/util-linux/util-linux/blob/2cd89de14549d2b2c079a4f8b73f75500d229fee/sys-utils/lscpu-arm.c#L286
|
|
|
|
|
if (cpu->vendor.length == 0 && implementer.length > 2 /* 0xX */)
|
|
|
|
|
{
|
|
|
|
|
uint32_t implId = (uint32_t) strtoul(implementer.chars, NULL, 16);
|
|
|
|
|
switch (implId)
|
|
|
|
|
{
|
|
|
|
|
case 0x41: ffStrbufSetStatic(&cpu->vendor, "ARM"); break;
|
|
|
|
|
case 0x42: ffStrbufSetStatic(&cpu->vendor, "Broadcom"); break;
|
|
|
|
|
case 0x48: ffStrbufSetStatic(&cpu->vendor, "HiSilicon"); break;
|
|
|
|
|
case 0x4e: ffStrbufSetStatic(&cpu->vendor, "Nvidia"); break;
|
|
|
|
|
case 0x51: ffStrbufSetStatic(&cpu->vendor, "Qualcomm"); break;
|
|
|
|
|
case 0x53: ffStrbufSetStatic(&cpu->vendor, "Samsung"); break;
|
|
|
|
|
case 0x61: ffStrbufSetStatic(&cpu->vendor, "Apple"); break;
|
|
|
|
|
case 0x69: ffStrbufSetStatic(&cpu->vendor, "Intel"); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-06-12 09:56:03 +08:00
|
|
|
return NULL;
|
2022-09-04 22:20:12 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-17 16:14:35 +08:00
|
|
|
static uint32_t getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, const char* scalingFileName, FFstrbuf* buffer)
|
2022-09-04 22:20:12 +02:00
|
|
|
{
|
2024-02-29 10:20:50 +08:00
|
|
|
uint32_t baseLen = basePath->length;
|
|
|
|
|
ffStrbufAppendS(basePath, cpuinfoFileName);
|
|
|
|
|
bool ok = ffReadFileBuffer(basePath->chars, buffer);
|
|
|
|
|
ffStrbufSubstrBefore(basePath, baseLen);
|
|
|
|
|
if (ok)
|
2024-05-17 16:14:35 +08:00
|
|
|
return (uint32_t) ffStrbufToUInt(buffer, 0);
|
2024-02-29 10:20:50 +08:00
|
|
|
|
2024-03-12 23:48:03 +08:00
|
|
|
if (scalingFileName)
|
|
|
|
|
{
|
|
|
|
|
ffStrbufAppendS(basePath, scalingFileName);
|
|
|
|
|
ok = ffReadFileBuffer(basePath->chars, buffer);
|
|
|
|
|
ffStrbufSubstrBefore(basePath, baseLen);
|
|
|
|
|
if (ok)
|
2024-05-17 16:14:35 +08:00
|
|
|
return (uint32_t) ffStrbufToUInt(buffer, 0);
|
2024-03-12 23:48:03 +08:00
|
|
|
}
|
2024-03-14 18:45:08 +08:00
|
|
|
|
2024-05-17 16:14:35 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint8_t getNumCores(FFstrbuf* basePath, FFstrbuf* buffer)
|
|
|
|
|
{
|
|
|
|
|
uint32_t baseLen = basePath->length;
|
|
|
|
|
ffStrbufAppendS(basePath, "/affected_cpus");
|
|
|
|
|
bool ok = ffReadFileBuffer(basePath->chars, buffer);
|
|
|
|
|
ffStrbufSubstrBefore(basePath, baseLen);
|
|
|
|
|
if (ok)
|
|
|
|
|
return (uint8_t) ffStrbufCountC(buffer, ' ') + 1;
|
|
|
|
|
|
|
|
|
|
ffStrbufAppendS(basePath, "/related_cpus");
|
|
|
|
|
ok = ffReadFileBuffer(basePath->chars, buffer);
|
|
|
|
|
ffStrbufSubstrBefore(basePath, baseLen);
|
|
|
|
|
if (ok)
|
|
|
|
|
return (uint8_t) ffStrbufCountC(buffer, ' ') + 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
2022-09-04 22:20:12 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-21 09:09:08 +08:00
|
|
|
static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options)
|
2022-09-04 22:20:12 +02:00
|
|
|
{
|
2024-02-29 10:20:50 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/devices/system/cpu/cpufreq/");
|
|
|
|
|
FF_AUTO_CLOSE_DIR DIR* dir = opendir(path.chars);
|
2024-03-07 21:31:11 +08:00
|
|
|
if (!dir) return false;
|
|
|
|
|
|
2024-02-29 10:20:50 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
|
|
|
|
uint32_t baseLen = path.length;
|
|
|
|
|
|
|
|
|
|
struct dirent* entry;
|
2024-05-18 09:58:04 +08:00
|
|
|
while ((entry = readdir(dir)) != NULL)
|
2024-02-29 10:20:50 +08:00
|
|
|
{
|
|
|
|
|
if (ffStrStartsWith(entry->d_name, "policy") && isdigit(entry->d_name[strlen("policy")]))
|
|
|
|
|
{
|
|
|
|
|
ffStrbufAppendS(&path, entry->d_name);
|
2024-05-17 16:14:35 +08:00
|
|
|
uint32_t fbase = getFrequency(&path, "/base_frequency", NULL, &buffer);
|
|
|
|
|
if (fbase > 0)
|
2024-03-14 18:45:08 +08:00
|
|
|
{
|
|
|
|
|
if (cpu->frequencyBase == cpu->frequencyBase)
|
|
|
|
|
cpu->frequencyBase = cpu->frequencyBase > fbase ? cpu->frequencyBase : fbase;
|
|
|
|
|
else
|
|
|
|
|
cpu->frequencyBase = fbase;
|
|
|
|
|
}
|
2024-05-20 18:33:47 +08:00
|
|
|
uint32_t fbioslimit = getFrequency(&path, "/bios_limit", NULL, &buffer);
|
|
|
|
|
if (fbioslimit > 0)
|
|
|
|
|
{
|
|
|
|
|
if (cpu->frequencyBiosLimit == cpu->frequencyBiosLimit)
|
|
|
|
|
cpu->frequencyBiosLimit = cpu->frequencyBiosLimit > fbioslimit ? cpu->frequencyBiosLimit : fbioslimit;
|
|
|
|
|
else
|
|
|
|
|
cpu->frequencyBiosLimit = fbioslimit;
|
|
|
|
|
}
|
2024-05-17 16:14:35 +08:00
|
|
|
uint32_t fmax = getFrequency(&path, "/cpuinfo_max_freq", "/scaling_max_freq", &buffer);
|
|
|
|
|
if (fmax > 0)
|
2024-03-14 18:45:08 +08:00
|
|
|
{
|
|
|
|
|
if (cpu->frequencyMax == cpu->frequencyMax)
|
|
|
|
|
cpu->frequencyMax = cpu->frequencyMax > fmax ? cpu->frequencyMax : fmax;
|
|
|
|
|
else
|
|
|
|
|
cpu->frequencyMax = fmax;
|
|
|
|
|
}
|
2024-05-17 16:14:35 +08:00
|
|
|
uint32_t fmin = getFrequency(&path, "/cpuinfo_min_freq", "/scaling_min_freq", &buffer);
|
|
|
|
|
if (fmin > 0)
|
2024-03-14 18:45:08 +08:00
|
|
|
{
|
|
|
|
|
if (cpu->frequencyMin == cpu->frequencyMin)
|
|
|
|
|
cpu->frequencyMin = cpu->frequencyMin < fmin ? cpu->frequencyMin : fmin;
|
|
|
|
|
else
|
|
|
|
|
cpu->frequencyMin = fmin;
|
|
|
|
|
}
|
2024-05-19 18:23:18 +08:00
|
|
|
|
2024-05-21 09:09:08 +08:00
|
|
|
if (options->showPeCoreCount)
|
|
|
|
|
{
|
|
|
|
|
uint32_t freq = fbase == 0 ? fmax : fbase; // seems base frequencies are more stable
|
|
|
|
|
uint32_t ifreq = 0;
|
|
|
|
|
while (cpu->coreTypes[ifreq].freq != freq && cpu->coreTypes[ifreq].freq > 0)
|
|
|
|
|
++ifreq;
|
|
|
|
|
if (cpu->coreTypes[ifreq].freq == 0)
|
|
|
|
|
cpu->coreTypes[ifreq].freq = freq;
|
|
|
|
|
cpu->coreTypes[ifreq].count += getNumCores(&path, &buffer);
|
|
|
|
|
}
|
2024-02-29 10:20:50 +08:00
|
|
|
ffStrbufSubstrBefore(&path, baseLen);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-17 16:14:35 +08:00
|
|
|
cpu->frequencyBase /= 1e6;
|
|
|
|
|
cpu->frequencyMax /= 1e6;
|
|
|
|
|
cpu->frequencyMin /= 1e6;
|
2024-05-20 18:33:47 +08:00
|
|
|
cpu->frequencyBiosLimit /= 1e6;
|
2024-03-14 10:32:34 +08:00
|
|
|
return true;
|
2022-09-04 22:20:12 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-21 14:03:57 +08:00
|
|
|
static double detectCPUTemp(void)
|
2022-09-04 22:20:12 +02:00
|
|
|
{
|
2023-11-06 19:08:17 +08:00
|
|
|
const FFlist* tempsResult = ffDetectTemps();
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2023-11-06 19:08:17 +08: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;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-08 02:33:35 -06:00
|
|
|
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".
|
|
|
|
|
}
|
2023-10-22 23:09:43 -04:00
|
|
|
if(ffStrbufStartsWithS(cpuIsa, "mips"))
|
|
|
|
|
{
|
|
|
|
|
ffStrbufSubstrAfterLastC(cpuIsa, ' ');
|
|
|
|
|
}
|
2023-01-08 02:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
2024-01-31 13:28:18 +08:00
|
|
|
void detectAsahi(FFCPUResult* cpu)
|
|
|
|
|
{
|
|
|
|
|
// In Asahi Linux, reading /proc/device-tree/compatible gives
|
|
|
|
|
// information on the device model. It consists of 3 NUL terminated
|
|
|
|
|
// strings, the second of which gives the actual SoC model. But it
|
|
|
|
|
// is not the marketing name, i.e. for M2 there is "apple,t8112" in
|
|
|
|
|
// the compatible string.
|
|
|
|
|
if (cpu->name.length == 0 && ffStrbufEqualS(&cpu->vendor, "Apple"))
|
|
|
|
|
{
|
2024-01-31 14:36:00 +08:00
|
|
|
char content[32];
|
|
|
|
|
ssize_t length = ffReadFileData("/proc/device-tree/compatible", sizeof(content), content);
|
|
|
|
|
if (length <= 0) return;
|
2024-01-31 13:28:18 +08:00
|
|
|
|
2024-01-31 14:36:00 +08:00
|
|
|
// get the second NUL terminated string
|
|
|
|
|
char* modelName = memchr(content, '\0', (size_t) length) + 1;
|
|
|
|
|
if (modelName - content < length && ffStrStartsWith(modelName, "apple,t"))
|
2024-01-31 13:28:18 +08:00
|
|
|
{
|
2024-04-18 16:41:19 +08:00
|
|
|
uint32_t deviceId = (uint32_t) strtoul(modelName + strlen("apple,t"), NULL, 10);
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, ffCPUAppleCodeToName(deviceId));
|
2024-01-31 13:28:18 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
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;
|
2022-09-24 15:59:36 +02:00
|
|
|
|
2023-04-15 15:29:54 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY physicalCoresBuffer = ffStrbufCreate();
|
2024-03-14 20:40:40 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY cpuMHz = ffStrbufCreate();
|
2023-04-15 15:29:54 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY cpuIsa = ffStrbufCreate();
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY cpuUarch = ffStrbufCreate();
|
2023-01-08 02:33:35 -06:00
|
|
|
|
2024-03-14 20:40:40 +08:00
|
|
|
const char* error = parseCpuInfo(cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch);
|
2023-06-12 09:56:03 +08:00
|
|
|
if (error) return error;
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2022-12-28 17:18:08 +08:00
|
|
|
cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
|
|
|
|
cpu->coresOnline = (uint16_t) get_nprocs();
|
2023-12-26 13:40:41 +08:00
|
|
|
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical);
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2024-05-21 09:09:08 +08:00
|
|
|
if (!detectFrequency(cpu, options) || cpu->frequencyBase != cpu->frequencyBase)
|
2024-03-14 20:40:40 +08:00
|
|
|
cpu->frequencyBase = ffStrbufToDouble(&cpuMHz) / 1000;
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2023-01-08 02:33:35 -06: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
|
|
|
|
|
|
2024-01-31 13:28:18 +08:00
|
|
|
#if defined(__linux__) && defined(__aarch64__)
|
|
|
|
|
detectAsahi(cpu);
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-09-27 15:11:05 +08:00
|
|
|
if (cpu->name.length == 0)
|
|
|
|
|
{
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
2023-12-26 11:20:40 +08:00
|
|
|
if (ffProcessAppendStdOut(&buffer, (char *const[]) { "lscpu", NULL }) == NULL)
|
2023-09-27 15:11:05 +08:00
|
|
|
{
|
2023-12-26 11:20:40 +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;
|
2024-01-18 15:06:47 +08:00
|
|
|
if (pstart >= buffer.chars + buffer.length)
|
|
|
|
|
return NULL;
|
2023-12-26 13:32:55 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-13 19:08:38 +08:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pstart = buffer.chars;
|
|
|
|
|
}
|
2023-12-26 13:32:55 +08:00
|
|
|
}
|
|
|
|
|
|
2023-12-26 11:20:40 +08:00
|
|
|
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 == '-')
|
|
|
|
|
{
|
2024-01-18 15:16:46 +08:00
|
|
|
if (cpu->vendor.length > 0)
|
|
|
|
|
ffStrbufAppend(&cpu->name, &cpu->vendor);
|
|
|
|
|
else
|
|
|
|
|
ffStrbufAppendS(&cpu->name, "Unknown");
|
2023-12-26 13:32:55 +08:00
|
|
|
++pstart;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-26 11:20:40 +08:00
|
|
|
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;
|
2024-01-18 15:06:47 +08:00
|
|
|
if (pstart >= buffer.chars + buffer.length)
|
|
|
|
|
return NULL;
|
2023-12-26 11:20:40 +08:00
|
|
|
}
|
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
|
|
|
}
|