Commit 8e180f3c authored by Len Brown's avatar Len Brown

tools/power turbostat: add [-d MSR#][-D MSR#] options to print counter deltas

 # turbostat -d 0x34
is useful for printing the number of SMI's within an interval
on Nehalem and newer processors.

where
 # turbostat -m 0x34
will simply print out the total SMI count since reset.

Suggested-by: Andi Kleen
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 2f32edf1
...@@ -4,17 +4,11 @@ turbostat \- Report processor frequency and idle statistics ...@@ -4,17 +4,11 @@ turbostat \- Report processor frequency and idle statistics
.SH SYNOPSIS .SH SYNOPSIS
.ft B .ft B
.B turbostat .B turbostat
.RB [ "\-s" ] .RB [ Options ]
.RB [ "\-v" ]
.RB [ "\-m MSR#" ]
.RB [ "\-M MSR#" ]
.RB command .RB command
.br .br
.B turbostat .B turbostat
.RB [ "\-s" ] .RB [ Options ]
.RB [ "\-v" ]
.RB [ "\-m MSR#" ]
.RB [ "\-M MSR#" ]
.RB [ "\-i interval_sec" ] .RB [ "\-i interval_sec" ]
.SH DESCRIPTION .SH DESCRIPTION
\fBturbostat \fP reports processor topology, frequency \fBturbostat \fP reports processor topology, frequency
...@@ -37,11 +31,13 @@ The \fB-p\fP option limits output to the 1st thread in each package. ...@@ -37,11 +31,13 @@ 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 32-bit MSR, The \fB-d MSR#\fP option includes the delta of the specified 32-bit MSR counter.
in addition to the usual frequency and idle statistics.
.PP .PP
The \fB-M MSR#\fP option dumps the specified 64-bit MSR, The \fB-D MSR#\fP option includes the delta of the specified 64-bit MSR counter.
in addition to the usual frequency and idle statistics. .PP
The \fB-m MSR#\fP option includes the the specified 32-bit MSR value.
.PP
The \fB-M MSR#\fP option includes the the specified 64-bit MSR value.
.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.
The default is 5 seconds. The default is 5 seconds.
...@@ -155,6 +151,29 @@ Note that turbostat reports average GHz of 3.63, while ...@@ -155,6 +151,29 @@ Note that turbostat reports average GHz of 3.63, while
the arithmetic average of the GHz column above is lower. the arithmetic average of the GHz column above is lower.
This is a weighted average, where the weight is %c0. ie. it is the total number of This is a weighted average, where the weight is %c0. ie. it is the total number of
un-halted cycles elapsed per time divided by the number of CPUs. un-halted cycles elapsed per time divided by the number of CPUs.
.SH SMI COUNTING EXAMPLE
On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter.
Using the -m option, you can display how many SMIs have fired since reset, or if there
are SMIs during the measurement interval, you can display the delta using the -d option.
.nf
[root@x980 ~]# turbostat -m 0x34
cor CPU %c0 GHz TSC MSR 0x034 %c1 %c3 %c6 %pc3 %pc6
1.41 1.82 3.38 0x00000000 8.92 37.82 51.85 17.37 0.55
0 0 3.73 2.03 3.38 0x00000055 1.72 48.25 46.31 17.38 0.55
0 6 0.14 1.63 3.38 0x00000056 5.30
1 2 2.51 1.80 3.38 0x00000056 15.65 29.33 52.52
1 8 0.10 1.65 3.38 0x00000056 18.05
2 4 1.16 1.68 3.38 0x00000056 5.87 24.47 68.50
2 10 0.10 1.63 3.38 0x00000056 6.93
8 1 3.84 1.91 3.38 0x00000056 1.36 50.65 44.16
8 7 0.08 1.64 3.38 0x00000056 5.12
9 3 1.82 1.73 3.38 0x00000056 7.59 24.21 66.38
9 9 0.09 1.68 3.38 0x00000056 9.32
10 5 1.66 1.65 3.38 0x00000056 15.10 50.00 33.23
10 11 1.72 1.65 3.38 0x00000056 15.05
^C
[root@x980 ~]#
.fi
.SH NOTES .SH NOTES
.B "turbostat " .B "turbostat "
......
...@@ -65,6 +65,8 @@ unsigned int do_nehalem_turbo_ratio_limit; ...@@ -65,6 +65,8 @@ 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_offset32; unsigned int extra_msr_offset32;
unsigned int extra_msr_offset64; unsigned int extra_msr_offset64;
unsigned int extra_delta_offset32;
unsigned int extra_delta_offset64;
double bclk; double bclk;
unsigned int show_pkg; unsigned int show_pkg;
unsigned int show_core; unsigned int show_core;
...@@ -86,7 +88,9 @@ struct thread_data { ...@@ -86,7 +88,9 @@ struct thread_data {
unsigned long long mperf; unsigned long long mperf;
unsigned long long c1; /* derived */ unsigned long long c1; /* derived */
unsigned long long extra_msr64; unsigned long long extra_msr64;
unsigned int extra_msr32; unsigned long long extra_delta64;
unsigned long long extra_msr32;
unsigned long long extra_delta32;
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
...@@ -208,24 +212,6 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) ...@@ -208,24 +212,6 @@ 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)
...@@ -243,10 +229,14 @@ void print_header(void) ...@@ -243,10 +229,14 @@ 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_delta_offset32)
outp += sprintf(outp, " delta 0x%03X", extra_delta_offset32);
if (extra_delta_offset64)
outp += sprintf(outp, " DELTA 0x%03X", extra_delta_offset64);
if (extra_msr_offset32) if (extra_msr_offset32)
outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset32); outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32);
if (extra_msr_offset64) if (extra_msr_offset64)
outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset64); outp += sprintf(outp, " MSR 0x%03X", 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)
...@@ -278,7 +268,11 @@ int dump_counters(struct thread_data *t, struct core_data *c, ...@@ -278,7 +268,11 @@ 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", fprintf(stderr, "msr0x%x: %08llX\n",
extra_delta_offset32, t->extra_delta32);
fprintf(stderr, "msr0x%x: %016llX\n",
extra_delta_offset64, t->extra_delta64);
fprintf(stderr, "msr0x%x: %08llX\n",
extra_msr_offset32, t->extra_msr32); extra_msr_offset32, t->extra_msr32);
fprintf(stderr, "msr0x%x: %016llX\n", fprintf(stderr, "msr0x%x: %016llX\n",
extra_msr_offset64, t->extra_msr64); extra_msr_offset64, t->extra_msr64);
...@@ -385,9 +379,16 @@ int format_counters(struct thread_data *t, struct core_data *c, ...@@ -385,9 +379,16 @@ 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);
/* delta */
if (extra_delta_offset32)
outp += sprintf(outp, " %11llu", t->extra_delta32);
/* DELTA */
if (extra_delta_offset64)
outp += sprintf(outp, " %11llu", t->extra_delta64);
/* msr */ /* msr */
if (extra_msr_offset32) if (extra_msr_offset32)
outp += sprintf(outp, " 0x%08x", t->extra_msr32); outp += sprintf(outp, " 0x%08llx", t->extra_msr32);
/* MSR */ /* MSR */
if (extra_msr_offset64) if (extra_msr_offset64)
...@@ -533,8 +534,13 @@ delta_thread(struct thread_data *new, struct thread_data *old, ...@@ -533,8 +534,13 @@ delta_thread(struct thread_data *new, struct thread_data *old,
old->mperf = 1; /* divide by 0 protection */ old->mperf = 1; /* divide by 0 protection */
} }
old->extra_delta32 = new->extra_delta32 - old->extra_delta32;
old->extra_delta32 &= 0xFFFFFFFF;
old->extra_delta64 = new->extra_delta64 - old->extra_delta64;
/* /*
* Extra MSR is a snapshot, simply copy latest w/o subtracting * Extra MSR is just a snapshot, simply copy latest w/o subtracting
*/ */
old->extra_msr32 = new->extra_msr32; old->extra_msr32 = new->extra_msr32;
old->extra_msr64 = new->extra_msr64; old->extra_msr64 = new->extra_msr64;
...@@ -565,6 +571,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data ...@@ -565,6 +571,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
t->mperf = 0; t->mperf = 0;
t->c1 = 0; t->c1 = 0;
t->extra_delta32 = 0;
t->extra_delta64 = 0;
/* tells format_counters to dump all fields from this set */ /* tells format_counters to dump all fields from this set */
t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
...@@ -585,6 +594,9 @@ int sum_counters(struct thread_data *t, struct core_data *c, ...@@ -585,6 +594,9 @@ int sum_counters(struct thread_data *t, struct core_data *c,
average.threads.mperf += t->mperf; average.threads.mperf += t->mperf;
average.threads.c1 += t->c1; average.threads.c1 += t->c1;
average.threads.extra_delta32 += t->extra_delta32;
average.threads.extra_delta64 += t->extra_delta64;
/* sum per-core values only for 1st thread in core */ /* sum per-core values only for 1st thread in core */
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
return 0; return 0;
...@@ -620,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c, ...@@ -620,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c,
average.threads.mperf /= topo.num_cpus; average.threads.mperf /= topo.num_cpus;
average.threads.c1 /= topo.num_cpus; average.threads.c1 /= topo.num_cpus;
average.threads.extra_delta32 /= topo.num_cpus;
average.threads.extra_delta32 &= 0xFFFFFFFF;
average.threads.extra_delta64 /= topo.num_cpus;
average.cores.c3 /= topo.num_cores; average.cores.c3 /= topo.num_cores;
average.cores.c6 /= topo.num_cores; average.cores.c6 /= topo.num_cores;
average.cores.c7 /= topo.num_cores; average.cores.c7 /= topo.num_cores;
...@@ -661,10 +678,22 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) ...@@ -661,10 +678,22 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
return -4; return -4;
} }
if (extra_msr_offset32) if (extra_delta_offset32) {
if (get_msr32(cpu, extra_msr_offset32, &t->extra_msr32)) if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32))
return -5;
t->extra_delta32 &= 0xFFFFFFFF;
}
if (extra_delta_offset64)
if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64))
return -5; return -5;
if (extra_msr_offset32) {
if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32))
return -5;
t->extra_msr32 &= 0xFFFFFFFF;
}
if (extra_msr_offset64) if (extra_msr_offset64)
if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64)) if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
return -5; return -5;
...@@ -1275,7 +1304,7 @@ void check_cpuid() ...@@ -1275,7 +1304,7 @@ void check_cpuid()
void usage() void usage()
{ {
fprintf(stderr, "%s: [-v] [-m msr#] [-M MSR#] [-i interval_sec | command ...]\n", fprintf(stderr, "%s: [-v][-d MSR#][-D MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n",
progname); progname);
exit(1); exit(1);
} }
...@@ -1565,7 +1594,7 @@ void cmdline(int argc, char **argv) ...@@ -1565,7 +1594,7 @@ void cmdline(int argc, char **argv)
progname = argv[0]; progname = argv[0];
while ((opt = getopt(argc, argv, "+cpsvi:m:M:")) != -1) { while ((opt = getopt(argc, argv, "+cpsvid:D:m:M:")) != -1) {
switch (opt) { switch (opt) {
case 'c': case 'c':
show_core_only++; show_core_only++;
...@@ -1582,15 +1611,17 @@ void cmdline(int argc, char **argv) ...@@ -1582,15 +1611,17 @@ void cmdline(int argc, char **argv)
case 'i': case 'i':
interval_sec = atoi(optarg); interval_sec = atoi(optarg);
break; break;
case 'd':
sscanf(optarg, "%x", &extra_delta_offset32);
break;
case 'D':
sscanf(optarg, "%x", &extra_delta_offset64);
break;
case 'm': case 'm':
sscanf(optarg, "%x", &extra_msr_offset32); sscanf(optarg, "%x", &extra_msr_offset32);
if (verbose > 1)
fprintf(stderr, "msr 0x%X\n", extra_msr_offset32);
break; break;
case 'M': case 'M':
sscanf(optarg, "%x", &extra_msr_offset64); sscanf(optarg, "%x", &extra_msr_offset64);
if (verbose > 1)
fprintf(stderr, "MSR 0x%X\n", extra_msr_offset64);
break; break;
default: default:
usage(); 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