#include "cpu.h" #include "common/sysctl.h" #include "common/strutil.h" #include #if __has_include() #include #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) { // // // 0, 1, 2, 3 // // // 0, 1 // THREAD groupSMT group // // // 2, 3 // THREAD groupSMT group // // // // for (char* p = buffer.chars; (p = strstr(p, "\n \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(¤tCPU); CPU_SET(1, ¤tCPU); CPU_SET(2, ¤tCPU); cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), ¤tCPU); #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; }