Linux: fall back to cpuinfo on slow scaling_cur_freq read

On some AMD and Intel CPUs read()ing scaling_cur_freq is quite slow
(> 1ms). This delay accumulates for every core.
If the read on CPU 0 takes longer than 500us bail out and fall back to
reading the frequencies from /proc/cpuinfo.
Once the condition has been met, bail out early for the next couple of
scans.

Closes: #471
This commit is contained in:
Christian Göttsche 2021-01-13 15:44:05 +01:00 committed by cgzones
parent b5a5e83470
commit 1f20c0fb3d
1 changed files with 30 additions and 0 deletions

View File

@ -20,6 +20,7 @@ in the source distribution for its full text.
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
@ -1727,10 +1728,28 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
int numCPUsWithFrequency = 0; int numCPUsWithFrequency = 0;
unsigned long totalFrequency = 0; unsigned long totalFrequency = 0;
/*
* On some AMD and Intel CPUs read()ing scaling_cur_freq is quite slow (> 1ms). This delay
* accumulates for every core. For details see issue#471.
* If the read on CPU 0 takes longer than 500us bail out and fall back to reading the
* frequencies from /proc/cpuinfo.
* Once the condition has been met, bail out early for the next couple of scans.
*/
static int timeout = 0;
if (timeout > 0) {
timeout--;
return -1;
}
for (int i = 0; i < cpus; ++i) { for (int i = 0; i < cpus; ++i) {
char pathBuffer[64]; char pathBuffer[64];
xSnprintf(pathBuffer, sizeof(pathBuffer), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i); xSnprintf(pathBuffer, sizeof(pathBuffer), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
struct timespec start;
if (i == 0)
clock_gettime(CLOCK_MONOTONIC, &start);
FILE* file = fopen(pathBuffer, "r"); FILE* file = fopen(pathBuffer, "r");
if (!file) if (!file)
return -errno; return -errno;
@ -1745,6 +1764,17 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
} }
fclose(file); fclose(file);
if (i == 0) {
struct timespec end;
clock_gettime(CLOCK_MONOTONIC, &end);
const time_t timeTakenUs = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
if (timeTakenUs > 500) {
timeout = 30;
return -1;
}
}
} }
if (numCPUsWithFrequency > 0) if (numCPUsWithFrequency > 0)