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"
|
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>
|
2024-09-24 01:51:45 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
|
|
2025-02-07 10:02:26 +08:00
|
|
|
#define FF_CPUINFO_PATH "/proc/cpuinfo"
|
|
|
|
|
|
2024-09-24 01:51:45 +00:00
|
|
|
static double parseHwmonDir(FFstrbuf* dir, FFstrbuf* buffer)
|
|
|
|
|
{
|
|
|
|
|
//https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
|
|
|
|
|
uint32_t dirLength = dir->length;
|
|
|
|
|
ffStrbufAppendS(dir, "temp1_input");
|
|
|
|
|
|
|
|
|
|
if(!ffReadFileBuffer(dir->chars, buffer))
|
|
|
|
|
{
|
|
|
|
|
// Some badly implemented system put temp file in /hwmonN/device
|
|
|
|
|
ffStrbufSubstrBefore(dir, dirLength);
|
|
|
|
|
ffStrbufAppendS(dir, "device/");
|
|
|
|
|
dirLength = dir->length;
|
|
|
|
|
ffStrbufAppendS(dir, "temp1_input");
|
|
|
|
|
|
|
|
|
|
if(!ffReadFileBuffer(dir->chars, buffer))
|
|
|
|
|
return 0.0/0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffStrbufSubstrBefore(dir, dirLength);
|
|
|
|
|
|
|
|
|
|
double value = ffStrbufToDouble(buffer);// millidegree Celsius
|
|
|
|
|
|
|
|
|
|
if(value != value)
|
|
|
|
|
return 0.0/0.0;
|
|
|
|
|
|
|
|
|
|
ffStrbufAppendS(dir, "name");
|
|
|
|
|
if (!ffReadFileBuffer(dir->chars, buffer))
|
|
|
|
|
return 0.0/0.0;
|
|
|
|
|
|
|
|
|
|
ffStrbufTrimRightSpace(buffer);
|
|
|
|
|
|
|
|
|
|
if(
|
|
|
|
|
ffStrbufContainS(buffer, "cpu") ||
|
|
|
|
|
ffStrbufEqualS(buffer, "k10temp") || // AMD
|
2025-01-05 17:27:23 +08:00
|
|
|
ffStrbufEqualS(buffer, "fam15h_power") || // AMD
|
2024-09-24 01:51:45 +00:00
|
|
|
ffStrbufEqualS(buffer, "coretemp") // Intel
|
|
|
|
|
) return value / 1000.;
|
|
|
|
|
|
2024-10-01 19:43:58 -04:00
|
|
|
return 0.0/0.0;
|
2024-09-24 01:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-05 17:27:23 +08:00
|
|
|
static double detectTZTemp(FFstrbuf* buffer)
|
|
|
|
|
{
|
|
|
|
|
if (ffReadFileBuffer("/sys/class/thermal/thermal_zone0/temp", buffer))
|
|
|
|
|
return ffStrbufToDouble(buffer) / 1000.;
|
|
|
|
|
return 0.0/0.0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-24 01:51:45 +00:00
|
|
|
static double detectCPUTemp(void)
|
|
|
|
|
{
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
|
|
|
|
|
ffStrbufAppendS(&baseDir, "/sys/class/hwmon/");
|
|
|
|
|
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
|
|
|
|
|
|
|
|
|
uint32_t baseDirLength = baseDir.length;
|
|
|
|
|
|
|
|
|
|
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars);
|
|
|
|
|
if(dirp == NULL)
|
|
|
|
|
return 0.0/0.0;
|
|
|
|
|
|
|
|
|
|
struct dirent* entry;
|
|
|
|
|
while((entry = readdir(dirp)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
if(entry->d_name[0] == '.')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ffStrbufAppendS(&baseDir, entry->d_name);
|
|
|
|
|
ffStrbufAppendC(&baseDir, '/');
|
|
|
|
|
|
|
|
|
|
double result = parseHwmonDir(&baseDir, &buffer);
|
|
|
|
|
if (result == result)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
ffStrbufSubstrBefore(&baseDir, baseDirLength);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-05 17:27:23 +08:00
|
|
|
return detectTZTemp(&buffer);
|
2024-09-24 01:51:45 +00:00
|
|
|
}
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2023-07-27 19:35:55 +08:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
|
#include "common/settings.h"
|
|
|
|
|
|
2024-07-25 10:29:21 +08:00
|
|
|
static void detectQualcomm(FFCPUResult* cpu)
|
|
|
|
|
{
|
2024-09-06 14:01:56 +08:00
|
|
|
// https://en.wikipedia.org/wiki/List_of_Qualcomm_Snapdragon_systems_on_chips
|
|
|
|
|
|
2025-01-24 10:05:24 +08:00
|
|
|
if (ffStrbufEqualS(&cpu->name, "SM8750-AC"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite for Galaxy [SM8750-AC]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8750-3"))
|
2025-01-23 19:33:42 +08:00
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750-3]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8750"))
|
2024-10-31 09:33:23 +08:00
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8635"))
|
2024-07-25 10:29:21 +08:00
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8s Gen 3 [SM8635]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8650-AC"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 3 for Galaxy [SM8650-AC]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8650"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 3 [SM8650]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8550-AC"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 2 for Galaxy [SM8550-AC]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8550"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 2 [SM8550]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8475"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8+ Gen 1 [SM8475]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM8450"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 1 [SM8450]");
|
|
|
|
|
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM7675"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7+ Gen 3 [SM7675]");
|
2024-09-06 14:01:56 +08:00
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM7635"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7s Gen 3 [SM7635]");
|
2024-07-25 10:29:21 +08:00
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM7550"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7 Gen 3 [SM7550]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM7475"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7+ Gen 2 [SM7550]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM7435"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7s Gen 2 [SM7435]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM7450"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7 Gen 1 [SM7450]");
|
|
|
|
|
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM6375-AC"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6s Gen 3 [SM6375-AC]");
|
2024-09-06 14:01:56 +08:00
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM6475"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6 Gen 3 [SM6475]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM6115"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6s Gen 1 [SM6115]");
|
2024-07-25 10:29:21 +08:00
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM6450"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6 Gen 1 [SM6450]");
|
|
|
|
|
|
2024-07-31 08:57:53 +08:00
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM4635"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4s Gen 2 [SM4635]");
|
2024-07-25 10:29:21 +08:00
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM4450"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4 Gen 2 [SM4450]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "SM4375"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4 Gen 1 [SM4375]");
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 16:28:34 +08:00
|
|
|
static void detectMediaTek(FFCPUResult* cpu)
|
|
|
|
|
{
|
|
|
|
|
// https://en.wikipedia.org/wiki/List_of_MediaTek_systems_on_chips
|
|
|
|
|
|
|
|
|
|
if (ffStrbufEqualS(&cpu->name, "MT6991"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT6991Z"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991Z]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT6989Z"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT6989Z]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT8796Z"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT8796Z]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT6989"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT6989]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT8796"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT8796]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT6985W"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200+ [MT6985W]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT6985"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200 [MT6985]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT6983W"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT6983W]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/T"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT8798Z/T]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT6983Z"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT6983Z]");
|
|
|
|
|
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/C"))
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT8798Z/C]");
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 19:35:55 +08:00
|
|
|
static void detectAndroid(FFCPUResult* cpu)
|
|
|
|
|
{
|
|
|
|
|
if (cpu->name.length == 0)
|
2024-03-17 19:11:55 +08:00
|
|
|
{
|
2024-07-25 10:48:42 +08:00
|
|
|
if (ffSettingsGetAndroidProperty("ro.soc.model", &cpu->name))
|
|
|
|
|
ffStrbufClear(&cpu->vendor); // We usually detect the vendor of CPU core as ARM, but instead we want the vendor of SOC
|
|
|
|
|
else if(ffSettingsGetAndroidProperty("ro.mediatek.platform", &cpu->name))
|
|
|
|
|
ffStrbufSetStatic(&cpu->vendor, "MTK");
|
2024-03-17 19:11:55 +08:00
|
|
|
}
|
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);
|
|
|
|
|
}
|
2024-07-25 10:29:21 +08:00
|
|
|
|
|
|
|
|
if (ffStrbufEqualS(&cpu->vendor, "QTI") && ffStrbufStartsWithS(&cpu->name, "SM"))
|
|
|
|
|
detectQualcomm(cpu);
|
2025-01-07 16:28:34 +08:00
|
|
|
else if (ffStrbufEqualS(&cpu->vendor, "MTK") && ffStrbufStartsWithS(&cpu->name, "MT"))
|
|
|
|
|
detectMediaTek(cpu);
|
2023-07-27 19:35:55 +08:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-08-15 15:24:13 +08:00
|
|
|
#if __arm__ || __aarch64__
|
2024-08-12 10:19:18 +08:00
|
|
|
#include "cpu_arm.h"
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2024-11-26 14:47:02 +08:00
|
|
|
static void detectArmName(FFstrbuf* cpuinfo, FFCPUResult* cpu, uint32_t implId)
|
2024-08-12 10:19:18 +08:00
|
|
|
{
|
2024-11-26 14:47:02 +08:00
|
|
|
char* line = NULL;
|
2022-09-04 22:20:12 +02:00
|
|
|
size_t len = 0;
|
2024-08-15 14:43:00 +08:00
|
|
|
uint32_t lastPartId = UINT32_MAX;
|
2024-08-12 10:19:18 +08:00
|
|
|
uint32_t num = 0;
|
2024-11-26 14:47:02 +08:00
|
|
|
while(ffStrbufGetline(&line, &len, cpuinfo))
|
2024-08-12 10:19:18 +08:00
|
|
|
{
|
|
|
|
|
if (!ffStrStartsWith(line, "CPU part\t: ")) continue;
|
|
|
|
|
uint32_t partId = (uint32_t) strtoul(line + strlen("CPU part\t: "), NULL, 16);
|
|
|
|
|
const char* name = NULL;
|
2024-12-13 15:28:59 +08:00
|
|
|
switch (implId)
|
2024-08-12 10:19:18 +08:00
|
|
|
{
|
2024-12-13 15:28:59 +08:00
|
|
|
case 0x41: name = armPartId2name(partId); break;
|
|
|
|
|
case 0x42: name = brcmPartId2name(partId); break;
|
|
|
|
|
case 0x43: name = caviumPartId2name(partId); break;
|
|
|
|
|
case 0x44: name = decPartId2name(partId); break;
|
|
|
|
|
case 0x46: name = fujitsuPartId2name(partId); break;
|
|
|
|
|
case 0x48: name = hisiPartId2name(partId); break;
|
|
|
|
|
case 0x4e: name = nvidiaPartId2name(partId); break;
|
|
|
|
|
case 0x50: name = apmPartId2name(partId); break;
|
|
|
|
|
case 0x51: name = qcomPartId2name(partId); break;
|
|
|
|
|
case 0x53: name = samsungPartId2name(partId); break;
|
|
|
|
|
case 0x56: name = marvellPartId2name(partId); break;
|
|
|
|
|
case 0x61:
|
|
|
|
|
if (partId == 0)
|
|
|
|
|
{
|
|
|
|
|
// https://github.com/Dr-Noob/cpufetch/issues/213#issuecomment-1927782105
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, "Virtualized Apple Silicon");
|
2025-01-06 10:57:29 +08:00
|
|
|
ffStrbufGetlineRestore(&line, &len, cpuinfo);
|
2024-12-13 15:28:59 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
name = applePartId2name(partId);
|
|
|
|
|
break;
|
|
|
|
|
case 0x66: name = faradayPartId2name(partId); break;
|
|
|
|
|
case 0x69: name = intelPartId2name(partId); break;
|
|
|
|
|
case 0x6d: name = msPartId2name(partId); break;
|
|
|
|
|
case 0x70: name = ftPartId2name(partId); break;
|
|
|
|
|
case 0xc0: name = amperePartId2name(partId); break;
|
2024-08-12 10:19:18 +08:00
|
|
|
}
|
2024-08-15 14:43:00 +08:00
|
|
|
if (lastPartId != partId)
|
2024-08-12 10:19:18 +08:00
|
|
|
{
|
2024-08-15 14:43:00 +08:00
|
|
|
if (lastPartId != UINT32_MAX)
|
2024-08-12 10:19:18 +08:00
|
|
|
{
|
|
|
|
|
if (num > 1)
|
|
|
|
|
ffStrbufAppendF(&cpu->name, "*%u", num);
|
|
|
|
|
ffStrbufAppendS(&cpu->name, " + ");
|
|
|
|
|
}
|
2024-08-15 14:43:00 +08:00
|
|
|
if (name)
|
|
|
|
|
ffStrbufAppendS(&cpu->name, name);
|
|
|
|
|
else if (partId)
|
|
|
|
|
ffStrbufAppendF(&cpu->name, "%s-%X", cpu->vendor.chars, partId);
|
|
|
|
|
else
|
|
|
|
|
ffStrbufAppend(&cpu->name, &cpu->vendor);
|
|
|
|
|
lastPartId = partId;
|
2024-08-12 10:19:18 +08:00
|
|
|
num = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
++num;
|
|
|
|
|
}
|
|
|
|
|
if (num > 1)
|
|
|
|
|
ffStrbufAppendF(&cpu->name, "*%u", num);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2024-08-21 16:42:40 +08:00
|
|
|
static const char* parseCpuInfo(
|
2024-11-26 14:47:02 +08:00
|
|
|
FFstrbuf* cpuinfo,
|
|
|
|
|
FFCPUResult* cpu,
|
2024-08-22 09:16:20 +08:00
|
|
|
FF_MAYBE_UNUSED FFstrbuf* physicalCoresBuffer,
|
|
|
|
|
FF_MAYBE_UNUSED FFstrbuf* cpuMHz,
|
2024-08-21 16:42:40 +08:00
|
|
|
FF_MAYBE_UNUSED FFstrbuf* cpuIsa,
|
|
|
|
|
FF_MAYBE_UNUSED FFstrbuf* cpuUarch,
|
|
|
|
|
FF_MAYBE_UNUSED FFstrbuf* cpuImplementer)
|
2024-08-12 10:19:18 +08:00
|
|
|
{
|
2024-11-26 14:47:02 +08:00
|
|
|
char* line = NULL;
|
2024-08-12 10:19:18 +08:00
|
|
|
size_t len = 0;
|
2024-01-31 13:28:18 +08:00
|
|
|
|
2024-11-26 14:47:02 +08:00
|
|
|
while(ffStrbufGetline(&line, &len, cpuinfo))
|
2022-09-04 22:20:12 +02:00
|
|
|
{
|
2024-08-21 15:46:12 +08:00
|
|
|
//Stop after reasonable information is acquired
|
2025-01-27 13:06:08 +08:00
|
|
|
if((*line == '\0' || *line == '\n') && cpu->name.length > 0)
|
2025-01-06 10:57:29 +08:00
|
|
|
{
|
|
|
|
|
ffStrbufGetlineRestore(&line, &len, cpuinfo);
|
2022-09-04 22:20:12 +02:00
|
|
|
break;
|
2025-01-06 10:57:29 +08:00
|
|
|
}
|
2022-09-04 22:20:12 +02:00
|
|
|
|
|
|
|
|
(void)(
|
2024-08-22 09:16:20 +08:00
|
|
|
// arm64 doesn't have "model name"; arm32 does have "model name" but its value is not useful.
|
|
|
|
|
// "Hardware" should always be used in this case
|
2025-01-27 13:06:08 +08:00
|
|
|
#if __x86_64__ || __i386__
|
2024-08-22 09:16:20 +08:00
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
|
|
|
|
|
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) ||
|
|
|
|
|
(physicalCoresBuffer->length == 0 && ffParsePropLine(line, "cpu cores :", physicalCoresBuffer)) ||
|
|
|
|
|
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) ||
|
2025-02-05 16:10:01 +08:00
|
|
|
#elif __arm__ || __aarch64__
|
2024-08-21 15:46:12 +08:00
|
|
|
(cpuImplementer->length == 0 && ffParsePropLine(line, "CPU implementer :", cpuImplementer)) ||
|
2023-07-12 11:38:56 +02:00
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "Hardware :", &cpu->name)) || //For Android devices
|
2025-02-05 16:10:01 +08:00
|
|
|
#elif __powerpc__ || __powerpc
|
2025-02-08 10:38:13 +08:00
|
|
|
(cpuMHz->length == 0 && ffParsePropLine(line, "clock :", cpuMHz)) ||
|
|
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "cpu :", &cpu->name)) ||
|
2025-02-05 16:10:01 +08:00
|
|
|
#elif __mips__ || __mips
|
2025-02-08 10:38:13 +08:00
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "cpu model :", &cpu->name)) ||
|
2025-02-05 16:10:01 +08:00
|
|
|
#elif __loongarch__
|
2025-01-27 13:06:08 +08:00
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "Model Name :", &cpu->name)) ||
|
|
|
|
|
(cpuMHz->length == 0 && ffParsePropLine(line, "CPU MHz :", cpuMHz)) ||
|
2025-02-05 16:10:01 +08:00
|
|
|
#elif __riscv__ || __riscv
|
2025-01-27 13:06:08 +08:00
|
|
|
(cpuIsa->length == 0 && ffParsePropLine(line, "isa :", cpuIsa)) ||
|
|
|
|
|
(cpuUarch->length == 0 && ffParsePropLine(line, "uarch :", cpuUarch)) ||
|
2025-02-08 10:31:06 +08:00
|
|
|
#elif __s390x__
|
|
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "processor 0:", &cpu->name)) ||
|
|
|
|
|
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) ||
|
|
|
|
|
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz static :", cpuMHz)) || // This one cannot be detected because of early return
|
2025-02-05 16:10:01 +08:00
|
|
|
#else
|
|
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
|
2025-02-08 10:38:13 +08:00
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "model :", &cpu->name)) ||
|
|
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "cpu model :", &cpu->name)) ||
|
|
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "hardware :", &cpu->name)) ||
|
|
|
|
|
(cpu->name.length == 0 && ffParsePropLine(line, "processor :", &cpu->name)) ||
|
2025-01-27 13:06:08 +08:00
|
|
|
#endif
|
|
|
|
|
|
2024-08-12 10:19:18 +08:00
|
|
|
false
|
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
|
|
|
}
|
|
|
|
|
|
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-07-17 10:56:30 +08:00
|
|
|
return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000);
|
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-07-17 10:56:30 +08:00
|
|
|
return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000);
|
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)
|
2024-06-05 16:03:10 +08:00
|
|
|
return (uint8_t) (ffStrbufCountC(buffer, ' ') + 1);
|
2024-05-17 16:14:35 +08:00
|
|
|
|
|
|
|
|
ffStrbufAppendS(basePath, "/related_cpus");
|
|
|
|
|
ok = ffReadFileBuffer(basePath->chars, buffer);
|
|
|
|
|
ffStrbufSubstrBefore(basePath, baseLen);
|
|
|
|
|
if (ok)
|
2024-06-05 16:03:10 +08:00
|
|
|
return (uint8_t) (ffStrbufCountC(buffer, ' ') + 1);
|
2024-05-17 16:14:35 +08:00
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2024-05-28 15:34:59 +08:00
|
|
|
if (ffStrStartsWith(entry->d_name, "policy") && ffCharIsDigit(entry->d_name[strlen("policy")]))
|
2024-02-29 10:20:50 +08:00
|
|
|
{
|
|
|
|
|
ffStrbufAppendS(&path, entry->d_name);
|
2024-09-28 16:49:03 +08:00
|
|
|
|
|
|
|
|
uint32_t fmax = getFrequency(&path, "/cpuinfo_max_freq", "/scaling_max_freq", &buffer);
|
|
|
|
|
if (fmax == 0) continue;
|
|
|
|
|
|
|
|
|
|
if (cpu->frequencyMax >= fmax)
|
|
|
|
|
{
|
|
|
|
|
if (!options->showPeCoreCount)
|
|
|
|
|
{
|
|
|
|
|
ffStrbufSubstrBefore(&path, baseLen);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cpu->frequencyMax = fmax;
|
|
|
|
|
|
2024-05-17 16:14:35 +08:00
|
|
|
uint32_t fbase = getFrequency(&path, "/base_frequency", NULL, &buffer);
|
|
|
|
|
if (fbase > 0)
|
2024-07-17 10:56:30 +08:00
|
|
|
cpu->frequencyBase = cpu->frequencyBase > fbase ? cpu->frequencyBase : fbase;
|
|
|
|
|
|
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-03-14 10:32:34 +08:00
|
|
|
return true;
|
2022-09-04 22:20:12 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-27 13:06:08 +08:00
|
|
|
#if __i386__ || __x86_64__
|
|
|
|
|
|
|
|
|
|
FF_MAYBE_UNUSED static uint16_t getPackageCount(FFstrbuf* cpuinfo)
|
|
|
|
|
{
|
|
|
|
|
const char* p = cpuinfo->chars;
|
|
|
|
|
uint64_t low = 0, high = 0;
|
|
|
|
|
|
|
|
|
|
while ((p = memmem(p, cpuinfo->length - (uint32_t) (p - cpuinfo->chars), "\nphysical id\t:", strlen("\nphysical id\t:"))))
|
|
|
|
|
{
|
|
|
|
|
if (!p) break;
|
|
|
|
|
p += strlen("\nphysical id\t:");
|
|
|
|
|
char* pend;
|
|
|
|
|
unsigned long id = strtoul(p, &pend, 10);
|
|
|
|
|
if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist?
|
|
|
|
|
high |= 1 << (id - 64);
|
|
|
|
|
else
|
|
|
|
|
low |= 1 << id;
|
|
|
|
|
p = pend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFCPUResult* cpu)
|
|
|
|
|
{
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY cpuinfo = ffStrbufCreateA(PROC_FILE_BUFFSIZ);
|
2025-02-07 10:02:26 +08:00
|
|
|
if (!ffReadFileBuffer(FF_CPUINFO_PATH, &cpuinfo) || cpuinfo.length == 0)
|
|
|
|
|
return "ffReadFileBuffer(\"" FF_CPUINFO_PATH "\") failed";
|
2025-01-27 13:06:08 +08:00
|
|
|
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY physicalCoresBuffer = ffStrbufCreate();
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY cpuMHz = ffStrbufCreate();
|
|
|
|
|
const char* error = parseCpuInfo(&cpuinfo, cpu, &physicalCoresBuffer, &cpuMHz, NULL,NULL, NULL);
|
|
|
|
|
if (error) return error;
|
|
|
|
|
|
|
|
|
|
cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
|
|
|
|
cpu->coresOnline = (uint16_t) get_nprocs();
|
|
|
|
|
cpu->packages = getPackageCount(&cpuinfo);
|
|
|
|
|
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, 0); // physical cores in single package
|
|
|
|
|
if (cpu->coresPhysical == 0)
|
|
|
|
|
cpu->coresPhysical = cpu->coresLogical;
|
|
|
|
|
else if (cpu->packages > 1)
|
|
|
|
|
cpu->coresPhysical *= cpu->packages;
|
|
|
|
|
|
|
|
|
|
// Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252
|
|
|
|
|
ffCPUDetectSpeedByCpuid(cpu);
|
|
|
|
|
if (!detectFrequency(cpu, options) || cpu->frequencyBase == 0)
|
|
|
|
|
cpu->frequencyBase = (uint32_t) ffStrbufToUInt(&cpuMHz, 0);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
2024-08-21 16:42:40 +08:00
|
|
|
FF_MAYBE_UNUSED static void parseIsa(FFstrbuf* cpuIsa)
|
2023-01-08 02:33:35 -06:00
|
|
|
{
|
2024-08-22 09:16:20 +08:00
|
|
|
// Always use the last part of the ISA string. Ref: #590 #1204
|
|
|
|
|
ffStrbufSubstrAfterLastC(cpuIsa, ' ');
|
|
|
|
|
|
2023-01-08 02:33:35 -06:00
|
|
|
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".
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-22 22:19:23 +08:00
|
|
|
FF_MAYBE_UNUSED static void detectSocName(FFCPUResult* cpu)
|
2024-01-31 13:28:18 +08:00
|
|
|
{
|
2024-09-09 20:48:19 +08:00
|
|
|
if (cpu->name.length > 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-09-10 09:10:03 +08:00
|
|
|
// device-vendor,device-model\0soc-vendor,soc-model\0
|
2024-09-30 15:03:25 +08:00
|
|
|
char content[256];
|
2024-10-18 16:15:48 +08:00
|
|
|
ssize_t length = ffReadFileData("/proc/device-tree/compatible", ARRAY_SIZE(content), content);
|
2024-09-09 20:48:19 +08:00
|
|
|
if (length <= 2) return;
|
|
|
|
|
|
2024-09-30 15:03:25 +08:00
|
|
|
// get the second NUL terminated string if it exists
|
|
|
|
|
char* vendor = memchr(content, '\0', (size_t) length) + 1;
|
|
|
|
|
if (!vendor || vendor - content >= length) vendor = content;
|
2024-01-31 13:28:18 +08:00
|
|
|
|
2024-09-30 15:03:25 +08:00
|
|
|
char* model = strchr(vendor, ',');
|
|
|
|
|
if (!model) return;
|
|
|
|
|
*model = '\0';
|
|
|
|
|
++model;
|
|
|
|
|
|
|
|
|
|
if (false) {}
|
|
|
|
|
#if __aarch64__
|
|
|
|
|
else if (ffStrEquals(vendor, "apple"))
|
2024-09-09 20:48:19 +08:00
|
|
|
{
|
2024-09-30 15:03:25 +08:00
|
|
|
// https://elixir.bootlin.com/linux/v6.11/source/arch/arm64/boot/dts/apple
|
|
|
|
|
if (model[0] == 't')
|
2024-09-09 20:48:19 +08:00
|
|
|
{
|
2024-09-30 15:03:25 +08:00
|
|
|
uint32_t deviceId = (uint32_t) strtoul(model + 1, NULL, 10);
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, ffCPUAppleCodeToName(deviceId));
|
|
|
|
|
|
|
|
|
|
if (!cpu->name.length)
|
|
|
|
|
{
|
|
|
|
|
ffStrbufSetS(&cpu->name, "Apple Silicon ");
|
|
|
|
|
ffStrbufAppendS(&cpu->name, model);
|
|
|
|
|
}
|
2024-09-09 20:48:19 +08:00
|
|
|
}
|
2024-09-30 15:03:25 +08:00
|
|
|
else
|
|
|
|
|
ffStrbufSetS(&cpu->name, model);
|
|
|
|
|
|
|
|
|
|
ffStrbufSetStatic(&cpu->vendor, "Apple");
|
2024-09-09 20:48:19 +08:00
|
|
|
}
|
2024-09-30 15:03:25 +08:00
|
|
|
#endif
|
|
|
|
|
else if (ffStrEquals(vendor, "qcom"))
|
2024-09-09 20:48:19 +08:00
|
|
|
{
|
2024-09-30 15:03:25 +08:00
|
|
|
// https://elixir.bootlin.com/linux/v6.11/source/arch/arm64/boot/dts/qcom
|
|
|
|
|
if (ffStrStartsWith(model, "x"))
|
2024-09-09 20:48:19 +08:00
|
|
|
{
|
|
|
|
|
ffStrbufSetS(&cpu->name, "Qualcomm Snapdragon X Elite ");
|
2024-09-30 15:03:25 +08:00
|
|
|
for (const char* p = model + 1; *p; ++p)
|
2024-09-09 20:48:19 +08:00
|
|
|
ffStrbufAppendC(&cpu->name, (char) toupper(*p));
|
|
|
|
|
}
|
2024-09-30 15:03:25 +08:00
|
|
|
else if (ffStrStartsWith(model, "sc"))
|
2024-01-31 13:28:18 +08:00
|
|
|
{
|
2024-09-30 15:03:25 +08:00
|
|
|
const char* code = model + 2;
|
2024-09-09 20:48:19 +08:00
|
|
|
uint32_t deviceId = (uint32_t) strtoul(code, NULL, 10);
|
|
|
|
|
ffStrbufSetStatic(&cpu->name, ffCPUQualcommCodeToName(deviceId));
|
|
|
|
|
if (!cpu->name.length)
|
|
|
|
|
{
|
|
|
|
|
ffStrbufAppendS(&cpu->name, "Qualcomm Snapdragon SC");
|
|
|
|
|
ffStrbufAppendS(&cpu->name, code);
|
|
|
|
|
}
|
2024-01-31 13:28:18 +08:00
|
|
|
}
|
2024-09-30 15:03:25 +08:00
|
|
|
else
|
|
|
|
|
ffStrbufSetS(&cpu->name, model);
|
|
|
|
|
|
|
|
|
|
ffStrbufSetStatic(&cpu->vendor, "Qualcomm");
|
|
|
|
|
}
|
|
|
|
|
else if (ffStrEquals(vendor, "brcm"))
|
|
|
|
|
{
|
|
|
|
|
// Raspberry Pi
|
|
|
|
|
ffStrbufSetStatic(&cpu->vendor, "Broadcom");
|
|
|
|
|
for (const char* p = model; *p; ++p)
|
|
|
|
|
ffStrbufAppendC(&cpu->name, (char) toupper(*p));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ffStrbufSetS(&cpu->name, model);
|
|
|
|
|
ffStrbufSetS(&cpu->vendor, vendor);
|
|
|
|
|
cpu->vendor.chars[0] = (char) toupper(vendor[0]);
|
2024-01-31 13:28:18 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-07 10:02:26 +08:00
|
|
|
#ifdef __loongarch__
|
|
|
|
|
FF_MAYBE_UNUSED static uint16_t getLoongarchPropCount(FFstrbuf* cpuinfo, const char* key)
|
|
|
|
|
{
|
|
|
|
|
const char* p = cpuinfo->chars;
|
|
|
|
|
uint64_t low = 0, high = 0;
|
|
|
|
|
uint32_t keylen = (uint32_t) strlen(key);
|
|
|
|
|
|
|
|
|
|
while ((p = memmem(p, cpuinfo->length - (uint32_t) (p - cpuinfo->chars), key, keylen)))
|
|
|
|
|
{
|
|
|
|
|
if (!p) break;
|
|
|
|
|
p += keylen;
|
|
|
|
|
char* pend;
|
|
|
|
|
unsigned long id = strtoul(p, &pend, 10);
|
|
|
|
|
if (__builtin_expect(id > 64, false))
|
|
|
|
|
high |= 1 << (id - 64);
|
|
|
|
|
else
|
|
|
|
|
low |= 1 << id;
|
|
|
|
|
p = pend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-01-27 13:06:08 +08:00
|
|
|
FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options, FFCPUResult* cpu)
|
2022-09-04 22:20:12 +02:00
|
|
|
{
|
2025-01-27 13:06:08 +08:00
|
|
|
cpu->coresPhysical = cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
2022-12-28 17:18:08 +08:00
|
|
|
cpu->coresOnline = (uint16_t) get_nprocs();
|
2022-09-04 22:20:12 +02:00
|
|
|
|
2025-01-22 22:19:23 +08:00
|
|
|
#if __ANDROID__
|
|
|
|
|
detectAndroid(cpu);
|
2025-01-27 13:06:08 +08:00
|
|
|
#else
|
2025-01-22 22:19:23 +08:00
|
|
|
detectSocName(cpu);
|
2024-08-21 16:42:40 +08:00
|
|
|
#endif
|
2023-06-12 09:56:03 +08:00
|
|
|
|
2025-01-27 13:06:08 +08:00
|
|
|
detectFrequency(cpu, options);
|
2024-08-12 10:19:18 +08:00
|
|
|
|
2025-01-22 22:19:23 +08:00
|
|
|
if (cpu->name.length == 0)
|
|
|
|
|
{
|
2025-01-27 13:06:08 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY cpuinfo = ffStrbufCreateA(PROC_FILE_BUFFSIZ);
|
2025-02-07 10:02:26 +08:00
|
|
|
if (!ffReadFileBuffer(FF_CPUINFO_PATH, &cpuinfo) || cpuinfo.length == 0)
|
|
|
|
|
return "ffReadFileBuffer(\"" FF_CPUINFO_PATH "\") failed";
|
2025-01-27 13:06:08 +08:00
|
|
|
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY cpuMHz = ffStrbufCreate();
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY cpuIsa = ffStrbufCreate();
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY cpuUarch = ffStrbufCreate();
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY cpuImplementerStr = ffStrbufCreate();
|
|
|
|
|
|
|
|
|
|
const char* error = parseCpuInfo(&cpuinfo, cpu, NULL, &cpuMHz, &cpuIsa, &cpuUarch, &cpuImplementerStr);
|
|
|
|
|
if (error) return error;
|
|
|
|
|
|
|
|
|
|
if (cpu->frequencyBase == 0)
|
|
|
|
|
cpu->frequencyBase = (uint32_t) ffStrbufToUInt(&cpuMHz, 0);
|
|
|
|
|
|
|
|
|
|
#if __arm__ || __aarch64__
|
|
|
|
|
uint32_t cpuImplementer = (uint32_t) strtoul(cpuImplementerStr.chars, NULL, 16);
|
|
|
|
|
ffStrbufSetStatic(&cpu->vendor, hwImplId2Vendor(cpuImplementer));
|
2025-01-22 22:19:23 +08:00
|
|
|
|
2025-01-27 13:06:08 +08:00
|
|
|
if (cpu->name.length == 0)
|
|
|
|
|
detectArmName(&cpuinfo, cpu, cpuImplementer);
|
|
|
|
|
#elif __riscv__ || __riscv
|
|
|
|
|
if (cpu->name.length == 0)
|
2025-01-22 22:19:23 +08:00
|
|
|
{
|
2025-01-27 13:06:08 +08: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);
|
|
|
|
|
}
|
2025-01-22 22:19:23 +08:00
|
|
|
}
|
2025-02-07 10:02:26 +08:00
|
|
|
#elif __loongarch__
|
|
|
|
|
cpu->packages = getLoongarchPropCount(&cpuinfo, "\npackage\t\t\t:");
|
|
|
|
|
cpu->coresPhysical = getLoongarchPropCount(&cpuinfo, "\ncore\t\t\t:");
|
|
|
|
|
if (cpu->packages > 1) cpu->coresPhysical *= cpu->packages;
|
2025-02-08 10:31:06 +08:00
|
|
|
#elif __s390x__
|
|
|
|
|
if (ffStrbufSubstrAfterFirstS(&cpu->name, "machine = "))
|
|
|
|
|
ffStrbufPrependS(&cpu->name, "Machine ");
|
2025-01-27 13:06:08 +08:00
|
|
|
#endif
|
2025-01-22 22:19:23 +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
|
|
|
}
|
2025-01-27 13:06:08 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
|
|
|
|
{
|
|
|
|
|
cpu->temperature = options->temp ? detectCPUTemp() : FF_CPU_TEMP_UNSET;
|
|
|
|
|
|
|
|
|
|
#if __x86_64__ || __i386__
|
|
|
|
|
return detectCPUX86(options, cpu);
|
|
|
|
|
#else
|
|
|
|
|
return detectCPUOthers(options, cpu);
|
|
|
|
|
#endif
|
|
|
|
|
}
|