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>
This commit is contained in:
parent
130ff304f6
commit
2f32edf12c
2 changed files with 67 additions and 17 deletions
|
@ -6,12 +6,14 @@ turbostat \- Report processor frequency and idle statistics
|
||||||
.B turbostat
|
.B turbostat
|
||||||
.RB [ "\-s" ]
|
.RB [ "\-s" ]
|
||||||
.RB [ "\-v" ]
|
.RB [ "\-v" ]
|
||||||
|
.RB [ "\-m MSR#" ]
|
||||||
.RB [ "\-M MSR#" ]
|
.RB [ "\-M MSR#" ]
|
||||||
.RB command
|
.RB command
|
||||||
.br
|
.br
|
||||||
.B turbostat
|
.B turbostat
|
||||||
.RB [ "\-s" ]
|
.RB [ "\-s" ]
|
||||||
.RB [ "\-v" ]
|
.RB [ "\-v" ]
|
||||||
|
.RB [ "\-m MSR#" ]
|
||||||
.RB [ "\-M MSR#" ]
|
.RB [ "\-M MSR#" ]
|
||||||
.RB [ "\-i interval_sec" ]
|
.RB [ "\-i interval_sec" ]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
@ -35,7 +37,10 @@ The \fB-p\fP option limits output to the 1st thread in each package.
|
||||||
.PP
|
.PP
|
||||||
The \fB-v\fP option increases verbosity.
|
The \fB-v\fP option increases verbosity.
|
||||||
.PP
|
.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.
|
in addition to the usual frequency and idle statistics.
|
||||||
.PP
|
.PP
|
||||||
The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
|
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
|
as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
|
||||||
in those kernels.
|
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.
|
The APERF, MPERF MSRs are defined to count non-halted cycles.
|
||||||
Although it is not guaranteed by the architecture, turbostat assumes
|
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.
|
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_platform_info;
|
||||||
unsigned int do_nehalem_turbo_ratio_limit;
|
unsigned int do_nehalem_turbo_ratio_limit;
|
||||||
unsigned int do_ivt_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;
|
double bclk;
|
||||||
unsigned int show_pkg;
|
unsigned int show_pkg;
|
||||||
unsigned int show_core;
|
unsigned int show_core;
|
||||||
|
@ -84,7 +85,8 @@ struct thread_data {
|
||||||
unsigned long long aperf;
|
unsigned long long aperf;
|
||||||
unsigned long long mperf;
|
unsigned long long mperf;
|
||||||
unsigned long long c1; /* derived */
|
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 cpu_id;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
#define CPU_IS_FIRST_THREAD_IN_CORE 0x2
|
#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;
|
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)
|
void print_header(void)
|
||||||
{
|
{
|
||||||
if (show_pkg)
|
if (show_pkg)
|
||||||
|
@ -223,8 +243,10 @@ void print_header(void)
|
||||||
if (has_aperf)
|
if (has_aperf)
|
||||||
outp += sprintf(outp, " GHz");
|
outp += sprintf(outp, " GHz");
|
||||||
outp += sprintf(outp, " TSC");
|
outp += sprintf(outp, " TSC");
|
||||||
if (extra_msr_offset)
|
if (extra_msr_offset32)
|
||||||
outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset);
|
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)
|
if (do_nhm_cstates)
|
||||||
outp += sprintf(outp, " %%c1");
|
outp += sprintf(outp, " %%c1");
|
||||||
if (do_nhm_cstates)
|
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, "aperf: %016llX\n", t->aperf);
|
||||||
fprintf(stderr, "mperf: %016llX\n", t->mperf);
|
fprintf(stderr, "mperf: %016llX\n", t->mperf);
|
||||||
fprintf(stderr, "c1: %016llX\n", t->c1);
|
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",
|
fprintf(stderr, "msr0x%x: %016llX\n",
|
||||||
extra_msr_offset, t->extra_msr);
|
extra_msr_offset64, t->extra_msr64);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c) {
|
if (c) {
|
||||||
|
@ -361,9 +385,13 @@ int format_counters(struct thread_data *t, struct core_data *c,
|
||||||
/* TSC */
|
/* TSC */
|
||||||
outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
|
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 */
|
/* MSR */
|
||||||
if (extra_msr_offset)
|
if (extra_msr_offset64)
|
||||||
outp += sprintf(outp, " 0x%016llx", t->extra_msr);
|
outp += sprintf(outp, " 0x%016llx", t->extra_msr64);
|
||||||
|
|
||||||
if (do_nhm_cstates) {
|
if (do_nhm_cstates) {
|
||||||
if (!skip_c1)
|
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,
|
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;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extra_msr_offset)
|
if (extra_msr_offset32)
|
||||||
if (get_msr(cpu, extra_msr_offset, &t->extra_msr))
|
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;
|
return -5;
|
||||||
|
|
||||||
/* collect core counters only for 1st thread in core */
|
/* collect core counters only for 1st thread in core */
|
||||||
|
@ -1242,7 +1275,7 @@ void check_cpuid()
|
||||||
|
|
||||||
void usage()
|
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);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -1532,7 +1565,7 @@ void cmdline(int argc, char **argv)
|
||||||
|
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) {
|
while ((opt = getopt(argc, argv, "+cpsvi:m:M:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'c':
|
case 'c':
|
||||||
show_core_only++;
|
show_core_only++;
|
||||||
|
@ -1549,10 +1582,15 @@ void cmdline(int argc, char **argv)
|
||||||
case 'i':
|
case 'i':
|
||||||
interval_sec = atoi(optarg);
|
interval_sec = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'm':
|
||||||
sscanf(optarg, "%x", &extra_msr_offset);
|
sscanf(optarg, "%x", &extra_msr_offset32);
|
||||||
if (verbose > 1)
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
|
|
Loading…
Add table
Reference in a new issue