mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:14:37 +02:00
CPU (Linux): refactor; fix cpu count detection
This commit is contained in:
@@ -159,14 +159,13 @@ static void detectAndroid(FFCPUResult* cpu)
|
||||
#if __arm__ || __aarch64__
|
||||
#include "cpu_arm.h"
|
||||
|
||||
static void detectArmName(FILE* cpuinfo, FFCPUResult* cpu, uint32_t implId)
|
||||
static void detectArmName(FFstrbuf* cpuinfo, FFCPUResult* cpu, uint32_t implId)
|
||||
{
|
||||
FF_AUTO_FREE char* line = NULL;
|
||||
rewind(cpuinfo);
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
uint32_t lastPartId = UINT32_MAX;
|
||||
uint32_t num = 0;
|
||||
while(getline(&line, &len, cpuinfo) != -1)
|
||||
while(ffStrbufGetline(&line, &len, cpuinfo))
|
||||
{
|
||||
if (!ffStrStartsWith(line, "CPU part\t: ")) continue;
|
||||
uint32_t partId = (uint32_t) strtoul(line + strlen("CPU part\t: "), NULL, 16);
|
||||
@@ -220,19 +219,18 @@ static void detectArmName(FILE* cpuinfo, FFCPUResult* cpu, uint32_t implId)
|
||||
#endif
|
||||
|
||||
static const char* parseCpuInfo(
|
||||
FF_MAYBE_UNUSED FILE* cpuinfo,
|
||||
FF_MAYBE_UNUSED FFCPUResult* cpu,
|
||||
FF_MAYBE_UNUSED FFstrbuf* cpuPhysicalId,
|
||||
FFstrbuf* cpuinfo,
|
||||
FFCPUResult* cpu,
|
||||
FF_MAYBE_UNUSED FFstrbuf* physicalCoresBuffer,
|
||||
FF_MAYBE_UNUSED FFstrbuf* cpuMHz,
|
||||
FF_MAYBE_UNUSED FFstrbuf* cpuIsa,
|
||||
FF_MAYBE_UNUSED FFstrbuf* cpuUarch,
|
||||
FF_MAYBE_UNUSED FFstrbuf* cpuImplementer)
|
||||
{
|
||||
FF_AUTO_FREE char* line = NULL;
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
while(getline(&line, &len, cpuinfo) != -1)
|
||||
while(ffStrbufGetline(&line, &len, cpuinfo))
|
||||
{
|
||||
//Stop after reasonable information is acquired
|
||||
if((*line == '\0' || *line == '\n')
|
||||
@@ -248,9 +246,6 @@ static const char* parseCpuInfo(
|
||||
#if !(__arm__ || __aarch64__)
|
||||
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
|
||||
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) ||
|
||||
//Is it cheaper to just parse every physical id or to check if it's already set to the parsed value?
|
||||
(cpuPhysicalId->length == 0 && ffParsePropLine(line, "physical id:", cpuPhysicalId)) ||
|
||||
(cpuPhysicalId->length > 0 && ffParsePropLine(line, "physical id:", cpuPhysicalId)) ||
|
||||
(physicalCoresBuffer->length == 0 && ffParsePropLine(line, "cpu cores :", physicalCoresBuffer)) ||
|
||||
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) ||
|
||||
#endif
|
||||
@@ -469,28 +464,45 @@ FF_MAYBE_UNUSED static void detectArmSoc(FFCPUResult* cpu)
|
||||
}
|
||||
}
|
||||
|
||||
FF_MAYBE_UNUSED static uint16_t getCPUCount(FFstrbuf* cpuinfo)
|
||||
{
|
||||
const char* p = cpuinfo->chars;
|
||||
uint64_t bits = 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;
|
||||
uint32_t id = (uint32_t) strtoul(p, &pend, 10);
|
||||
p = pend;
|
||||
bits |= 1 << id;
|
||||
}
|
||||
|
||||
return (uint16_t) __builtin_popcountll(bits);
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
FF_AUTO_CLOSE_FILE FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
|
||||
if(cpuinfo == NULL)
|
||||
return "fopen(\"/proc/cpuinfo\", \"r\") failed";
|
||||
FF_STRBUF_AUTO_DESTROY cpuinfo = ffStrbufCreateA(PROC_FILE_BUFFSIZ);
|
||||
if (!ffReadFileBuffer("/proc/cpuinfo", &cpuinfo) || cpuinfo.length == 0)
|
||||
return "ffReadFileBuffer(\"/proc/cpuinfo\") failed";
|
||||
|
||||
cpu->temperature = options->temp ? detectCPUTemp() : FF_CPU_TEMP_UNSET;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cpuPhysicalId= ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY physicalCoresBuffer = ffStrbufCreate();
|
||||
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, &cpuPhysicalId, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch, &cpuImplementerStr);
|
||||
const char* error = parseCpuInfo(&cpuinfo, cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch, &cpuImplementerStr);
|
||||
if (error) return error;
|
||||
|
||||
cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
||||
cpu->coresOnline = (uint16_t) get_nprocs();
|
||||
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical);
|
||||
cpu->cpuCount = (uint16_t) ffStrbufToUInt(&cpuPhysicalId, 1) +1; //Assuming at least 1 CPU is present otherwise we wouldn't get this far
|
||||
cpu->cpuCount = getCPUCount(&cpuinfo);
|
||||
|
||||
// Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
@@ -525,7 +537,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
#endif
|
||||
|
||||
if (cpu->name.length == 0)
|
||||
detectArmName(cpuinfo, cpu, cpuImplementer);
|
||||
detectArmName(&cpuinfo, cpu, cpuImplementer);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -531,3 +531,47 @@ void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c)
|
||||
memset(&strbuf->chars[index], c, num);
|
||||
strbuf->length += num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a line from a FFstrbuf.
|
||||
*
|
||||
* @details Behaves like getline(3) but reads from a FFstrbuf.
|
||||
*
|
||||
* @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line.
|
||||
* Can be NULL for the first call.
|
||||
* @param[in,out] n The pointer to the size of the buffer of lineptr.
|
||||
* @param[in] buffer The buffer to read from. The buffer must not be a string literal.
|
||||
*
|
||||
* @return true if a line has been read, false if the end of the buffer has been reached.
|
||||
*/
|
||||
bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
{
|
||||
assert(lineptr && n && buffer);
|
||||
assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0));
|
||||
assert(!*lineptr || (*lineptr >= buffer->chars && *lineptr <= buffer->chars + buffer->length));
|
||||
|
||||
const char* pBufferEnd = buffer->chars + buffer->length;
|
||||
if (!*lineptr)
|
||||
*lineptr = buffer->chars;
|
||||
else
|
||||
{
|
||||
*lineptr += *n;
|
||||
if (*lineptr >= pBufferEnd) // non-empty last line
|
||||
return false;
|
||||
**lineptr = '\n';
|
||||
++*lineptr;
|
||||
}
|
||||
if (*lineptr >= pBufferEnd) // empty last line
|
||||
return false;
|
||||
|
||||
size_t remaining = (size_t) (pBufferEnd - *lineptr);
|
||||
char* ending = memchr(*lineptr, '\n', remaining);
|
||||
if (ending)
|
||||
{
|
||||
*n = (size_t) (ending - *lineptr);
|
||||
*ending = '\0';
|
||||
}
|
||||
else
|
||||
*n = remaining;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultV
|
||||
void ffStrbufUpperCase(FFstrbuf* strbuf);
|
||||
void ffStrbufLowerCase(FFstrbuf* strbuf);
|
||||
|
||||
bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer);
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
|
||||
{
|
||||
FFstrbuf strbuf;
|
||||
|
||||
+107
@@ -458,6 +458,113 @@ int main(void)
|
||||
VERIFY(strbuf2.allocated == 32);
|
||||
}
|
||||
|
||||
{
|
||||
int i = 0;
|
||||
char* lineptr = NULL;
|
||||
size_t n = 0;
|
||||
const char* text = "Processor\t: ARMv7\nprocessor\t: 0\nBogoMIPS\t: 38.00\n\nprocessor\t: 1\nBogoMIPS\t: 38.00";
|
||||
ffStrbufSetS(&strbuf, text);
|
||||
|
||||
while (ffStrbufGetline(&lineptr, &n, &strbuf))
|
||||
{
|
||||
++i;
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
VERIFY(strcmp(lineptr, "Processor\t: ARMv7") == 0);
|
||||
VERIFY(n == strlen("Processor\t: ARMv7"));
|
||||
break;
|
||||
case 2:
|
||||
VERIFY(strcmp(lineptr, "processor\t: 0") == 0);
|
||||
VERIFY(n == strlen("processor\t: 0"));
|
||||
break;
|
||||
case 3:
|
||||
VERIFY(strcmp(lineptr, "BogoMIPS\t: 38.00") == 0);
|
||||
VERIFY(n == strlen("BogoMIPS\t: 38.00"));
|
||||
break;
|
||||
case 4:
|
||||
VERIFY(strcmp(lineptr, "") == 0);
|
||||
VERIFY(n == 0);
|
||||
break;
|
||||
case 5:
|
||||
VERIFY(strcmp(lineptr, "processor\t: 1") == 0);
|
||||
VERIFY(n == strlen("processor\t: 1"));
|
||||
break;
|
||||
case 6:
|
||||
VERIFY(strcmp(lineptr, "BogoMIPS\t: 38.00") == 0);
|
||||
VERIFY(n == strlen("BogoMIPS\t: 38.00"));
|
||||
break;
|
||||
default:
|
||||
VERIFY(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
VERIFY(ffStrbufEqualS(&strbuf, text));
|
||||
VERIFY(*lineptr == '\0');
|
||||
VERIFY(i == 6);
|
||||
|
||||
lineptr = NULL;
|
||||
n = 0;
|
||||
i = 0;
|
||||
text = "\n";
|
||||
ffStrbufSetS(&strbuf, text);
|
||||
while (ffStrbufGetline(&lineptr, &n, &strbuf))
|
||||
{
|
||||
++i;
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
VERIFY(strcmp(lineptr, "") == 0);
|
||||
VERIFY(n == 0);
|
||||
break;
|
||||
default:
|
||||
VERIFY(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
VERIFY(ffStrbufEqualS(&strbuf, text));
|
||||
VERIFY(*lineptr == '\0');
|
||||
VERIFY(i == 1);
|
||||
|
||||
lineptr = NULL;
|
||||
n = 0;
|
||||
i = 0;
|
||||
text = "abcd";
|
||||
ffStrbufSetS(&strbuf, text);
|
||||
while (ffStrbufGetline(&lineptr, &n, &strbuf))
|
||||
{
|
||||
++i;
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
VERIFY(strcmp(lineptr, "abcd") == 0);
|
||||
VERIFY(n == strlen("abcd"));
|
||||
break;
|
||||
default:
|
||||
VERIFY(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
VERIFY(ffStrbufEqualS(&strbuf, text));
|
||||
VERIFY(*lineptr == '\0');
|
||||
VERIFY(i == 1);
|
||||
|
||||
lineptr = NULL;
|
||||
n = 0;
|
||||
i = 0;
|
||||
text = "";
|
||||
ffStrbufSetS(&strbuf, text);
|
||||
while (ffStrbufGetline(&lineptr, &n, &strbuf))
|
||||
{
|
||||
++i;
|
||||
VERIFY(false);
|
||||
}
|
||||
|
||||
VERIFY(ffStrbufEqualS(&strbuf, text));
|
||||
VERIFY(*lineptr == '\0');
|
||||
VERIFY(i == 0);
|
||||
}
|
||||
|
||||
//Success
|
||||
puts("\e[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user