From 1f20c0fb3debf2fa4d4be934d0b4552fdf814caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Wed, 13 Jan 2021 15:44:05 +0100 Subject: 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 --- linux/LinuxProcessList.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index 49b2d0e1..96e8de6e 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -20,6 +20,7 @@ in the source distribution for its full text. #include #include #include +#include #include #include #include @@ -1727,10 +1728,28 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) { int numCPUsWithFrequency = 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) { char pathBuffer[64]; 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"); if (!file) return -errno; @@ -1745,6 +1764,17 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) { } 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) -- cgit v1.2.3