Skip to content

Commit ed625c6

Browse files
dedekindlenb
authored andcommitted
tools/power turbostat: Add idle governor statistics reporting
The idle governor provides the following per-idle state sysfs files: * above - Indicates overshoots, where a more shallow state should have been requested (if avaliale and enabled). * below - Indicates undershoots, where a deeper state should have been requested (if available and enabled). These files offer valuable insights into how effectively the Linux kernel idle governor selects idle states for a given workload. This commit adds support for these files in turbostat. Expose the contents of these files with the following naming convention: * C1: The number of times the C1 state was requested (existing counter). * C1+: The number of times the idle governor selected C1, but a deeper idle state should have been selected instead. * C1-: The number of times the idle governor selected C1, but a shallower idle state should have been selected instead. Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
1 parent 5132681 commit ed625c6

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

tools/power/x86/turbostat/turbostat.8

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ The system configuration dump (if --quiet is not used) is followed by statistics
160160
.PP
161161
\fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval. The system summary line shows the sum for all CPUs. These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name. While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system.
162162
.PP
163+
\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file.
164+
.PP
165+
\fBC1-, C2-, C3-...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a shallower idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/above file.
166+
.PP
163167
\fBC1%, C2%, C3%\fP The residency percentage that Linux requested C1, C2, C3.... The system summary is the average of all CPUs in the system. Note that these are software, reflecting what was requested. The hardware counters reflect what was actually achieved.
164168
.PP
165169
\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. These numbers are from hardware residency counters.

tools/power/x86/turbostat/turbostat.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10265,6 +10265,7 @@ void probe_sysfs(void)
1026510265
char name_buf[16];
1026610266
FILE *input;
1026710267
int state;
10268+
int min_state = 1024, max_state = 0;
1026810269
char *sp;
1026910270

1027010271
for (state = 10; state >= 0; --state) {
@@ -10296,6 +10297,11 @@ void probe_sysfs(void)
1029610297
continue;
1029710298

1029810299
add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_USEC, FORMAT_PERCENT, SYSFS_PERCPU, 0);
10300+
10301+
if (state > max_state)
10302+
max_state = state;
10303+
if (state < min_state)
10304+
min_state = state;
1029910305
}
1030010306

1030110307
for (state = 10; state >= 0; --state) {
@@ -10306,26 +10312,52 @@ void probe_sysfs(void)
1030610312
continue;
1030710313
if (!fgets(name_buf, sizeof(name_buf), input))
1030810314
err(1, "%s: failed to read file", path);
10309-
/* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
10310-
sp = strchr(name_buf, '-');
10311-
if (!sp)
10312-
sp = strchrnul(name_buf, '\n');
10313-
*sp = '\0';
1031410315
fclose(input);
1031510316

1031610317
remove_underbar(name_buf);
1031710318

10318-
sprintf(path, "cpuidle/state%d/usage", state);
10319-
1032010319
if (!DO_BIC(BIC_sysfs) && !is_deferred_add(name_buf))
1032110320
continue;
1032210321

1032310322
if (is_deferred_skip(name_buf))
1032410323
continue;
1032510324

10325+
/* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
10326+
sp = strchr(name_buf, '-');
10327+
if (!sp)
10328+
sp = strchrnul(name_buf, '\n');
10329+
10330+
/*
10331+
* The 'below' sysfs file always contains 0 for the deepest state (largest index),
10332+
* do not add it.
10333+
*/
10334+
if (state != max_state) {
10335+
/*
10336+
* Add 'C1+' for C1, and so on. The 'below' sysfs file always contains 0 for
10337+
* the last state, so do not add it.
10338+
*/
10339+
10340+
*sp = '+';
10341+
*(sp + 1) = '\0';
10342+
sprintf(path, "cpuidle/state%d/below", state);
10343+
add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_ITEMS, FORMAT_DELTA, SYSFS_PERCPU, 0);
10344+
}
10345+
10346+
*sp = '\0';
10347+
sprintf(path, "cpuidle/state%d/usage", state);
1032610348
add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_ITEMS, FORMAT_DELTA, SYSFS_PERCPU, 0);
10327-
}
1032810349

10350+
/*
10351+
* The 'above' sysfs file always contains 0 for the shallowest state (smallest
10352+
* index), do not add it.
10353+
*/
10354+
if (state != min_state) {
10355+
*sp = '-';
10356+
*(sp + 1) = '\0';
10357+
sprintf(path, "cpuidle/state%d/above", state);
10358+
add_counter(0, path, name_buf, 64, SCOPE_CPU, COUNTER_ITEMS, FORMAT_DELTA, SYSFS_PERCPU, 0);
10359+
}
10360+
}
1032910361
}
1033010362

1033110363
/*

0 commit comments

Comments
 (0)