diff options
author | Christian Göttsche <cgzones@googlemail.com> | 2020-09-22 14:50:50 +0200 |
---|---|---|
committer | cgzones <cgzones@googlemail.com> | 2020-09-24 20:11:28 +0200 |
commit | edf1b10d2c3fa94c23a23cfc947490cf1ebf66d1 (patch) | |
tree | 09571af36c5d969795a188604db164bfce1fd3cd | |
parent | f4e1f4619f3761382d5e97ddf92237085a7bd443 (diff) |
Read CPU frequency from sysfs by default
Use the more portable sysfs node /sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq
to get the CPU frequency.
In case of an error fall back to /proc/cpuinfo .
Also use a fixed width of 4 for the frequency to avoid position jumps
in case the frequency moves in the range 900-1100 MHz.
-rw-r--r-- | CPUMeter.c | 2 | ||||
-rw-r--r-- | linux/LinuxProcessList.c | 128 |
2 files changed, 78 insertions, 52 deletions
@@ -45,7 +45,7 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) { if (isnan(cpuFrequency)) { xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A"); } else { - xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%.0fMHz", cpuFrequency); + xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency); } if (this->pl->settings->showCPUUsage) { xSnprintf(buffer, size, "%5.1f%% %s", percent, cpuFrequencyBuffer); diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index 318a94b9..807cc8a6 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -1145,79 +1145,105 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) { return period; } -static inline double LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) { - ProcessList* pl = (ProcessList*) this; - Settings* settings = pl->settings; - +static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) { int cpus = this->super.cpuCount; - assert(cpus > 0); + int numCPUsWithFrequency = 0; + unsigned long totalFrequency = 0; + + for (int i = 0; i < cpus; ++i) { + char pathBuffer[64]; + xSnprintf(pathBuffer, sizeof(pathBuffer), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i); + + FILE* file = fopen(pathBuffer, "r"); + if (!file) + return -errno; + + unsigned long frequency; + if (fscanf(file, "%lu", &frequency) == 1) { + /* convert kHz to MHz */ + frequency = frequency / 1000; + this->cpus[i + 1].frequency = frequency; + numCPUsWithFrequency++; + totalFrequency += frequency; + } - for (int i = 0; i <= cpus; i++) { - CPUData* cpuData = &(this->cpus[i]); - cpuData->frequency = NAN; + fclose(file); } + if (numCPUsWithFrequency > 0) + this->cpus[0].frequency = (double)totalFrequency / numCPUsWithFrequency; + + return 0; +} + +static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) { + FILE* file = fopen(PROCCPUINFOFILE, "r"); + if (file == NULL) + return; + + int cpus = this->super.cpuCount; int numCPUsWithFrequency = 0; double totalFrequency = 0; + int cpuid = -1; - if (settings->showCPUFrequency) { - FILE* file = fopen(PROCCPUINFOFILE, "r"); - if (file == NULL) { - CRT_fatalError("Cannot open " PROCCPUINFOFILE); - } - - int cpuid = -1; + while (!feof(file)) { double frequency; - while (!feof(file)) { - char buffer[PROC_LINE_LENGTH]; - char *ok = fgets(buffer, PROC_LINE_LENGTH, file); - if (!ok) break; - - if ( - (sscanf(buffer, "processor : %d", &cpuid) == 1) || - (sscanf(buffer, "processor: %d", &cpuid) == 1) - ) { - if (cpuid < 0 || cpuid > (cpus - 1)) { - char tmpbuffer[64]; - xSnprintf(tmpbuffer, sizeof(tmpbuffer), PROCCPUINFOFILE " contains out-of-range CPU number %d", cpuid); - CRT_fatalError(tmpbuffer); - } - } else if ( - (sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) || - (sscanf(buffer, "cpu MHz: %lf", &frequency) == 1) - ) { - if (cpuid < 0 || cpuid > (cpus - 1)) { - CRT_fatalError(PROCCPUINFOFILE " is malformed: cpu MHz line without corresponding processor line"); - } + char buffer[PROC_LINE_LENGTH]; - int cpu = cpuid + 1; - CPUData* cpuData = &(this->cpus[cpu]); - cpuData->frequency = frequency; - numCPUsWithFrequency++; - totalFrequency += frequency; - } else if (buffer[0] == '\n') { - cpuid = -1; - } - } - fclose(file); + if (fgets(buffer, PROC_LINE_LENGTH, file) == NULL) + break; - if (numCPUsWithFrequency > 0) { - this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency; + if ( + (sscanf(buffer, "processor : %d", &cpuid) == 1) || + (sscanf(buffer, "processor: %d", &cpuid) == 1) + ) { + continue; + } else if ( + (sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) || + (sscanf(buffer, "cpu MHz: %lf", &frequency) == 1) + ) { + if (cpuid < 0 || cpuid > (cpus - 1)) + continue; + + CPUData* cpuData = &(this->cpus[cpuid + 1]); + /* do not override sysfs data */ + if (isnan(cpuData->frequency)) + cpuData->frequency = frequency; + numCPUsWithFrequency++; + totalFrequency += frequency; + } else if (buffer[0] == '\n') { + cpuid = -1; } } + fclose(file); - double period = (double)this->cpus[0].totalPeriod / cpus; - return period; + if (numCPUsWithFrequency > 0) + this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency; +} + +static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) { + int cpus = this->super.cpuCount; + assert(cpus > 0); + + for (int i = 0; i <= cpus; i++) + this->cpus[i].frequency = NAN; + + if (scanCPUFreqencyFromSysCPUFreq(this) == 0) + return; + + scanCPUFreqencyFromCPUinfo(this); } void ProcessList_goThroughEntries(ProcessList* super) { LinuxProcessList* this = (LinuxProcessList*) super; + const Settings* settings = super->settings; LinuxProcessList_scanMemoryInfo(super); LinuxProcessList_scanZfsArcstats(this); double period = LinuxProcessList_scanCPUTime(this); - LinuxProcessList_scanCPUFrequency(this); + if (settings->showCPUFrequency) + LinuxProcessList_scanCPUFrequency(this); struct timeval tv; gettimeofday(&tv, NULL); |