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 | |
| 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>
| -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(); |
