Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,8 @@ endif()
###################

if (BUILD_TESTS)
add_executable(fastfetch-test-cpu-riscv tests/cpu-riscv.c)
target_link_libraries(fastfetch-test-cpu-riscv PRIVATE libfastfetch)
add_executable(fastfetch-test-strbuf
tests/strbuf.c
)
Expand Down Expand Up @@ -2173,6 +2175,7 @@ if (BUILD_TESTS)
)

enable_testing()
add_test(NAME test-cpu-riscv COMMAND fastfetch-test-cpu-riscv)
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
add_test(NAME test-list COMMAND fastfetch-test-list)
add_test(NAME test-format COMMAND fastfetch-test-format)
Expand Down
15 changes: 15 additions & 0 deletions src/detection/cpu/cpu_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

#define FF_CPUINFO_PATH "/proc/cpuinfo"

#if __riscv__ || __riscv
#include "cpu_riscv.h"
#endif

static double readTempFile(int dfd, const char* filename, FFstrbuf* buffer) {
if (filename ? !ffReadFileBufferRelative(dfd, filename, buffer) : !ffReadFDBuffer(dfd, buffer)) {
return FF_CPU_TEMP_UNSET;
Expand Down Expand Up @@ -1047,6 +1051,17 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) {

detectFrequency(cpu, options);

#if __riscv__ || __riscv
// A detected SoC name must not hide a heterogeneous core topology.
// Frequency-based core counts can merge distinct uarchs on RISC-V.
{
FF_STRBUF_AUTO_DESTROY cpuinfo = ffStrbufCreateA(PROC_FILE_BUFFSIZ);
if (ffReadFileBuffer(FF_CPUINFO_PATH, &cpuinfo)) {
ffCPUDetectRiscvUarch(&cpuinfo, cpu->coresOnline, &cpu->name);
}
}
#endif

if (cpu->name.length == 0) {
FF_STRBUF_AUTO_DESTROY cpuinfo = ffStrbufCreateA(PROC_FILE_BUFFSIZ);
if (!ffReadFileBuffer(FF_CPUINFO_PATH, &cpuinfo) || cpuinfo.length == 0) {
Expand Down
79 changes: 79 additions & 0 deletions src/detection/cpu/cpu_riscv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#pragma once

#include "common/properties.h"

// Unlike frequency-based core grouping, uarch also distinguishes different
// implementations running at the same frequency. Keep the kernel's names:
// a microarchitecture name alone does not establish a P/E classification.
static bool ffCPUDetectRiscvUarch(FFstrbuf* cpuinfo, uint16_t coresOnline, FFstrbuf* name) {
typedef struct UarchCount {
FFstrbuf name;
uint32_t count;
} UarchCount;

FF_LIST_AUTO_DESTROY groups = ffListCreate();
FF_STRBUF_AUTO_DESTROY value = ffStrbufCreate();
uint32_t processors = 0;
uint32_t descriptions = 0;
bool haveUarch = false;
bool valid = true;
char* line = NULL;
size_t length = 0;

while (ffStrbufGetline(&line, &length, cpuinfo)) {
ffStrbufClear(&value);
if (ffParsePropLine(line, "processor :", &value)) {
if (processors > 0 && !haveUarch) {
valid = false;
}
++processors;
haveUarch = false;
} else if (ffParsePropLine(line, "uarch :", &value)) {
if (processors == 0 || haveUarch || value.length == 0) {
valid = false;
continue;
}
haveUarch = true;
++descriptions;

UarchCount* group = NULL;
FF_LIST_FOR_EACH (UarchCount, candidate, groups) {
if (ffStrbufEqual(&candidate->name, &value)) {
group = candidate;
break;
}
}
if (!group) {
group = FF_LIST_ADD(UarchCount, groups);
ffStrbufInitCopy(&group->name, &value);
group->count = 0;
}
++group->count;
}
}

// /proc/cpuinfo describes online CPUs. Do not publish a partial breakdown
// if descriptions are missing or CPU hotplug changed the snapshot.
bool heterogeneous = valid && haveUarch && groups.length > 1 &&
processors == coresOnline && descriptions == coresOnline;
if (heterogeneous) {
bool haveSocName = name->length > 0;
if (haveSocName) {
ffStrbufAppendS(name, " (");
}
FF_LIST_FOR_EACH (UarchCount, group, groups) {
if (group != ffListGet(&groups, sizeof(UarchCount), 0)) {
ffStrbufAppendS(name, " + ");
}
ffStrbufAppendF(name, "%u x %s", group->count, group->name.chars);
}
if (haveSocName) {
ffStrbufAppendC(name, ')');
}
}

FF_LIST_FOR_EACH (UarchCount, group, groups) {
ffStrbufDestroy(&group->name);
}
return heterogeneous;
}
42 changes: 42 additions & 0 deletions tests/cpu-riscv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "detection/cpu/cpu_riscv.h"

#include <stdlib.h>

static void verify(const char* input, uint16_t online, const char* soc, const char* expected, bool changed) {
FF_STRBUF_AUTO_DESTROY cpuinfo = ffStrbufCreateS(input);
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateS(soc);
bool result = ffCPUDetectRiscvUarch(&cpuinfo, online, &name);
if (result != changed || !ffStrbufEqualS(&name, expected) || !ffStrbufEqualS(&cpuinfo, input)) {
fprintf(stderr, "Expected '%s' (%d), got '%s' (%d)\n", expected, changed, name.chars, result);
exit(1);
}
}

int main(void) {
// Interleaved IDs must be grouped by uarch, not adjacency or frequency.
const char* mixed =
"processor\t: 0\nuarch\t: thead,c908\n\n"
"processor\t: 4\nuarch\t: thead,c920\n\n"
"processor\t: 1\nuarch\t: thead,c908\n\n"
"processor\t: 5\nuarch\t: thead,c920\n\n"
"processor\t: 2\nuarch\t: thead,c908\n\n"
"processor\t: 6\nuarch\t: thead,c920\n\n"
"processor\t: 3\nuarch\t: thead,c908\n\n"
"processor\t: 7\nuarch\t: thead,c920\n";
verify(mixed, 8, "a210", "a210 (4 x thead,c908 + 4 x thead,c920)", true);
verify(mixed, 8, "", "4 x thead,c908 + 4 x thead,c920", true);
verify(mixed, 7, "a210", "a210", false);
verify("processor : 0\nuarch : vendor,small\n\nprocessor : 7\nuarch : vendor,large",
2, "SoC", "SoC (1 x vendor,small + 1 x vendor,large)", true);
verify("processor : 0\nuarch : thead,c908\n\nprocessor : 1\nuarch : thead,c908\n",
2, "SoC", "SoC", false);
verify("processor : 0\nisa : rv64imafdc\n", 1, "SoC", "SoC", false);
verify("processor : 0\nuarch : vendor,a\n\nprocessor : 1\n\nprocessor : 2\nuarch : vendor,b\n",
3, "SoC", "SoC", false);
verify("processor : 0\nuarch : vendor,a\nuarch : vendor,b\n",
1, "SoC", "SoC", false);
verify("processor : 0\nuarch : \n", 1, "SoC", "SoC", false);
verify("", 0, "SoC", "SoC", false);
puts("RISC-V uarch tests passed");
return 0;
}