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
.SH SYNOPSIS
.ft B
.B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ]
.RB [ "\-m MSR#" ]
.RB [ "\-M MSR#" ]
.RB [ Options ]
.RB command
.br
.B turbostat
.RB [ "\-s" ]
.RB [ "\-v" ]
.RB [ "\-m MSR#" ]
.RB [ "\-M MSR#" ]
.RB [ Options ]
.RB [ "\-i interval_sec" ]
.SH DESCRIPTION
\fBturbostat \fP reports processor topology, frequency
......@@ -37,11 +31,13 @@ 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 32-bit MSR,
in addition to the usual frequency and idle statistics.
The \fB-d MSR#\fP option includes the delta of the specified 32-bit MSR counter.
.PP
The \fB-M MSR#\fP option dumps the specified 64-bit MSR,
in addition to the usual frequency and idle statistics.
The \fB-D MSR#\fP option includes the delta of the specified 64-bit MSR counter.
.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
The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
The default is 5 seconds.
......@@ -155,6 +151,29 @@ Note that turbostat reports average GHz of 3.63, while
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
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
.B "turbostat "
......
......@@ -65,6 +65,8 @@ unsigned int do_nehalem_turbo_ratio_limit;
unsigned int do_ivt_turbo_ratio_limit;
unsigned int extra_msr_offset32;
unsigned int extra_msr_offset64;
unsigned int extra_delta_offset32;
unsigned int extra_delta_offset64;
double bclk;
unsigned int show_pkg;
unsigned int show_core;
......@@ -86,7 +88,9 @@ struct thread_data {
unsigned long long mperf;
unsigned long long c1; /* derived */
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 flags;
#define CPU_IS_FIRST_THREAD_IN_CORE 0x2
......@@ -208,24 +212,6 @@ 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)
......@@ -243,10 +229,14 @@ void print_header(void)
if (has_aperf)
outp += sprintf(outp, " GHz");
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)
outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset32);
outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32);
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)
outp += sprintf(outp, " %%c1");
if (do_nhm_cstates)
......@@ -278,7 +268,11 @@ 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",
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);
fprintf(stderr, "msr0x%x: %016llX\n",
extra_msr_offset64, t->extra_msr64);
......@@ -385,9 +379,16 @@ int format_counters(struct thread_data *t, struct core_data *c,
/* TSC */
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 */
if (extra_msr_offset32)
outp += sprintf(outp, " 0x%08x", t->extra_msr32);
outp += sprintf(outp, " 0x%08llx", t->extra_msr32);
/* MSR */
if (extra_msr_offset64)
......@@ -533,8 +534,13 @@ delta_thread(struct thread_data *new, struct thread_data *old,
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_msr64 = new->extra_msr64;
......@@ -565,6 +571,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
t->mperf = 0;
t->c1 = 0;
t->extra_delta32 = 0;
t->extra_delta64 = 0;
/* tells format_counters to dump all fields from this set */
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,
average.threads.mperf += t->mperf;
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 */
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
return 0;
......@@ -620,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c,
average.threads.mperf /= 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.c6 /= 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)
return -4;
}
if (extra_msr_offset32)
if (get_msr32(cpu, extra_msr_offset32, &t->extra_msr32))
if (extra_delta_offset32) {
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;
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 (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
return -5;
......@@ -1275,7 +1304,7 @@ void check_cpuid()
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);
exit(1);
}
......@@ -1565,7 +1594,7 @@ void cmdline(int argc, char **argv)
progname = argv[0];
while ((opt = getopt(argc, argv, "+cpsvi:m:M:")) != -1) {
while ((opt = getopt(argc, argv, "+cpsvid:D:m:M:")) != -1) {
switch (opt) {
case 'c':
show_core_only++;
......@@ -1582,15 +1611,17 @@ void cmdline(int argc, char **argv)
case 'i':
interval_sec = atoi(optarg);
break;
case 'd':
sscanf(optarg, "%x", &extra_delta_offset32);
break;
case 'D':
sscanf(optarg, "%x", &extra_delta_offset64);
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_offset64);
if (verbose > 1)
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