diff options
author | Len Brown <len.brown@intel.com> | 2012-09-22 01:25:08 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-09-27 22:04:56 -0400 |
commit | 8e180f3cb6b7510a3bdf14e16ce87c9f5d86f102 (patch) | |
tree | 2a7b3ac9789a47d1bfb9ccbb7a9a4fa31f91b61d /tools/power | |
parent | 2f32edf12c1eafc8e5b1b0337360993fde1b3565 (diff) |
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: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools/power')
-rw-r--r-- | tools/power/x86/turbostat/turbostat.8 | 43 | ||||
-rw-r--r-- | tools/power/x86/turbostat/turbostat.c | 95 |
2 files changed, 94 insertions, 44 deletions
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 8e7b29af78f6..0fc7a11f300e 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 | |||
@@ -4,17 +4,11 @@ turbostat \- Report processor frequency and idle statistics | |||
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .ft B | 5 | .ft B |
6 | .B turbostat | 6 | .B turbostat |
7 | .RB [ "\-s" ] | 7 | .RB [ Options ] |
8 | .RB [ "\-v" ] | ||
9 | .RB [ "\-m MSR#" ] | ||
10 | .RB [ "\-M MSR#" ] | ||
11 | .RB command | 8 | .RB command |
12 | .br | 9 | .br |
13 | .B turbostat | 10 | .B turbostat |
14 | .RB [ "\-s" ] | 11 | .RB [ Options ] |
15 | .RB [ "\-v" ] | ||
16 | .RB [ "\-m MSR#" ] | ||
17 | .RB [ "\-M MSR#" ] | ||
18 | .RB [ "\-i interval_sec" ] | 12 | .RB [ "\-i interval_sec" ] |
19 | .SH DESCRIPTION | 13 | .SH DESCRIPTION |
20 | \fBturbostat \fP reports processor topology, frequency | 14 | \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 | .PP | 31 | .PP |
38 | The \fB-v\fP option increases verbosity. | 32 | The \fB-v\fP option increases verbosity. |
39 | .PP | 33 | .PP |
40 | The \fB-m MSR#\fP option dumps the specified 32-bit MSR, | 34 | The \fB-d MSR#\fP option includes the delta of the specified 32-bit MSR counter. |
41 | in addition to the usual frequency and idle statistics. | ||
42 | .PP | 35 | .PP |
43 | The \fB-M MSR#\fP option dumps the specified 64-bit MSR, | 36 | The \fB-D MSR#\fP option includes the delta of the specified 64-bit MSR counter. |
44 | in addition to the usual frequency and idle statistics. | 37 | .PP |
38 | The \fB-m MSR#\fP option includes the the specified 32-bit MSR value. | ||
39 | .PP | ||
40 | The \fB-M MSR#\fP option includes the the specified 64-bit MSR value. | ||
45 | .PP | 41 | .PP |
46 | The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. | 42 | The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. |
47 | The default is 5 seconds. | 43 | The default is 5 seconds. |
@@ -155,6 +151,29 @@ Note that turbostat reports average GHz of 3.63, while | |||
155 | the arithmetic average of the GHz column above is lower. | 151 | the arithmetic average of the GHz column above is lower. |
156 | This is a weighted average, where the weight is %c0. ie. it is the total number of | 152 | This is a weighted average, where the weight is %c0. ie. it is the total number of |
157 | un-halted cycles elapsed per time divided by the number of CPUs. | 153 | un-halted cycles elapsed per time divided by the number of CPUs. |
154 | .SH SMI COUNTING EXAMPLE | ||
155 | On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter. | ||
156 | Using the -m option, you can display how many SMIs have fired since reset, or if there | ||
157 | are SMIs during the measurement interval, you can display the delta using the -d option. | ||
158 | .nf | ||
159 | [root@x980 ~]# turbostat -m 0x34 | ||
160 | cor CPU %c0 GHz TSC MSR 0x034 %c1 %c3 %c6 %pc3 %pc6 | ||
161 | 1.41 1.82 3.38 0x00000000 8.92 37.82 51.85 17.37 0.55 | ||
162 | 0 0 3.73 2.03 3.38 0x00000055 1.72 48.25 46.31 17.38 0.55 | ||
163 | 0 6 0.14 1.63 3.38 0x00000056 5.30 | ||
164 | 1 2 2.51 1.80 3.38 0x00000056 15.65 29.33 52.52 | ||
165 | 1 8 0.10 1.65 3.38 0x00000056 18.05 | ||
166 | 2 4 1.16 1.68 3.38 0x00000056 5.87 24.47 68.50 | ||
167 | 2 10 0.10 1.63 3.38 0x00000056 6.93 | ||
168 | 8 1 3.84 1.91 3.38 0x00000056 1.36 50.65 44.16 | ||
169 | 8 7 0.08 1.64 3.38 0x00000056 5.12 | ||
170 | 9 3 1.82 1.73 3.38 0x00000056 7.59 24.21 66.38 | ||
171 | 9 9 0.09 1.68 3.38 0x00000056 9.32 | ||
172 | 10 5 1.66 1.65 3.38 0x00000056 15.10 50.00 33.23 | ||
173 | 10 11 1.72 1.65 3.38 0x00000056 15.05 | ||
174 | ^C | ||
175 | [root@x980 ~]# | ||
176 | .fi | ||
158 | .SH NOTES | 177 | .SH NOTES |
159 | 178 | ||
160 | .B "turbostat " | 179 | .B "turbostat " |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 946e9ab48edb..e38976c0b0a2 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -65,6 +65,8 @@ unsigned int do_nehalem_turbo_ratio_limit; | |||
65 | unsigned int do_ivt_turbo_ratio_limit; | 65 | unsigned int do_ivt_turbo_ratio_limit; |
66 | unsigned int extra_msr_offset32; | 66 | unsigned int extra_msr_offset32; |
67 | unsigned int extra_msr_offset64; | 67 | unsigned int extra_msr_offset64; |
68 | unsigned int extra_delta_offset32; | ||
69 | unsigned int extra_delta_offset64; | ||
68 | double bclk; | 70 | double bclk; |
69 | unsigned int show_pkg; | 71 | unsigned int show_pkg; |
70 | unsigned int show_core; | 72 | unsigned int show_core; |
@@ -86,7 +88,9 @@ struct thread_data { | |||
86 | unsigned long long mperf; | 88 | unsigned long long mperf; |
87 | unsigned long long c1; /* derived */ | 89 | unsigned long long c1; /* derived */ |
88 | unsigned long long extra_msr64; | 90 | unsigned long long extra_msr64; |
89 | unsigned int extra_msr32; | 91 | unsigned long long extra_delta64; |
92 | unsigned long long extra_msr32; | ||
93 | unsigned long long extra_delta32; | ||
90 | unsigned int cpu_id; | 94 | unsigned int cpu_id; |
91 | unsigned int flags; | 95 | unsigned int flags; |
92 | #define CPU_IS_FIRST_THREAD_IN_CORE 0x2 | 96 | #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 | return 0; | 212 | return 0; |
209 | } | 213 | } |
210 | 214 | ||
211 | /* | ||
212 | * Truncate the 8 bytes we read from /dev/cpu/.../msr | ||
213 | * to the 4 bytes requested | ||
214 | */ | ||
215 | |||
216 | int get_msr32(int cpu, off_t offset, unsigned int *msr) | ||
217 | { | ||
218 | int retval; | ||
219 | |||
220 | unsigned long long msr64; | ||
221 | |||
222 | retval = get_msr(cpu, offset, &msr64); | ||
223 | *msr = (unsigned int) msr64; | ||
224 | |||
225 | return retval; | ||
226 | } | ||
227 | |||
228 | |||
229 | void print_header(void) | 215 | void print_header(void) |
230 | { | 216 | { |
231 | if (show_pkg) | 217 | if (show_pkg) |
@@ -243,10 +229,14 @@ void print_header(void) | |||
243 | if (has_aperf) | 229 | if (has_aperf) |
244 | outp += sprintf(outp, " GHz"); | 230 | outp += sprintf(outp, " GHz"); |
245 | outp += sprintf(outp, " TSC"); | 231 | outp += sprintf(outp, " TSC"); |
232 | if (extra_delta_offset32) | ||
233 | outp += sprintf(outp, " delta 0x%03X", extra_delta_offset32); | ||
234 | if (extra_delta_offset64) | ||
235 | outp += sprintf(outp, " DELTA 0x%03X", extra_delta_offset64); | ||
246 | if (extra_msr_offset32) | 236 | if (extra_msr_offset32) |
247 | outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset32); | 237 | outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32); |
248 | if (extra_msr_offset64) | 238 | if (extra_msr_offset64) |
249 | outp += sprintf(outp, " MSR 0x%04X", extra_msr_offset64); | 239 | outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64); |
250 | if (do_nhm_cstates) | 240 | if (do_nhm_cstates) |
251 | outp += sprintf(outp, " %%c1"); | 241 | outp += sprintf(outp, " %%c1"); |
252 | if (do_nhm_cstates) | 242 | if (do_nhm_cstates) |
@@ -278,7 +268,11 @@ int dump_counters(struct thread_data *t, struct core_data *c, | |||
278 | fprintf(stderr, "aperf: %016llX\n", t->aperf); | 268 | fprintf(stderr, "aperf: %016llX\n", t->aperf); |
279 | fprintf(stderr, "mperf: %016llX\n", t->mperf); | 269 | fprintf(stderr, "mperf: %016llX\n", t->mperf); |
280 | fprintf(stderr, "c1: %016llX\n", t->c1); | 270 | fprintf(stderr, "c1: %016llX\n", t->c1); |
281 | fprintf(stderr, "msr0x%x: %08X\n", | 271 | fprintf(stderr, "msr0x%x: %08llX\n", |
272 | extra_delta_offset32, t->extra_delta32); | ||
273 | fprintf(stderr, "msr0x%x: %016llX\n", | ||
274 | extra_delta_offset64, t->extra_delta64); | ||
275 | fprintf(stderr, "msr0x%x: %08llX\n", | ||
282 | extra_msr_offset32, t->extra_msr32); | 276 | extra_msr_offset32, t->extra_msr32); |
283 | fprintf(stderr, "msr0x%x: %016llX\n", | 277 | fprintf(stderr, "msr0x%x: %016llX\n", |
284 | extra_msr_offset64, t->extra_msr64); | 278 | extra_msr_offset64, t->extra_msr64); |
@@ -385,9 +379,16 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
385 | /* TSC */ | 379 | /* TSC */ |
386 | outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); | 380 | outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); |
387 | 381 | ||
382 | /* delta */ | ||
383 | if (extra_delta_offset32) | ||
384 | outp += sprintf(outp, " %11llu", t->extra_delta32); | ||
385 | |||
386 | /* DELTA */ | ||
387 | if (extra_delta_offset64) | ||
388 | outp += sprintf(outp, " %11llu", t->extra_delta64); | ||
388 | /* msr */ | 389 | /* msr */ |
389 | if (extra_msr_offset32) | 390 | if (extra_msr_offset32) |
390 | outp += sprintf(outp, " 0x%08x", t->extra_msr32); | 391 | outp += sprintf(outp, " 0x%08llx", t->extra_msr32); |
391 | 392 | ||
392 | /* MSR */ | 393 | /* MSR */ |
393 | if (extra_msr_offset64) | 394 | if (extra_msr_offset64) |
@@ -533,8 +534,13 @@ delta_thread(struct thread_data *new, struct thread_data *old, | |||
533 | old->mperf = 1; /* divide by 0 protection */ | 534 | old->mperf = 1; /* divide by 0 protection */ |
534 | } | 535 | } |
535 | 536 | ||
537 | old->extra_delta32 = new->extra_delta32 - old->extra_delta32; | ||
538 | old->extra_delta32 &= 0xFFFFFFFF; | ||
539 | |||
540 | old->extra_delta64 = new->extra_delta64 - old->extra_delta64; | ||
541 | |||
536 | /* | 542 | /* |
537 | * Extra MSR is a snapshot, simply copy latest w/o subtracting | 543 | * Extra MSR is just a snapshot, simply copy latest w/o subtracting |
538 | */ | 544 | */ |
539 | old->extra_msr32 = new->extra_msr32; | 545 | old->extra_msr32 = new->extra_msr32; |
540 | old->extra_msr64 = new->extra_msr64; | 546 | 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 | t->mperf = 0; | 571 | t->mperf = 0; |
566 | t->c1 = 0; | 572 | t->c1 = 0; |
567 | 573 | ||
574 | t->extra_delta32 = 0; | ||
575 | t->extra_delta64 = 0; | ||
576 | |||
568 | /* tells format_counters to dump all fields from this set */ | 577 | /* tells format_counters to dump all fields from this set */ |
569 | t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; | 578 | t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; |
570 | 579 | ||
@@ -585,6 +594,9 @@ int sum_counters(struct thread_data *t, struct core_data *c, | |||
585 | average.threads.mperf += t->mperf; | 594 | average.threads.mperf += t->mperf; |
586 | average.threads.c1 += t->c1; | 595 | average.threads.c1 += t->c1; |
587 | 596 | ||
597 | average.threads.extra_delta32 += t->extra_delta32; | ||
598 | average.threads.extra_delta64 += t->extra_delta64; | ||
599 | |||
588 | /* sum per-core values only for 1st thread in core */ | 600 | /* sum per-core values only for 1st thread in core */ |
589 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) | 601 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) |
590 | return 0; | 602 | return 0; |
@@ -620,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c, | |||
620 | average.threads.mperf /= topo.num_cpus; | 632 | average.threads.mperf /= topo.num_cpus; |
621 | average.threads.c1 /= topo.num_cpus; | 633 | average.threads.c1 /= topo.num_cpus; |
622 | 634 | ||
635 | average.threads.extra_delta32 /= topo.num_cpus; | ||
636 | average.threads.extra_delta32 &= 0xFFFFFFFF; | ||
637 | |||
638 | average.threads.extra_delta64 /= topo.num_cpus; | ||
639 | |||
623 | average.cores.c3 /= topo.num_cores; | 640 | average.cores.c3 /= topo.num_cores; |
624 | average.cores.c6 /= topo.num_cores; | 641 | average.cores.c6 /= topo.num_cores; |
625 | average.cores.c7 /= topo.num_cores; | 642 | 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 | return -4; | 678 | return -4; |
662 | } | 679 | } |
663 | 680 | ||
664 | if (extra_msr_offset32) | 681 | if (extra_delta_offset32) { |
665 | if (get_msr32(cpu, extra_msr_offset32, &t->extra_msr32)) | 682 | if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32)) |
683 | return -5; | ||
684 | t->extra_delta32 &= 0xFFFFFFFF; | ||
685 | } | ||
686 | |||
687 | if (extra_delta_offset64) | ||
688 | if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64)) | ||
666 | return -5; | 689 | return -5; |
667 | 690 | ||
691 | if (extra_msr_offset32) { | ||
692 | if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32)) | ||
693 | return -5; | ||
694 | t->extra_msr32 &= 0xFFFFFFFF; | ||
695 | } | ||
696 | |||
668 | if (extra_msr_offset64) | 697 | if (extra_msr_offset64) |
669 | if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64)) | 698 | if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64)) |
670 | return -5; | 699 | return -5; |
@@ -1275,7 +1304,7 @@ void check_cpuid() | |||
1275 | 1304 | ||
1276 | void usage() | 1305 | void usage() |
1277 | { | 1306 | { |
1278 | fprintf(stderr, "%s: [-v] [-m msr#] [-M MSR#] [-i interval_sec | command ...]\n", | 1307 | fprintf(stderr, "%s: [-v][-d MSR#][-D MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", |
1279 | progname); | 1308 | progname); |
1280 | exit(1); | 1309 | exit(1); |
1281 | } | 1310 | } |
@@ -1565,7 +1594,7 @@ void cmdline(int argc, char **argv) | |||
1565 | 1594 | ||
1566 | progname = argv[0]; | 1595 | progname = argv[0]; |
1567 | 1596 | ||
1568 | while ((opt = getopt(argc, argv, "+cpsvi:m:M:")) != -1) { | 1597 | while ((opt = getopt(argc, argv, "+cpsvid:D:m:M:")) != -1) { |
1569 | switch (opt) { | 1598 | switch (opt) { |
1570 | case 'c': | 1599 | case 'c': |
1571 | show_core_only++; | 1600 | show_core_only++; |
@@ -1582,15 +1611,17 @@ void cmdline(int argc, char **argv) | |||
1582 | case 'i': | 1611 | case 'i': |
1583 | interval_sec = atoi(optarg); | 1612 | interval_sec = atoi(optarg); |
1584 | break; | 1613 | break; |
1614 | case 'd': | ||
1615 | sscanf(optarg, "%x", &extra_delta_offset32); | ||
1616 | break; | ||
1617 | case 'D': | ||
1618 | sscanf(optarg, "%x", &extra_delta_offset64); | ||
1619 | break; | ||
1585 | case 'm': | 1620 | case 'm': |
1586 | sscanf(optarg, "%x", &extra_msr_offset32); | 1621 | sscanf(optarg, "%x", &extra_msr_offset32); |
1587 | if (verbose > 1) | ||
1588 | fprintf(stderr, "msr 0x%X\n", extra_msr_offset32); | ||
1589 | break; | 1622 | break; |
1590 | case 'M': | 1623 | case 'M': |
1591 | sscanf(optarg, "%x", &extra_msr_offset64); | 1624 | sscanf(optarg, "%x", &extra_msr_offset64); |
1592 | if (verbose > 1) | ||
1593 | fprintf(stderr, "MSR 0x%X\n", extra_msr_offset64); | ||
1594 | break; | 1625 | break; |
1595 | default: | 1626 | default: |
1596 | usage(); | 1627 | usage(); |