tools/power turbostat: add [-m MSR#] option
-m MSR# prints the specified MSR in 32-bit format
-M MSR# prints the specified MSR in 64-bit format
Signed-off-by: Len Brown <len.brown@intel.com>
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index 74e4450..8e7b29af 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -6,12 +6,14 @@
.B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ]
+.RB [ "\-m MSR#" ]
.RB [ "\-M MSR#" ]
.RB command
.br
.B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ]
+.RB [ "\-m MSR#" ]
.RB [ "\-M MSR#" ]
.RB [ "\-i interval_sec" ]
.SH DESCRIPTION
@@ -35,7 +37,10 @@
.PP
The \fB-v\fP option increases verbosity.
.PP
-The \fB-M MSR#\fP option dumps the specified MSR,
+The \fB-m MSR#\fP option dumps the specified 32-bit MSR,
+in addition to the usual frequency and idle statistics.
+.PP
+The \fB-M MSR#\fP option dumps the specified 64-bit MSR,
in addition to the usual frequency and idle statistics.
.PP
The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
@@ -165,6 +170,13 @@
as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
in those kernels.
+If the TSC column does not make sense, then
+the other numbers will also make no sense.
+Turbostat is lightweight, and its data collection is not atomic.
+These issues are usually caused by an extremely short measurement
+interval (much less than 1 second), or system activity that prevents
+turbostat from being able to run on all CPUS to quickly collect data.
+
The APERF, MPERF MSRs are defined to count non-halted cycles.
Although it is not guaranteed by the architecture, turbostat assumes
that they count at TSC rate, which is true on all processors tested to date.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 5ce88dd..946e9ab 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -63,7 +63,8 @@
unsigned int do_nehalem_platform_info;
unsigned int do_nehalem_turbo_ratio_limit;
unsigned int do_ivt_turbo_ratio_limit;
-unsigned int extra_msr_offset;
+unsigned int extra_msr_offset32;
+unsigned int extra_msr_offset64;
double bclk;
unsigned int show_pkg;
unsigned int show_core;
@@ -84,7 +85,8 @@
unsigned long long aperf;
unsigned long long mperf;
unsigned long long c1; /* derived */
- unsigned long long extra_msr;
+ unsigned long long extra_msr64;
+ unsigned int extra_msr32;
unsigned int cpu_id;
unsigned int flags;
#define CPU_IS_FIRST_THREAD_IN_CORE 0x2
@@ -206,6 +208,24 @@
return 0;
}
+/*
+ * Truncate the 8 bytes we read from /dev/cpu/.../msr
+ * to the 4 bytes requested
+ */
+
+int get_msr32(int cpu, off_t offset, unsigned int *msr)
+{
+ int retval;
+
+ unsigned long long msr64;
+
+ retval = get_msr(cpu, offset, &msr64);
+ *msr = (unsigned int) msr64;
+
+ return retval;
+}
+
+
void print_header(void)
{
if (show_pkg)
@@ -223,8 +243,10 @@
if (has_aperf)
outp += sprintf(outp, " GHz");
outp += sprintf(outp, " TSC");
- if (extra_msr_offset)
- outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset);
+ if (extra_msr_offset32)
+ outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset32);
+ if (extra_msr_offset64)
+ outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset64);
if (do_nhm_cstates)
outp += sprintf(outp, " %%c1");
if (do_nhm_cstates)
@@ -256,8 +278,10 @@
fprintf(stderr, "aperf: %016llX\n", t->aperf);
fprintf(stderr, "mperf: %016llX\n", t->mperf);
fprintf(stderr, "c1: %016llX\n", t->c1);
+ fprintf(stderr, "msr0x%x: %08X\n",
+ extra_msr_offset32, t->extra_msr32);
fprintf(stderr, "msr0x%x: %016llX\n",
- extra_msr_offset, t->extra_msr);
+ extra_msr_offset64, t->extra_msr64);
}
if (c) {
@@ -361,9 +385,13 @@
/* TSC */
outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
+ /* msr */
+ if (extra_msr_offset32)
+ outp += sprintf(outp, " 0x%08x", t->extra_msr32);
+
/* MSR */
- if (extra_msr_offset)
- outp += sprintf(outp, " 0x%016llx", t->extra_msr);
+ if (extra_msr_offset64)
+ outp += sprintf(outp, " 0x%016llx", t->extra_msr64);
if (do_nhm_cstates) {
if (!skip_c1)
@@ -506,9 +534,10 @@
}
/*
- * for "extra msr", just copy the latest w/o subtracting
+ * Extra MSR is a snapshot, simply copy latest w/o subtracting
*/
- old->extra_msr = new->extra_msr;
+ old->extra_msr32 = new->extra_msr32;
+ old->extra_msr64 = new->extra_msr64;
}
int delta_cpu(struct thread_data *t, struct core_data *c,
@@ -632,8 +661,12 @@
return -4;
}
- if (extra_msr_offset)
- if (get_msr(cpu, extra_msr_offset, &t->extra_msr))
+ if (extra_msr_offset32)
+ if (get_msr32(cpu, extra_msr_offset32, &t->extra_msr32))
+ return -5;
+
+ if (extra_msr_offset64)
+ if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
return -5;
/* collect core counters only for 1st thread in core */
@@ -1242,7 +1275,7 @@
void usage()
{
- fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
+ fprintf(stderr, "%s: [-v] [-m msr#] [-M MSR#] [-i interval_sec | command ...]\n",
progname);
exit(1);
}
@@ -1532,7 +1565,7 @@
progname = argv[0];
- while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) {
+ while ((opt = getopt(argc, argv, "+cpsvi:m:M:")) != -1) {
switch (opt) {
case 'c':
show_core_only++;
@@ -1549,10 +1582,15 @@
case 'i':
interval_sec = atoi(optarg);
break;
- case 'M':
- sscanf(optarg, "%x", &extra_msr_offset);
+ case 'm':
+ sscanf(optarg, "%x", &extra_msr_offset32);
if (verbose > 1)
- fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
+ fprintf(stderr, "msr 0x%X\n", extra_msr_offset32);
+ break;
+ case 'M':
+ sscanf(optarg, "%x", &extra_msr_offset64);
+ if (verbose > 1)
+ fprintf(stderr, "MSR 0x%X\n", extra_msr_offset64);
break;
default:
usage();