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.
This commit is contained in:
Christian Göttsche 2020-09-22 14:50:50 +02:00 committed by cgzones
parent f4e1f4619f
commit edf1b10d2c
2 changed files with 85 additions and 59 deletions

View File

@ -45,7 +45,7 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
if (isnan(cpuFrequency)) { if (isnan(cpuFrequency)) {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A"); xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A");
} else { } else {
xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%.0fMHz", cpuFrequency); xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "%4uMHz", (unsigned)cpuFrequency);
} }
if (this->pl->settings->showCPUUsage) { if (this->pl->settings->showCPUUsage) {
xSnprintf(buffer, size, "%5.1f%% %s", percent, cpuFrequencyBuffer); xSnprintf(buffer, size, "%5.1f%% %s", percent, cpuFrequencyBuffer);

View File

@ -1145,53 +1145,69 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
return period; return period;
} }
static inline double LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) { static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) {
ProcessList* pl = (ProcessList*) this; int cpus = this->super.cpuCount;
Settings* settings = pl->settings; 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;
}
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 cpus = this->super.cpuCount;
assert(cpus > 0);
for (int i = 0; i <= cpus; i++) {
CPUData* cpuData = &(this->cpus[i]);
cpuData->frequency = NAN;
}
int numCPUsWithFrequency = 0; int numCPUsWithFrequency = 0;
double totalFrequency = 0; double totalFrequency = 0;
if (settings->showCPUFrequency) {
FILE* file = fopen(PROCCPUINFOFILE, "r");
if (file == NULL) {
CRT_fatalError("Cannot open " PROCCPUINFOFILE);
}
int cpuid = -1; int cpuid = -1;
double frequency;
while (!feof(file)) { while (!feof(file)) {
double frequency;
char buffer[PROC_LINE_LENGTH]; char buffer[PROC_LINE_LENGTH];
char *ok = fgets(buffer, PROC_LINE_LENGTH, file);
if (!ok) break; if (fgets(buffer, PROC_LINE_LENGTH, file) == NULL)
break;
if ( if (
(sscanf(buffer, "processor : %d", &cpuid) == 1) || (sscanf(buffer, "processor : %d", &cpuid) == 1) ||
(sscanf(buffer, "processor: %d", &cpuid) == 1) (sscanf(buffer, "processor: %d", &cpuid) == 1)
) { ) {
if (cpuid < 0 || cpuid > (cpus - 1)) { continue;
char tmpbuffer[64];
xSnprintf(tmpbuffer, sizeof(tmpbuffer), PROCCPUINFOFILE " contains out-of-range CPU number %d", cpuid);
CRT_fatalError(tmpbuffer);
}
} else if ( } else if (
(sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) || (sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
(sscanf(buffer, "cpu MHz: %lf", &frequency) == 1) (sscanf(buffer, "cpu MHz: %lf", &frequency) == 1)
) { ) {
if (cpuid < 0 || cpuid > (cpus - 1)) { if (cpuid < 0 || cpuid > (cpus - 1))
CRT_fatalError(PROCCPUINFOFILE " is malformed: cpu MHz line without corresponding processor line"); continue;
}
int cpu = cpuid + 1; CPUData* cpuData = &(this->cpus[cpuid + 1]);
CPUData* cpuData = &(this->cpus[cpu]); /* do not override sysfs data */
if (isnan(cpuData->frequency))
cpuData->frequency = frequency; cpuData->frequency = frequency;
numCPUsWithFrequency++; numCPUsWithFrequency++;
totalFrequency += frequency; totalFrequency += frequency;
@ -1201,22 +1217,32 @@ static inline double LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
} }
fclose(file); fclose(file);
if (numCPUsWithFrequency > 0) { if (numCPUsWithFrequency > 0)
this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency; this->cpus[0].frequency = totalFrequency / numCPUsWithFrequency;
} }
}
double period = (double)this->cpus[0].totalPeriod / cpus; static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
return period; 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) { void ProcessList_goThroughEntries(ProcessList* super) {
LinuxProcessList* this = (LinuxProcessList*) super; LinuxProcessList* this = (LinuxProcessList*) super;
const Settings* settings = super->settings;
LinuxProcessList_scanMemoryInfo(super); LinuxProcessList_scanMemoryInfo(super);
LinuxProcessList_scanZfsArcstats(this); LinuxProcessList_scanZfsArcstats(this);
double period = LinuxProcessList_scanCPUTime(this); double period = LinuxProcessList_scanCPUTime(this);
if (settings->showCPUFrequency)
LinuxProcessList_scanCPUFrequency(this); LinuxProcessList_scanCPUFrequency(this);
struct timeval tv; struct timeval tv;