tools/power turbostat: add [-m MSR#] option
authorLen Brown <len.brown@intel.com>
Sat, 22 Sep 2012 03:45:46 +0000 (23:45 -0400)
committerLen Brown <len.brown@intel.com>
Wed, 26 Sep 2012 22:17:21 +0000 (18:17 -0400)
-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>
tools/power/x86/turbostat/turbostat.8
tools/power/x86/turbostat/turbostat.c

index 74e44507dfe9ed9b4c376b075a7dceadb0a0959f..8e7b29af78f65cd17169f0030d81b952528d79f3 100644 (file)
@@ -6,12 +6,14 @@ turbostat \- Report processor frequency and idle statistics
 .B turbostat
 .RB [ "\-s" ]
 .RB [ "\-v" ]
 .B turbostat
 .RB [ "\-s" ]
 .RB [ "\-v" ]
+.RB [ "\-m MSR#" ]
 .RB [ "\-M MSR#" ]
 .RB command
 .br
 .B turbostat
 .RB [ "\-s" ]
 .RB [ "\-v" ]
 .RB [ "\-M MSR#" ]
 .RB command
 .br
 .B turbostat
 .RB [ "\-s" ]
 .RB [ "\-v" ]
+.RB [ "\-m MSR#" ]
 .RB [ "\-M MSR#" ]
 .RB [ "\-i interval_sec" ]
 .SH DESCRIPTION
 .RB [ "\-M MSR#" ]
 .RB [ "\-i interval_sec" ]
 .SH DESCRIPTION
@@ -35,7 +37,10 @@ The \fB-p\fP option limits output to the 1st thread in each package.
 .PP
 The \fB-v\fP option increases verbosity.
 .PP
 .PP
 The \fB-v\fP option increases verbosity.
 .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.
 .PP
 The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
 in addition to the usual frequency and idle statistics.
 .PP
 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
 in those kernels.
 
 as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
 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.
 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.
 The APERF, MPERF MSRs are defined to count non-halted cycles.
 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.
index 5ce88dd8c95a059aa01313109cd9f871574c9d85..946e9ab48edbc6ddac367d215c798f27002d2e96 100644 (file)
@@ -63,7 +63,8 @@ unsigned int has_invariant_tsc;
 unsigned int do_nehalem_platform_info;
 unsigned int do_nehalem_turbo_ratio_limit;
 unsigned int do_ivt_turbo_ratio_limit;
 unsigned int do_nehalem_platform_info;
 unsigned int do_nehalem_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;
 unsigned int show_pkg;
 unsigned int show_core;
 double bclk;
 unsigned int show_pkg;
 unsigned int show_core;
@@ -84,7 +85,8 @@ struct thread_data {
        unsigned long long aperf;
        unsigned long long mperf;
        unsigned long long c1;  /* derived */
        unsigned long long aperf;
        unsigned long long mperf;
        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 flags;
 #define CPU_IS_FIRST_THREAD_IN_CORE    0x2
        unsigned int cpu_id;
        unsigned int flags;
 #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)
 {
        if (show_pkg)
 void print_header(void)
 {
        if (show_pkg)
@@ -223,8 +243,10 @@ void print_header(void)
        if (has_aperf)
                outp += sprintf(outp, "  GHz");
        outp += sprintf(outp, "  TSC");
        if (has_aperf)
                outp += sprintf(outp, "  GHz");
        outp += sprintf(outp, "  TSC");
-       if (extra_msr_offset)
-               outp += sprintf(outp, "          MSR 0x%04X", extra_msr_offset);
+       if (extra_msr_offset32)
+               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)
                outp += sprintf(outp, "    %%c1");
        if (do_nhm_cstates)
        if (do_nhm_cstates)
                outp += sprintf(outp, "    %%c1");
        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, "mperf: %016llX\n", t->mperf);
                fprintf(stderr, "c1: %016llX\n", t->c1);
                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",
+                       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 */
        outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
 
        /* TSC */
        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)
-               outp += sprintf(outp, "  0x%016llx", t->extra_msr);
+       if (extra_msr_offset64)
+               outp += sprintf(outp, "  0x%016llx", t->extra_msr64);
 
        if (do_nhm_cstates) {
                if (!skip_c1)
 
        if (do_nhm_cstates) {
                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 (get_msr(cpu, extra_msr_offset, &t->extra_msr))
+       if (extra_msr_offset32)
+               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;
 
        /* collect core counters only for 1st thread in core */
                        return -5;
 
        /* 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);
        exit(1);
 }
                progname);
        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) {
                case 'c':
                        show_core_only++;
                switch (opt) {
                case 'c':
                        show_core_only++;
@@ -1549,10 +1582,15 @@ void cmdline(int argc, char **argv)
                case 'i':
                        interval_sec = atoi(optarg);
                        break;
                case 'i':
                        interval_sec = atoi(optarg);
                        break;
+               case 'm':
+                       sscanf(optarg, "%x", &extra_msr_offset32);
+                       if (verbose > 1)
+                               fprintf(stderr, "msr 0x%X\n", extra_msr_offset32);
+                       break;
                case 'M':
                case 'M':
-                       sscanf(optarg, "%x", &extra_msr_offset);
+                       sscanf(optarg, "%x", &extra_msr_offset64);
                        if (verbose > 1)
                        if (verbose > 1)
-                               fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
+                               fprintf(stderr, "MSR 0x%X\n", extra_msr_offset64);
                        break;
                default:
                        usage();
                        break;
                default:
                        usage();