From d282050130f61008a2f6f13dcd13248263477d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 17 Jul 2024 10:56:30 +0800 Subject: [PATCH] CPU: support display frequency in MHz --- doc/json_schema.json | 4 +- src/common/parsing.c | 12 ++++++ src/common/parsing.h | 1 + src/data/help.json | 2 +- src/detection/cpu/cpu.h | 6 +-- src/detection/cpu/cpu_apple.c | 10 ++--- src/detection/cpu/cpu_bsd.c | 12 +++--- src/detection/cpu/cpu_linux.c | 34 +++++------------ src/detection/cpu/cpu_sunos.c | 2 +- src/detection/cpu/cpu_windows.c | 14 +++---- src/modules/cpu/cpu.c | 68 ++++++++++++++++----------------- src/modules/cpu/option.h | 2 +- src/modules/loadavg/loadavg.c | 6 +-- 13 files changed, 84 insertions(+), 89 deletions(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index 3de8047d9..00e60af19 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1104,9 +1104,9 @@ "$ref": "#/$defs/temperature" }, "freqNdigits": { - "description": "Set the number of digits to keep after the decimal point when printing CPU frequency", + "description": "Set the number of digits to keep after the decimal point when printing frequency in GHz, or MHz if set to -1", "type": "integer", - "minimum": 0, + "minimum": -1, "maximum": 9, "default": 2 }, diff --git a/src/common/parsing.c b/src/common/parsing.c index 0d1aaba54..1a050aec5 100644 --- a/src/common/parsing.c +++ b/src/common/parsing.c @@ -96,6 +96,18 @@ void ffParseSize(uint64_t bytes, FFstrbuf* result) } } +bool ffParseFrequency(uint32_t mhz, FFstrbuf* result, int8_t freqNdigits) +{ + if (mhz == 0) + return false; + + if (freqNdigits >= 0) + ffStrbufAppendF(result, "%.*f GHz", freqNdigits, mhz / 1000.); + else + ffStrbufAppendF(result, "%u MHz", (unsigned) mhz); + return true; +} + void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4) { if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0) diff --git a/src/common/parsing.h b/src/common/parsing.h index f295c74cc..823d8b2ee 100644 --- a/src/common/parsing.h +++ b/src/common/parsing.h @@ -26,3 +26,4 @@ void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty); int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2); void ffParseSize(uint64_t bytes, FFstrbuf* result); +bool ffParseFrequency(uint32_t mhz, FFstrbuf* result, int8_t freqNdigits); diff --git a/src/data/help.json b/src/data/help.json index 5b1a8b848..c195ce23a 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1179,7 +1179,7 @@ }, { "long": "cpu-freq-ndigits", - "desc": "Set the number of digits to keep after the decimal point when printing CPU frequency", + "desc": "Set the number of digits to keep after the decimal point when printing CPU frequency in GHz", "arg": { "type": "num", "default": 2 diff --git a/src/detection/cpu/cpu.h b/src/detection/cpu/cpu.h index c37fc1997..e27a437af 100644 --- a/src/detection/cpu/cpu.h +++ b/src/detection/cpu/cpu.h @@ -19,9 +19,9 @@ typedef struct FFCPUResult uint16_t coresLogical; uint16_t coresOnline; - double frequencyBase; // GHz - double frequencyMax; // GHz - double frequencyBiosLimit; // GHz + uint32_t frequencyBase; // GHz + uint32_t frequencyMax; // GHz + uint32_t frequencyBiosLimit; // GHz FFCPUCore coreTypes[16]; // number of P cores, E cores, etc. diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index 398c0ca9e..20ef4a023 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -56,21 +56,21 @@ static const char* detectFrequency(FFCPUResult* cpu) pMax = pMax > pStart[i] ? pMax : pStart[i]; if (pMax > 0) - cpu->frequencyMax = pMax / 1000.0 / 1000.0 / 1000.0; + cpu->frequencyMax = pMax / 1000 / 1000; return NULL; } #else static const char* detectFrequency(FFCPUResult* cpu) { - cpu->frequencyBase = ffSysctlGetInt64("hw.cpufrequency", 0) / 1000.0 / 1000.0 / 1000.0; - cpu->frequencyMax = ffSysctlGetInt64("hw.cpufrequency_max", 0) / 1000.0 / 1000.0 / 1000.0; - if(cpu->frequencyBase != cpu->frequencyBase) + cpu->frequencyBase = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency", 0) / 1000 / 1000); + cpu->frequencyMax = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency_max", 0) / 1000 / 1000); + if(cpu->frequencyBase == 0) { unsigned current = 0; size_t size = sizeof(current); if (sysctl((int[]){ CTL_HW, HW_CPU_FREQ }, 2, ¤t, &size, NULL, 0) == 0) - cpu->frequencyBase = (double) current / 1000.0 / 1000.0 / 1000.0; + cpu->frequencyBase = (uint32_t) (current / 1000 / 1000); } return NULL; } diff --git a/src/detection/cpu/cpu_bsd.c b/src/detection/cpu/cpu_bsd.c index 710963a1f..92773dcdc 100644 --- a/src/detection/cpu/cpu_bsd.c +++ b/src/detection/cpu/cpu_bsd.c @@ -44,11 +44,13 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) ffStrbufClear(&buffer); char key[32]; snprintf(key, sizeof(key), "dev.cpu.%u.freq_levels", i); - if (ffSysctlGetString(key, &buffer) == NULL && buffer.length > 0) + 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; + if (cpu->frequencyMax < fmax) cpu->frequencyMax = fmax; if (options->showPeCoreCount) { @@ -60,11 +62,11 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) cpu->coreTypes[ifreq].count++; } } + else + break; } - cpu->frequencyMax /= 1000; - int clockRate = ffSysctlGetInt("hw.clockrate", 0); - cpu->frequencyBase = clockRate <= 0 ? 0.0/0.0 : clockRate / 1000.0; + cpu->frequencyBase = (uint32_t) ffSysctlGetInt("hw.clockrate", 0); cpu->temperature = FF_CPU_TEMP_UNSET; if (options->temp) diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 2886fd2ff..36f6e1e9d 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -94,7 +94,7 @@ static uint32_t getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, co bool ok = ffReadFileBuffer(basePath->chars, buffer); ffStrbufSubstrBefore(basePath, baseLen); if (ok) - return (uint32_t) ffStrbufToUInt(buffer, 0); + return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000); if (scalingFileName) { @@ -102,7 +102,7 @@ static uint32_t getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, co ok = ffReadFileBuffer(basePath->chars, buffer); ffStrbufSubstrBefore(basePath, baseLen); if (ok) - return (uint32_t) ffStrbufToUInt(buffer, 0); + return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000); } return 0; @@ -143,28 +143,15 @@ static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options) ffStrbufAppendS(&path, entry->d_name); uint32_t fbase = getFrequency(&path, "/base_frequency", NULL, &buffer); if (fbase > 0) - { - if (cpu->frequencyBase == cpu->frequencyBase) - cpu->frequencyBase = cpu->frequencyBase > fbase ? cpu->frequencyBase : fbase; - else - cpu->frequencyBase = fbase; - } + cpu->frequencyBase = cpu->frequencyBase > fbase ? cpu->frequencyBase : fbase; + uint32_t fbioslimit = getFrequency(&path, "/bios_limit", NULL, &buffer); if (fbioslimit > 0) - { - if (cpu->frequencyBiosLimit == cpu->frequencyBiosLimit) - cpu->frequencyBiosLimit = cpu->frequencyBiosLimit > fbioslimit ? cpu->frequencyBiosLimit : fbioslimit; - else - cpu->frequencyBiosLimit = fbioslimit; - } + cpu->frequencyBiosLimit = cpu->frequencyBiosLimit > fbioslimit ? cpu->frequencyBiosLimit : fbioslimit; + uint32_t fmax = getFrequency(&path, "/cpuinfo_max_freq", "/scaling_max_freq", &buffer); if (fmax > 0) - { - if (cpu->frequencyMax == cpu->frequencyMax) - cpu->frequencyMax = cpu->frequencyMax > fmax ? cpu->frequencyMax : fmax; - else - cpu->frequencyMax = fmax; - } + cpu->frequencyMax = cpu->frequencyMax > fmax ? cpu->frequencyMax : fmax; if (options->showPeCoreCount) { @@ -179,9 +166,6 @@ static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options) ffStrbufSubstrBefore(&path, baseLen); } } - cpu->frequencyBase /= 1e6; - cpu->frequencyMax /= 1e6; - cpu->frequencyBiosLimit /= 1e6; return true; } @@ -263,8 +247,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) cpu->coresOnline = (uint16_t) get_nprocs(); cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical); - if (!detectFrequency(cpu, options) || cpu->frequencyBase != cpu->frequencyBase) - cpu->frequencyBase = ffStrbufToDouble(&cpuMHz) / 1000; + if (!detectFrequency(cpu, options) || cpu->frequencyBase == 0) + cpu->frequencyBase = (uint32_t) ffStrbufToUInt(&cpuMHz, 0); if(cpuUarch.length > 0) { diff --git a/src/detection/cpu/cpu_sunos.c b/src/detection/cpu/cpu_sunos.c index 4d66c69ab..67954ee30 100644 --- a/src/detection/cpu/cpu_sunos.c +++ b/src/detection/cpu/cpu_sunos.c @@ -31,7 +31,7 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe } { kstat_named_t* kn = kstat_data_lookup(ks, "clock_MHz"); - cpu->frequencyBase = kn->value.ui32 / 1000.; + cpu->frequencyBase = kn->value.ui32; } ks = kstat_lookup(kc, "unix", -1, "system_misc"); diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 1e6ca5ff6..fa96bb6ff 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -65,8 +65,8 @@ inline static const char* detectSpeedByCpuid(FFCPUResult* cpu) return "Unsupported instruction"; // cpuid returns 0 MHz when hyper-v is enabled - if (base) cpu->frequencyBase = base / 1000.0; - if (max) cpu->frequencyMax = max / 1000.0; + if (base) cpu->frequencyBase = base; + if (max) cpu->frequencyMax = max; return NULL; } @@ -97,7 +97,7 @@ static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) return "No active CPU is found in SMBIOS data"; } - double speed = data->MaxSpeed / 1000.0; + uint32_t speed = data->MaxSpeed; // Sometimes SMBIOS reports invalid value. We assume that max speed is small than 2x of base if (speed < cpu->frequencyBase || speed > cpu->frequencyBase * 2) return "Possible invalid CPU max speed in SMBIOS data. See #800"; @@ -159,7 +159,7 @@ static const char* detectByRegistry(FFCPUResult* cpu) uint32_t mhz; if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL)) - cpu->frequencyBase = mhz / 1000.0; + cpu->frequencyBase = mhz; return NULL; } @@ -180,8 +180,8 @@ static const char* detectCoreTypes(FFCPUResult* cpu) ++cpu->coreTypes[ifreq].count; } - if (cpu->frequencyBase != cpu->frequencyBase) - cpu->frequencyBase = pinfo->MaxMhz / 1000.0; + if (cpu->frequencyBase == 0) + cpu->frequencyBase = pinfo->MaxMhz; return NULL; } @@ -196,7 +196,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) detectSpeedByCpuid(cpu); if (options->showPeCoreCount) detectCoreTypes(cpu); - if (cpu->frequencyMax != cpu->frequencyMax) + if (cpu->frequencyMax == 0) detectMaxSpeedBySmbios(cpu); if(options->temp) diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index 20607ba84..ebe6f297a 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -17,9 +17,9 @@ void ffPrintCPU(FFCPUOptions* options) { FFCPUResult cpu = { .temperature = FF_CPU_TEMP_UNSET, - .frequencyMax = 0.0/0.0, - .frequencyBase = 0.0/0.0, - .frequencyBiosLimit = 0.0/0.0, + .frequencyMax = 0, + .frequencyBase = 0, + .frequencyBiosLimit = 0, .name = ffStrbufCreate(), .vendor = ffStrbufCreate(), }; @@ -71,13 +71,16 @@ void ffPrintCPU(FFCPUOptions* options) else if(cpu.coresOnline > 1) ffStrbufAppendF(&str, " (%u)", cpu.coresOnline); - double freq = cpu.frequencyBiosLimit; - if(!(freq > 0.0000001)) + uint32_t freq = cpu.frequencyBiosLimit; + if(freq == 0) freq = cpu.frequencyMax; - if(!(freq > 0.0000001)) + if(freq == 0) freq = cpu.frequencyBase; - if(freq > 0.0000001) - ffStrbufAppendF(&str, " @ %.*f GHz", options->freqNdigits, freq); + if(freq > 0) + { + ffStrbufAppendS(&str, " @ "); + ffParseFrequency(freq, &str, options->freqNdigits); + } if(cpu.temperature == cpu.temperature) //FF_CPU_TEMP_UNSET { @@ -89,19 +92,12 @@ void ffPrintCPU(FFCPUOptions* options) } else { - char freqBase[32], freqMax[32], freqBioslimit[32]; - if (cpu.frequencyBase > 0) - snprintf(freqBase, sizeof(freqBase), "%.*f", options->freqNdigits, cpu.frequencyBase); - else - freqBase[0] = 0; - if (cpu.frequencyMax > 0) - snprintf(freqMax, sizeof(freqMax), "%.*f", options->freqNdigits, cpu.frequencyMax); - else - freqMax[0] = 0; - if (cpu.frequencyBiosLimit > 0) - snprintf(freqBioslimit, sizeof(freqBioslimit), "%.*f", options->freqNdigits, cpu.frequencyBiosLimit); - else - freqBioslimit[0] = 0; + FF_STRBUF_AUTO_DESTROY freqBase = ffStrbufCreate(); + ffParseFrequency(cpu.frequencyBase, &freqBase, options->freqNdigits); + FF_STRBUF_AUTO_DESTROY freqMax = ffStrbufCreate(); + ffParseFrequency(cpu.frequencyBase, &freqBase, options->freqNdigits); + FF_STRBUF_AUTO_DESTROY freqBioslimit = ffStrbufCreate(); + ffParseFrequency(cpu.frequencyBiosLimit, &freqBioslimit, options->freqNdigits); FF_STRBUF_AUTO_DESTROY tempStr = ffStrbufCreate(); ffTempsAppendNum(cpu.temperature, &tempStr, options->tempConfig, &options->moduleArgs); @@ -111,11 +107,11 @@ void ffPrintCPU(FFCPUOptions* options) {FF_FORMAT_ARG_TYPE_UINT16, &cpu.coresPhysical, "cores-physical"}, {FF_FORMAT_ARG_TYPE_UINT16, &cpu.coresLogical, "cores-logical"}, {FF_FORMAT_ARG_TYPE_UINT16, &cpu.coresOnline, "cores-online"}, - {FF_FORMAT_ARG_TYPE_STRING, freqBase, "freq-base"}, - {FF_FORMAT_ARG_TYPE_STRING, freqMax, "freq-max"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &freqBase, "freq-base"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &freqMax, "freq-max"}, {FF_FORMAT_ARG_TYPE_STRBUF, &tempStr, "temperature"}, {FF_FORMAT_ARG_TYPE_STRBUF, &coreTypes, "core-types"}, - {FF_FORMAT_ARG_TYPE_STRING, freqBioslimit, "freq-bios-limit"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &freqBioslimit, "freq-bios-limit"}, })); } } @@ -136,7 +132,7 @@ bool ffParseCPUCommandOptions(FFCPUOptions* options, const char* key, const char if (ffStrEqualsIgnCase(subKey, "freq-ndigits")) { - options->freqNdigits = (uint8_t) ffOptionParseUInt32(key, value); + options->freqNdigits = (int8_t) ffOptionParseInt32(key, value); return true; } @@ -167,7 +163,7 @@ void ffParseCPUJsonObject(FFCPUOptions* options, yyjson_val* module) if (ffStrEqualsIgnCase(key, "freqNdigits")) { - options->freqNdigits = (uint8_t) yyjson_get_uint(val); + options->freqNdigits = (int8_t) yyjson_get_int(val); continue; } @@ -191,7 +187,7 @@ void ffGenerateCPUJsonConfig(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ ffTempsGenerateJsonConfig(doc, module, defaultOptions.temp, defaultOptions.tempConfig, options->temp, options->tempConfig); if (defaultOptions.freqNdigits != options->freqNdigits) - yyjson_mut_obj_add_uint(doc, module, "freqNdigits", options->freqNdigits); + yyjson_mut_obj_add_int(doc, module, "freqNdigits", options->freqNdigits); if (defaultOptions.showPeCoreCount != options->showPeCoreCount) yyjson_mut_obj_add_bool(doc, module, "showPeCoreCount", options->showPeCoreCount); @@ -201,9 +197,9 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ { FFCPUResult cpu = { .temperature = FF_CPU_TEMP_UNSET, - .frequencyMax = 0.0/0.0, - .frequencyBase = 0.0/0.0, - .frequencyBiosLimit = 0.0/0.0, + .frequencyMax = 0, + .frequencyBase = 0, + .frequencyBiosLimit = 0, .name = ffStrbufCreate(), .vendor = ffStrbufCreate(), }; @@ -230,9 +226,9 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ yyjson_mut_obj_add_uint(doc, cores, "online", cpu.coresOnline); yyjson_mut_val* frequency = yyjson_mut_obj_add_obj(doc, obj, "frequency"); - yyjson_mut_obj_add_real(doc, frequency, "base", cpu.frequencyBase); - yyjson_mut_obj_add_real(doc, frequency, "max", cpu.frequencyMax); - yyjson_mut_obj_add_real(doc, frequency, "biosLimit", cpu.frequencyBiosLimit); + yyjson_mut_obj_add_uint(doc, frequency, "base", cpu.frequencyBase); + yyjson_mut_obj_add_uint(doc, frequency, "max", cpu.frequencyMax); + yyjson_mut_obj_add_uint(doc, frequency, "biosLimit", cpu.frequencyBiosLimit); yyjson_mut_val* coreTypes = yyjson_mut_obj_add_arr(doc, obj, "coreTypes"); for (uint32_t i = 0; i < sizeof (cpu.coreTypes) / sizeof (cpu.coreTypes[0]) && cpu.coreTypes[i].count > 0; i++) @@ -257,11 +253,11 @@ void ffPrintCPUHelpFormat(void) "Physical core count - cores-physical", "Logical core count - cores-logical", "Online core count - cores-online", - "Base frequency - freq-base", - "Max frequency - freq-max", + "Base frequency (formatted) - freq-base", + "Max frequency (formatted) - freq-max", "Temperature (formatted) - temperature", "Logical core count grouped by frequency - core-types", - "Bios limited frequency - freq-bios-limit", + "Bios limited frequency (formatted) - freq-bios-limit", })); } diff --git a/src/modules/cpu/option.h b/src/modules/cpu/option.h index fc2c6d174..ff3cfd42f 100644 --- a/src/modules/cpu/option.h +++ b/src/modules/cpu/option.h @@ -11,6 +11,6 @@ typedef struct FFCPUOptions bool temp; FFColorRangeConfig tempConfig; - uint8_t freqNdigits; + int8_t freqNdigits; bool showPeCoreCount; } FFCPUOptions; diff --git a/src/modules/loadavg/loadavg.c b/src/modules/loadavg/loadavg.c index 0fb9e73de..5d7de3582 100644 --- a/src/modules/loadavg/loadavg.c +++ b/src/modules/loadavg/loadavg.c @@ -30,9 +30,9 @@ void ffPrintLoadavg(FFLoadavgOptions* options) { FFCPUResult cpu = { .temperature = FF_CPU_TEMP_UNSET, - .frequencyMax = 0.0/0.0, - .frequencyBase = 0.0/0.0, - .frequencyBiosLimit = 0.0/0.0, + .frequencyMax = 0, + .frequencyBase = 0, + .frequencyBiosLimit = 0, .name = ffStrbufCreate(), .vendor = ffStrbufCreate(), };