master ohmu/fastfetch-openbsd / src / detection / cpu / cpu_bsd.c
ohmu  ·  2026-10-15
  1#include "cpu.h"
  2#include "common/debug.h"
  3#include "common/sysctl.h"
  4#include "common/strutil.h"
  5
  6#include <errno.h>
  7#include <string.h>
  8#include <sys/param.h>
  9#if __has_include(<sys/cpuset.h>)
 10    #include <sys/cpuset.h>
 11    #define FF_HAVE_CPUSET 1
 12#endif
 13
 14static const char* detectCpuTemp(const FFCPUOptions* options, double* current) {
 15    int temp;
 16    if (options->tempSensor.length > 0) {
 17        temp = ffSysctlGetInt(options->tempSensor.chars, -999999);
 18        if (temp == -999999) {
 19            FF_DEBUG("sysctlbyname(%s) failed: %s", options->tempSensor.chars, strerror(errno));
 20            return "ffSysctlGetInt(options->tempSensor) failed";
 21        }
 22    } else {
 23        temp = ffSysctlGetInt("dev.cpu.0.temperature", -999999);
 24        if (temp == -999999) {
 25            // Thermal zone temperature
 26            temp = ffSysctlGetInt("hw.acpi.thermal.tz0.temperature", -999999);
 27            if (temp == -999999) {
 28                FF_DEBUG("Neither sysctlbyname(dev.cpu.0.temperature) nor sysctlbyname(hw.acpi.thermal.tz0.temperature) is readable: %s", strerror(errno));
 29                return "ffSysctlGetInt(\"dev.cpu.0.temperature\" or \"hw.acpi.thermal.tz0.temperature\") failed";
 30            }
 31        }
 32    }
 33
 34    // In tenth of degrees Kelvin
 35    *current = (double) temp / 10 - 273.15;
 36    return nullptr;
 37}
 38
 39const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
 40    const char* modelError = ffSysctlGetString("hw.model", &cpu->name);
 41    if (modelError != nullptr) {
 42        FF_DEBUG("sysctlbyname(hw.model) failed: %s", modelError);
 43        return "sysctlbyname(hw.model) failed";
 44    }
 45
 46    cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
 47    cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
 48    cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
 49
 50    FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
 51    if (ffSysctlGetString("kern.sched.topology_spec", &buffer) == nullptr && buffer.length > 0) {
 52        // <groups>
 53        //  <group level="1" cache-level="3">
 54        //   <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
 55        //   <children>
 56        //    <group level="2" cache-level="2">
 57        //     <cpu count="2" mask="3,0,0,0">0, 1</cpu>
 58        //     <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
 59        //    </group>
 60        //    <group level="2" cache-level="2">
 61        //     <cpu count="2" mask="c,0,0,0">2, 3</cpu>
 62        //     <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
 63        //    </group>
 64        //   </children>
 65        //  </group>
 66        // </groups>
 67        for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p) {
 68            cpu->packages++;
 69        }
 70    }
 71
 72#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
 73    // Bind current process to the first two cores, which is *usually* a performance core
 74    cpuset_t currentCPU;
 75    CPU_ZERO(&currentCPU);
 76    CPU_SET(1, &currentCPU);
 77    CPU_SET(2, &currentCPU);
 78    cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &currentCPU);
 79#endif
 80
 81    ffCPUDetectByCpuid(cpu);
 82
 83    uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
 84    if (clockrate > cpu->frequencyBase) {
 85        cpu->frequencyBase = clockrate;
 86    }
 87
 88    for (uint16_t i = 0; i < cpu->coresLogical; ++i) {
 89        ffStrbufClear(&buffer);
 90        char key[32];
 91        snprintf(key, sizeof(key), "dev.cpu.%u.freq_levels", i);
 92        if (ffSysctlGetString(key, &buffer) == nullptr) {
 93            if (buffer.length == 0) {
 94                continue;
 95            }
 96
 97            // MHz/Watts pairs like: 2501/32000 2187/27125 2000/24000
 98            uint32_t fmax = (uint32_t) strtoul(buffer.chars, nullptr, 10);
 99            if (cpu->frequencyMax < fmax) {
100                cpu->frequencyMax = fmax;
101            }
102        } else {
103            break;
104        }
105    }
106
107    cpu->temperature = FF_CPU_TEMP_UNSET;
108
109    if (options->temp) {
110        detectCpuTemp(options, &cpu->temperature);
111    }
112
113    cpu->numaNodes = (uint16_t) ffSysctlGetInt("vm.ndomains", 0);
114
115    return nullptr;
116}