summaryrefslogtreecommitdiffstats
path: root/src/detection/cpu/cpu_bsd.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/cpu/cpu_bsd.c
Add the files
Diffstat (limited to 'src/detection/cpu/cpu_bsd.c')
-rw-r--r--src/detection/cpu/cpu_bsd.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/detection/cpu/cpu_bsd.c b/src/detection/cpu/cpu_bsd.c
new file mode 100644
index 0000000..4cca30e
--- /dev/null
+++ b/src/detection/cpu/cpu_bsd.c
@@ -0,0 +1,109 @@
+#include "cpu.h"
+#include "common/sysctl.h"
+#include "common/strutil.h"
+
+#include <sys/param.h>
+#if __has_include(<sys/cpuset.h>)
+ #include <sys/cpuset.h>
+ #define FF_HAVE_CPUSET 1
+#endif
+
+static const char* detectCpuTemp(const FFCPUOptions* options, double* current) {
+ int temp;
+ if (options->tempSensor.length > 0) {
+ temp = ffSysctlGetInt(options->tempSensor.chars, -999999);
+ if (temp == -999999) {
+ return "ffSysctlGetInt(options->tempSensor) failed";
+ }
+ } else {
+ temp = ffSysctlGetInt("dev.cpu.0.temperature", -999999);
+ if (temp == -999999) {
+ // Thermal zone temperature
+ temp = ffSysctlGetInt("hw.acpi.thermal.tz0.temperature", -999999);
+ if (temp == -999999) {
+ return "ffSysctlGetInt(\"dev.cpu.0.temperature\" or \"hw.acpi.thermal.tz0.temperature\") failed";
+ }
+ }
+ }
+
+ // In tenth of degrees Kelvin
+ *current = (double) temp / 10 - 273.15;
+ return NULL;
+}
+
+const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
+ if (ffSysctlGetString("hw.model", &cpu->name) != NULL) {
+ return "sysctlbyname(hw.model) failed";
+ }
+
+ cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
+ cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
+ cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
+
+ FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
+ if (ffSysctlGetString("kern.sched.topology_spec", &buffer) == NULL && buffer.length > 0) {
+ // <groups>
+ // <group level="1" cache-level="3">
+ // <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
+ // <children>
+ // <group level="2" cache-level="2">
+ // <cpu count="2" mask="3,0,0,0">0, 1</cpu>
+ // <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
+ // </group>
+ // <group level="2" cache-level="2">
+ // <cpu count="2" mask="c,0,0,0">2, 3</cpu>
+ // <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
+ // </group>
+ // </children>
+ // </group>
+ // </groups>
+ for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p) {
+ cpu->packages++;
+ }
+ }
+
+#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
+ // Bind current process to the first two cores, which is *usually* a performance core
+ cpuset_t currentCPU;
+ CPU_ZERO(&currentCPU);
+ CPU_SET(1, &currentCPU);
+ CPU_SET(2, &currentCPU);
+ cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &currentCPU);
+#endif
+
+ ffCPUDetectByCpuid(cpu);
+
+ uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
+ if (clockrate > cpu->frequencyBase) {
+ cpu->frequencyBase = clockrate;
+ }
+
+ for (uint16_t i = 0; i < cpu->coresLogical; ++i) {
+ ffStrbufClear(&buffer);
+ char key[32];
+ snprintf(key, sizeof(key), "dev.cpu.%u.freq_levels", i);
+ if (ffSysctlGetString(key, &buffer) == NULL) {
+ if (buffer.length == 0) {
+ continue;
+ }
+
+ // MHz/Watts pairs like: 2501/32000 2187/27125 2000/24000
+ uint32_t fmax = (uint32_t) strtoul(buffer.chars, NULL, 10);
+ if (cpu->frequencyMax < fmax) {
+ cpu->frequencyMax = fmax;
+ }
+ } else {
+ break;
+ }
+ }
+
+ cpu->temperature = FF_CPU_TEMP_UNSET;
+
+ if (options->temp) {
+ detectCpuTemp(options, &cpu->temperature);
+ }
+
+ cpu->numaNodes = (uint16_t) ffSysctlGetInt("vm.ndomains", 0);
+
+ return NULL;
+}