Commit 2f32edf1 authored by Len Brown's avatar Len Brown
Browse files

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: default avatarLen Brown <len.brown@intel.com>
parent 130ff304
......@@ -6,12 +6,14 @@ turbostat \- Report processor frequency and idle statistics
.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 @@ The \fB-p\fP option limits output to the 1st thread in each package.
.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 @@ may work poorly on Linux-2.6.20 through 2.6.29,
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.
......
......@@ -63,7 +63,8 @@ unsigned int has_invariant_tsc;
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 @@ struct thread_data {
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 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
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 @@ void print_header(void)
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 @@ int dump_counters(struct thread_data *t, struct core_data *c,
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 @@ int format_counters(struct thread_data *t, struct core_data *c,
/* 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 @@ delta_thread(struct thread_data *new, struct thread_data *old,
}
/*
* 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 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
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 check_cpuid()
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 @@ void cmdline(int argc, char **argv)
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 @@ void cmdline(int argc, char **argv)
case 'i':
interval_sec = atoi(optarg);
break;
case 'm':
sscanf(optarg, "%x", &extra_msr_offset32);
if (verbose > 1)
fprintf(stderr, "msr 0x%X\n", extra_msr_offset32);
break;
case 'M':
sscanf(optarg, "%x", &extra_msr_offset);
sscanf(optarg, "%x", &extra_msr_offset64);
if (verbose > 1)
fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
fprintf(stderr, "MSR 0x%X\n", extra_msr_offset64);
break;
default:
usage();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment