Commit b5e82233 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-tools'

* pm-tools:
  tools/power turbostat: relax dependency on APERF_MSR
  tools/power turbostat: relax dependency on invariant TSC
  tools/power turbostat: decode MSR_*_PERF_LIMIT_REASONS
  tools/power turbostat: relax dependency on root permission
  cpupower Makefile change to help run the tool without 'make install'
parents 7bc95d4e 994b7f10
...@@ -152,6 +152,10 @@ ...@@ -152,6 +152,10 @@
#define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668 #define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668
#define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669 #define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669
#define MSR_CORE_PERF_LIMIT_REASONS 0x00000690
#define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0
#define MSR_RING_PERF_LIMIT_REASONS 0x000006B1
/* Hardware P state interface */ /* Hardware P state interface */
#define MSR_PPERF 0x0000064e #define MSR_PPERF 0x0000064e
#define MSR_PERF_LIMIT_REASONS 0x0000064f #define MSR_PERF_LIMIT_REASONS 0x0000064f
......
...@@ -209,7 +209,7 @@ $(OUTPUT)%.o: %.c ...@@ -209,7 +209,7 @@ $(OUTPUT)%.o: %.c
$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ) $(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ)
$(ECHO) " CC " $@ $(ECHO) " CC " $@
$(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@ $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -Wl,-rpath=./ -lrt -lpci -L$(OUTPUT) -o $@
$(QUIET) $(STRIPCMD) $@ $(QUIET) $(STRIPCMD) $@
$(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC) $(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC)
......
...@@ -12,16 +12,16 @@ turbostat \- Report processor frequency and idle statistics ...@@ -12,16 +12,16 @@ turbostat \- Report processor frequency and idle statistics
.RB [ "\-i interval_sec" ] .RB [ "\-i interval_sec" ]
.SH DESCRIPTION .SH DESCRIPTION
\fBturbostat \fP reports processor topology, frequency, \fBturbostat \fP reports processor topology, frequency,
idle power-state statistics, temperature and power on modern X86 processors. idle power-state statistics, temperature and power on X86 processors.
Either \fBcommand\fP is forked and statistics are printed There are two ways to invoke turbostat.
upon its completion, or statistics are printed periodically. The first method is to supply a
\fBcommand\fP, which is forked and statistics are printed
\fBturbostat \fP upon its completion.
must be run on root, and The second method is to omit the command,
minimally requires that the processor and turbodstat will print statistics every 5 seconds.
supports an "invariant" TSC, plus the APERF and MPERF MSRs. The 5-second interval can changed using the -i option.
Additional information is reported depending on hardware counter support.
Some information is not availalbe on older processors.
.SS Options .SS Options
The \fB-p\fP option limits output to the 1st thread in 1st core of each package. The \fB-p\fP option limits output to the 1st thread in 1st core of each package.
.PP .PP
...@@ -130,12 +130,13 @@ cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1) ...@@ -130,12 +130,13 @@ cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1)
... ...
.fi .fi
The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency
available at the minimum package voltage. The \fBTSC frequency\fP is the nominal available at the minimum package voltage. The \fBTSC frequency\fP is the base
maximum frequency of the processor if turbo-mode were not available. This frequency frequency of the processor -- this should match the brand string
in /proc/cpuinfo. This base frequency
should be sustainable on all CPUs indefinitely, given nominal power and cooling. should be sustainable on all CPUs indefinitely, given nominal power and cooling.
The remaining rows show what maximum turbo frequency is possible The remaining rows show what maximum turbo frequency is possible
depending on the number of idle cores. Note that this information is depending on the number of idle cores. Note that not all information is
not available on all processors. available on all processors.
.SH FORK EXAMPLE .SH FORK EXAMPLE
If turbostat is invoked with a command, it will fork that command If turbostat is invoked with a command, it will fork that command
and output the statistics gathered when the command exits. and output the statistics gathered when the command exits.
...@@ -176,6 +177,11 @@ not including any non-busy idle time. ...@@ -176,6 +177,11 @@ not including any non-busy idle time.
.B "turbostat " .B "turbostat "
must be run as root. must be run as root.
Alternatively, non-root users can be enabled to run turbostat this way:
# setcap cap_sys_rawio=ep ./turbostat
# chmod +r /dev/cpu/*/msr
.B "turbostat " .B "turbostat "
reads hardware counters, but doesn't write them. reads hardware counters, but doesn't write them.
...@@ -184,15 +190,33 @@ multiple invocations of itself. ...@@ -184,15 +190,33 @@ multiple invocations of itself.
\fBturbostat \fP \fBturbostat \fP
may work poorly on Linux-2.6.20 through 2.6.29, may work poorly on Linux-2.6.20 through 2.6.29,
as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF MSRs
in those kernels. in those kernels.
If the TSC column does not make sense, then AVG_MHz = APERF_delta/measurement_interval. This is the actual
the other numbers will also make no sense. number of elapsed cycles divided by the entire sample interval --
Turbostat is lightweight, and its data collection is not atomic. including idle time. Note that this calculation is resiliant
These issues are usually caused by an extremely short measurement to systems lacking a non-stop TSC.
interval (much less than 1 second), or system activity that prevents
turbostat from being able to run on all CPUS to quickly collect data. TSC_MHz = TSC_delta/measurement_interval.
On a system with an invariant TSC, this value will be constant
and will closely match the base frequency value shown
in the brand string in /proc/cpuinfo. On a system where
the TSC stops in idle, TSC_MHz will drop
below the processor's base frequency.
%Busy = MPERF_delta/TSC_delta
Bzy_MHz = TSC_delta/APERF_delta/MPERF_delta/measurement_interval
Note that these calculations depend on TSC_delta, so they
are not reliable during intervals when TSC_MHz is not running at the base frequency.
Turbostat data collection is not atomic.
Extremely short measurement intervals (much less than 1 second),
or system activity that prevents turbostat from being able
to run on all CPUS to quickly collect data, will result in
inconsistent results.
The APERF, MPERF MSRs are defined to count non-halted cycles. The APERF, MPERF MSRs are defined to count non-halted cycles.
Although it is not guaranteed by the architecture, turbostat assumes Although it is not guaranteed by the architecture, turbostat assumes
......
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
#include <ctype.h> #include <ctype.h>
#include <sched.h> #include <sched.h>
#include <cpuid.h> #include <cpuid.h>
#include <linux/capability.h>
#include <errno.h>
char *proc_stat = "/proc/stat"; char *proc_stat = "/proc/stat";
unsigned int interval_sec = 5; /* set with -i interval_sec */ unsigned int interval_sec = 5; /* set with -i interval_sec */
...@@ -59,8 +61,8 @@ unsigned int has_epb; ...@@ -59,8 +61,8 @@ unsigned int has_epb;
unsigned int units = 1000000; /* MHz etc */ unsigned int units = 1000000; /* MHz etc */
unsigned int genuine_intel; unsigned int genuine_intel;
unsigned int has_invariant_tsc; unsigned int has_invariant_tsc;
unsigned int do_nehalem_platform_info; unsigned int do_nhm_platform_info;
unsigned int do_nehalem_turbo_ratio_limit; unsigned int do_nhm_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;
...@@ -81,6 +83,9 @@ unsigned int tcc_activation_temp; ...@@ -81,6 +83,9 @@ unsigned int tcc_activation_temp;
unsigned int tcc_activation_temp_override; unsigned int tcc_activation_temp_override;
double rapl_power_units, rapl_energy_units, rapl_time_units; double rapl_power_units, rapl_energy_units, rapl_time_units;
double rapl_joule_counter_range; double rapl_joule_counter_range;
unsigned int do_core_perf_limit_reasons;
unsigned int do_gfx_perf_limit_reasons;
unsigned int do_ring_perf_limit_reasons;
#define RAPL_PKG (1 << 0) #define RAPL_PKG (1 << 0)
/* 0x610 MSR_PKG_POWER_LIMIT */ /* 0x610 MSR_PKG_POWER_LIMIT */
...@@ -251,15 +256,13 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) ...@@ -251,15 +256,13 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
sprintf(pathname, "/dev/cpu/%d/msr", cpu); sprintf(pathname, "/dev/cpu/%d/msr", cpu);
fd = open(pathname, O_RDONLY); fd = open(pathname, O_RDONLY);
if (fd < 0) if (fd < 0)
return -1; err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
retval = pread(fd, msr, sizeof *msr, offset); retval = pread(fd, msr, sizeof *msr, offset);
close(fd); close(fd);
if (retval != sizeof *msr) { if (retval != sizeof *msr)
fprintf(stderr, "%s offset 0x%llx read failed\n", pathname, (unsigned long long)offset); err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset);
return -1;
}
return 0; return 0;
} }
...@@ -281,7 +284,7 @@ void print_header(void) ...@@ -281,7 +284,7 @@ void print_header(void)
outp += sprintf(outp, " CPU"); outp += sprintf(outp, " CPU");
if (has_aperf) if (has_aperf)
outp += sprintf(outp, " Avg_MHz"); outp += sprintf(outp, " Avg_MHz");
if (do_nhm_cstates) if (has_aperf)
outp += sprintf(outp, " %%Busy"); outp += sprintf(outp, " %%Busy");
if (has_aperf) if (has_aperf)
outp += sprintf(outp, " Bzy_MHz"); outp += sprintf(outp, " Bzy_MHz");
...@@ -337,7 +340,7 @@ void print_header(void) ...@@ -337,7 +340,7 @@ void print_header(void)
outp += sprintf(outp, " PKG_%%"); outp += sprintf(outp, " PKG_%%");
if (do_rapl & RAPL_DRAM_PERF_STATUS) if (do_rapl & RAPL_DRAM_PERF_STATUS)
outp += sprintf(outp, " RAM_%%"); outp += sprintf(outp, " RAM_%%");
} else { } else if (do_rapl && rapl_joules) {
if (do_rapl & RAPL_PKG) if (do_rapl & RAPL_PKG)
outp += sprintf(outp, " Pkg_J"); outp += sprintf(outp, " Pkg_J");
if (do_rapl & RAPL_CORES) if (do_rapl & RAPL_CORES)
...@@ -457,25 +460,25 @@ int format_counters(struct thread_data *t, struct core_data *c, ...@@ -457,25 +460,25 @@ int format_counters(struct thread_data *t, struct core_data *c,
outp += sprintf(outp, "%8d", t->cpu_id); outp += sprintf(outp, "%8d", t->cpu_id);
} }
/* AvgMHz */ /* Avg_MHz */
if (has_aperf) if (has_aperf)
outp += sprintf(outp, "%8.0f", outp += sprintf(outp, "%8.0f",
1.0 / units * t->aperf / interval_float); 1.0 / units * t->aperf / interval_float);
/* %c0 */ /* %Busy */
if (do_nhm_cstates) { if (has_aperf) {
if (!skip_c0) if (!skip_c0)
outp += sprintf(outp, "%8.2f", 100.0 * t->mperf/t->tsc); outp += sprintf(outp, "%8.2f", 100.0 * t->mperf/t->tsc);
else else
outp += sprintf(outp, "********"); outp += sprintf(outp, "********");
} }
/* BzyMHz */ /* Bzy_MHz */
if (has_aperf) if (has_aperf)
outp += sprintf(outp, "%8.0f", outp += sprintf(outp, "%8.0f",
1.0 * t->tsc / units * t->aperf / t->mperf / interval_float); 1.0 * t->tsc / units * t->aperf / t->mperf / interval_float);
/* TSC */ /* TSC_MHz */
outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float); outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float);
/* SMI */ /* SMI */
...@@ -561,7 +564,7 @@ int format_counters(struct thread_data *t, struct core_data *c, ...@@ -561,7 +564,7 @@ int format_counters(struct thread_data *t, struct core_data *c,
outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
if (do_rapl & RAPL_DRAM_PERF_STATUS) if (do_rapl & RAPL_DRAM_PERF_STATUS)
outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
} else { } else if (do_rapl && rapl_joules) {
if (do_rapl & RAPL_PKG) if (do_rapl & RAPL_PKG)
outp += sprintf(outp, fmt8, outp += sprintf(outp, fmt8,
p->energy_pkg * rapl_energy_units); p->energy_pkg * rapl_energy_units);
...@@ -578,8 +581,8 @@ int format_counters(struct thread_data *t, struct core_data *c, ...@@ -578,8 +581,8 @@ int format_counters(struct thread_data *t, struct core_data *c,
outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
if (do_rapl & RAPL_DRAM_PERF_STATUS) if (do_rapl & RAPL_DRAM_PERF_STATUS)
outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
outp += sprintf(outp, fmt8, interval_float);
outp += sprintf(outp, fmt8, interval_float);
} }
done: done:
outp += sprintf(outp, "\n"); outp += sprintf(outp, "\n");
...@@ -670,24 +673,26 @@ delta_thread(struct thread_data *new, struct thread_data *old, ...@@ -670,24 +673,26 @@ delta_thread(struct thread_data *new, struct thread_data *old,
old->c1 = new->c1 - old->c1; old->c1 = new->c1 - old->c1;
if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) { if (has_aperf) {
old->aperf = new->aperf - old->aperf; if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) {
old->mperf = new->mperf - old->mperf; old->aperf = new->aperf - old->aperf;
} else { old->mperf = new->mperf - old->mperf;
} else {
if (!aperf_mperf_unstable) { if (!aperf_mperf_unstable) {
fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname); fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
fprintf(stderr, "* Frequency results do not cover entire interval *\n"); fprintf(stderr, "* Frequency results do not cover entire interval *\n");
fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n"); fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
aperf_mperf_unstable = 1; aperf_mperf_unstable = 1;
}
/*
* mperf delta is likely a huge "positive" number
* can not use it for calculating c0 time
*/
skip_c0 = 1;
skip_c1 = 1;
} }
/*
* mperf delta is likely a huge "positive" number
* can not use it for calculating c0 time
*/
skip_c0 = 1;
skip_c1 = 1;
} }
...@@ -1019,7 +1024,7 @@ void print_verbose_header(void) ...@@ -1019,7 +1024,7 @@ void print_verbose_header(void)
unsigned long long msr; unsigned long long msr;
unsigned int ratio; unsigned int ratio;
if (!do_nehalem_platform_info) if (!do_nhm_platform_info)
return; return;
get_msr(0, MSR_NHM_PLATFORM_INFO, &msr); get_msr(0, MSR_NHM_PLATFORM_INFO, &msr);
...@@ -1132,7 +1137,7 @@ void print_verbose_header(void) ...@@ -1132,7 +1137,7 @@ void print_verbose_header(void)
} }
fprintf(stderr, ")\n"); fprintf(stderr, ")\n");
if (!do_nehalem_turbo_ratio_limit) if (!do_nhm_turbo_ratio_limit)
return; return;
get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr); get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
...@@ -1178,6 +1183,7 @@ void print_verbose_header(void) ...@@ -1178,6 +1183,7 @@ void print_verbose_header(void)
if (ratio) if (ratio)
fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
ratio, bclk, ratio * bclk); ratio, bclk, ratio * bclk);
} }
void free_all_buffers(void) void free_all_buffers(void)
...@@ -1458,17 +1464,60 @@ void check_dev_msr() ...@@ -1458,17 +1464,60 @@ void check_dev_msr()
struct stat sb; struct stat sb;
if (stat("/dev/cpu/0/msr", &sb)) if (stat("/dev/cpu/0/msr", &sb))
err(-5, "no /dev/cpu/0/msr\n" err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
"Try \"# modprobe msr\"");
} }
void check_super_user() void check_permissions()
{ {
if (getuid() != 0) struct __user_cap_header_struct cap_header_data;
errx(-6, "must be root"); cap_user_header_t cap_header = &cap_header_data;
struct __user_cap_data_struct cap_data_data;
cap_user_data_t cap_data = &cap_data_data;
extern int capget(cap_user_header_t hdrp, cap_user_data_t datap);
int do_exit = 0;
/* check for CAP_SYS_RAWIO */
cap_header->pid = getpid();
cap_header->version = _LINUX_CAPABILITY_VERSION;
if (capget(cap_header, cap_data) < 0)
err(-6, "capget(2) failed");
if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
do_exit++;
warnx("capget(CAP_SYS_RAWIO) failed,"
" try \"# setcap cap_sys_rawio=ep %s\"", progname);
}
/* test file permissions */
if (euidaccess("/dev/cpu/0/msr", R_OK)) {
do_exit++;
warn("/dev/cpu/0/msr open failed, try chown or chmod +r /dev/cpu/*/msr");
}
/* if all else fails, thell them to be root */
if (do_exit)
if (getuid() != 0)
warnx("... or simply run as root");
if (do_exit)
exit(-6);
} }
int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) /*
* NHM adds support for additional MSRs:
*
* MSR_SMI_COUNT 0x00000034
*
* MSR_NHM_PLATFORM_INFO 0x000000ce
* MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2
*
* MSR_PKG_C3_RESIDENCY 0x000003f8
* MSR_PKG_C6_RESIDENCY 0x000003f9
* MSR_CORE_C3_RESIDENCY 0x000003fc
* MSR_CORE_C6_RESIDENCY 0x000003fd
*
*/
int has_nhm_msrs(unsigned int family, unsigned int model)
{ {
if (!genuine_intel) if (!genuine_intel)
return 0; return 0;
...@@ -1495,13 +1544,27 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) ...@@ -1495,13 +1544,27 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
case 0x3D: /* BDW */ case 0x3D: /* BDW */
case 0x4F: /* BDX */ case 0x4F: /* BDX */
case 0x56: /* BDX-DE */ case 0x56: /* BDX-DE */
return 1;
case 0x2E: /* Nehalem-EX Xeon - Beckton */ case 0x2E: /* Nehalem-EX Xeon - Beckton */
case 0x2F: /* Westmere-EX Xeon - Eagleton */ case 0x2F: /* Westmere-EX Xeon - Eagleton */
return 1;
default: default:
return 0; return 0;
} }
} }
int has_nhm_turbo_ratio_limit(unsigned int family, unsigned int model)
{
if (!has_nhm_msrs(family, model))
return 0;
switch (model) {
/* Nehalem compatible, but do not include turbo-ratio limit support */
case 0x2E: /* Nehalem-EX Xeon - Beckton */
case 0x2F: /* Westmere-EX Xeon - Eagleton */
return 0;
default:
return 1;
}
}
int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model) int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
{ {
if (!genuine_intel) if (!genuine_intel)
...@@ -1564,6 +1627,103 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p) ...@@ -1564,6 +1627,103 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
return 0; return 0;
} }
/*
* print_perf_limit()
*/
int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data *p)
{
unsigned long long msr;
int cpu;
cpu = t->cpu_id;
/* per-package */
if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
return 0;
if (cpu_migrate(cpu)) {
fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
return -1;
}
if (do_core_perf_limit_reasons) {
get_msr(cpu, MSR_CORE_PERF_LIMIT_REASONS, &msr);
fprintf(stderr, "cpu%d: MSR_CORE_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
fprintf(stderr, " (Active: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
(msr & 1 << 0) ? "PROCHOT, " : "",
(msr & 1 << 1) ? "ThermStatus, " : "",
(msr & 1 << 2) ? "bit2, " : "",
(msr & 1 << 4) ? "Graphics, " : "",
(msr & 1 << 5) ? "Auto-HWP, " : "",
(msr & 1 << 6) ? "VR-Therm, " : "",
(msr & 1 << 8) ? "Amps, " : "",
(msr & 1 << 9) ? "CorePwr, " : "",
(msr & 1 << 10) ? "PkgPwrL1, " : "",
(msr & 1 << 11) ? "PkgPwrL2, " : "",
(msr & 1 << 12) ? "MultiCoreTurbo, " : "",
(msr & 1 << 13) ? "Transitions, " : "",
(msr & 1 << 14) ? "bit14, " : "",
(msr & 1 << 15) ? "bit15, " : "");
fprintf(stderr, " (Logged: %s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
(msr & 1 << 16) ? "PROCHOT, " : "",
(msr & 1 << 17) ? "ThermStatus, " : "",
(msr & 1 << 18) ? "bit18, " : "",
(msr & 1 << 20) ? "Graphics, " : "",
(msr & 1 << 21) ? "Auto-HWP, " : "",
(msr & 1 << 22) ? "VR-Therm, " : "",
(msr & 1 << 24) ? "Amps, " : "",
(msr & 1 << 25) ? "CorePwr, " : "",
(msr & 1 << 26) ? "PkgPwrL1, " : "",
(msr & 1 << 27) ? "PkgPwrL2, " : "",
(msr & 1 << 28) ? "MultiCoreTurbo, " : "",
(msr & 1 << 29) ? "Transitions, " : "",
(msr & 1 << 30) ? "bit30, " : "",
(msr & 1 << 31) ? "bit31, " : "");
}
if (do_gfx_perf_limit_reasons) {
get_msr(cpu, MSR_GFX_PERF_LIMIT_REASONS, &msr);
fprintf(stderr, "cpu%d: MSR_GFX_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
fprintf(stderr, " (Active: %s%s%s%s%s%s%s%s)",
(msr & 1 << 0) ? "PROCHOT, " : "",
(msr & 1 << 1) ? "ThermStatus, " : "",
(msr & 1 << 4) ? "Graphics, " : "",
(msr & 1 << 6) ? "VR-Therm, " : "",
(msr & 1 << 8) ? "Amps, " : "",
(msr & 1 << 9) ? "GFXPwr, " : "",
(msr & 1 << 10) ? "PkgPwrL1, " : "",
(msr & 1 << 11) ? "PkgPwrL2, " : "");
fprintf(stderr, " (Logged: %s%s%s%s%s%s%s%s)\n",
(msr & 1 << 16) ? "PROCHOT, " : "",
(msr & 1 << 17) ? "ThermStatus, " : "",
(msr & 1 << 20) ? "Graphics, " : "",
(msr & 1 << 22) ? "VR-Therm, " : "",
(msr & 1 << 24) ? "Amps, " : "",
(msr & 1 << 25) ? "GFXPwr, " : "",
(msr & 1 << 26) ? "PkgPwrL1, " : "",
(msr & 1 << 27) ? "PkgPwrL2, " : "");
}
if (do_ring_perf_limit_reasons) {
get_msr(cpu, MSR_RING_PERF_LIMIT_REASONS, &msr);
fprintf(stderr, "cpu%d: MSR_RING_PERF_LIMIT_REASONS, 0x%08llx", cpu, msr);
fprintf(stderr, " (Active: %s%s%s%s%s%s)",
(msr & 1 << 0) ? "PROCHOT, " : "",
(msr & 1 << 1) ? "ThermStatus, " : "",
(msr & 1 << 6) ? "VR-Therm, " : "",
(msr & 1 << 8) ? "Amps, " : "",
(msr & 1 << 10) ? "PkgPwrL1, " : "",
(msr & 1 << 11) ? "PkgPwrL2, " : "");
fprintf(stderr, " (Logged: %s%s%s%s%s%s)\n",
(msr & 1 << 16) ? "PROCHOT, " : "",
(msr & 1 << 17) ? "ThermStatus, " : "",
(msr & 1 << 22) ? "VR-Therm, " : "",
(msr & 1 << 24) ? "Amps, " : "",
(msr & 1 << 26) ? "PkgPwrL1, " : "",
(msr & 1 << 27) ? "PkgPwrL2, " : "");
}
return 0;
}
#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */ #define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */
#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */ #define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */
...@@ -1653,6 +1813,27 @@ void rapl_probe(unsigned int family, unsigned int model) ...@@ -1653,6 +1813,27 @@ void rapl_probe(unsigned int family, unsigned int model)
return; return;
} }
void perf_limit_reasons_probe(family, model)
{
if (!genuine_intel)
return;
if (family != 6)
return;
switch (model) {
case 0x3C: /* HSW */
case 0x45: /* HSW */
case 0x46: /* HSW */
do_gfx_perf_limit_reasons = 1;
case 0x3F: /* HSX */
do_core_perf_limit_reasons = 1;
do_ring_perf_limit_reasons = 1;
default:
return;
}
}
int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p) int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p)
{ {
unsigned long long msr; unsigned long long msr;
...@@ -1842,8 +2023,15 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p) ...@@ -1842,8 +2023,15 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
return 0; return 0;
} }
/*
* SNB adds support for additional MSRs:
*
* MSR_PKG_C7_RESIDENCY 0x000003fa
* MSR_CORE_C7_RESIDENCY 0x000003fe
* MSR_PKG_C2_RESIDENCY 0x0000060d
*/
int is_snb(unsigned int family, unsigned int model) int has_snb_msrs(unsigned int family, unsigned int model)
{ {
if (!genuine_intel) if (!genuine_intel)
return 0; return 0;
...@@ -1865,7 +2053,14 @@ int is_snb(unsigned int family, unsigned int model) ...@@ -1865,7 +2053,14 @@ int is_snb(unsigned int family, unsigned int model)
return 0; return 0;
} }
int has_c8_c9_c10(unsigned int family, unsigned int model) /*
* HSW adds support for additional MSRs:
*
* MSR_PKG_C8_RESIDENCY 0x00000630
* MSR_PKG_C9_RESIDENCY 0x00000631
* MSR_PKG_C10_RESIDENCY 0x00000632
*/
int has_hsw_msrs(unsigned int family, unsigned int model)
{ {
if (!genuine_intel) if (!genuine_intel)
return 0; return 0;
...@@ -1917,7 +2112,7 @@ double slm_bclk(void) ...@@ -1917,7 +2112,7 @@ double slm_bclk(void)
double discover_bclk(unsigned int family, unsigned int model) double discover_bclk(unsigned int family, unsigned int model)
{ {
if (is_snb(family, model)) if (has_snb_msrs(family, model))
return 100.00; return 100.00;
else if (is_slm(family, model)) else if (is_slm(family, model))
return slm_bclk(); return slm_bclk();
...@@ -1965,7 +2160,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk ...@@ -1965,7 +2160,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
} }
/* Temperature Target MSR is Nehalem and newer only */ /* Temperature Target MSR is Nehalem and newer only */
if (!do_nehalem_platform_info) if (!do_nhm_platform_info)
goto guess; goto guess;
if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr)) if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))
...@@ -2029,18 +2224,15 @@ void check_cpuid() ...@@ -2029,18 +2224,15 @@ void check_cpuid()
ebx = ecx = edx = 0; ebx = ecx = edx = 0;
__get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx); __get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx);
if (max_level < 0x80000007) if (max_level >= 0x80000007) {
errx(1, "CPUID: no invariant TSC (max_level 0x%x)", max_level);
/* /*
* Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
* this check is valid for both Intel and AMD * this check is valid for both Intel and AMD
*/ */
__get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
has_invariant_tsc = edx & (1 << 8); has_invariant_tsc = edx & (1 << 8);
}
if (!has_invariant_tsc)
errx(1, "No invariant TSC");
/* /*
* APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
...@@ -2054,26 +2246,22 @@ void check_cpuid() ...@@ -2054,26 +2246,22 @@ void check_cpuid()
has_epb = ecx & (1 << 3); has_epb = ecx & (1 << 3);
if (verbose) if (verbose)
fprintf(stderr, "CPUID(6): %s%s%s%s\n", fprintf(stderr, "CPUID(6): %sAPERF, %sDTS, %sPTM, %sEPB\n",
has_aperf ? "APERF" : "No APERF!", has_aperf ? "" : "No ",
do_dts ? ", DTS" : "", do_dts ? "" : "No ",
do_ptm ? ", PTM": "", do_ptm ? "" : "No ",
has_epb ? ", EPB": ""); has_epb ? "" : "No ");
if (!has_aperf) do_nhm_platform_info = do_nhm_cstates = do_smi = has_nhm_msrs(family, model);
errx(-1, "No APERF"); do_snb_cstates = has_snb_msrs(family, model);
do_c8_c9_c10 = has_hsw_msrs(family, model);
do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
do_smi = do_nhm_cstates;
do_snb_cstates = is_snb(family, model);
do_c8_c9_c10 = has_c8_c9_c10(family, model);
do_slm_cstates = is_slm(family, model); do_slm_cstates = is_slm(family, model);
bclk = discover_bclk(family, model); bclk = discover_bclk(family, model);
do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); do_nhm_turbo_ratio_limit = has_nhm_turbo_ratio_limit(family, model);
do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model);
rapl_probe(family, model); rapl_probe(family, model);
perf_limit_reasons_probe(family, model);
return; return;
} }
...@@ -2299,10 +2487,9 @@ void setup_all_buffers(void) ...@@ -2299,10 +2487,9 @@ void setup_all_buffers(void)
void turbostat_init() void turbostat_init()
{ {
check_cpuid();
check_dev_msr(); check_dev_msr();
check_super_user(); check_permissions();
check_cpuid();
setup_all_buffers(); setup_all_buffers();
...@@ -2312,6 +2499,9 @@ void turbostat_init() ...@@ -2312,6 +2499,9 @@ void turbostat_init()
if (verbose) if (verbose)
for_all_cpus(print_epb, ODD_COUNTERS); for_all_cpus(print_epb, ODD_COUNTERS);
if (verbose)
for_all_cpus(print_perf_limit, ODD_COUNTERS);
if (verbose) if (verbose)
for_all_cpus(print_rapl, ODD_COUNTERS); for_all_cpus(print_rapl, ODD_COUNTERS);
...@@ -2441,7 +2631,7 @@ int main(int argc, char **argv) ...@@ -2441,7 +2631,7 @@ int main(int argc, char **argv)
cmdline(argc, argv); cmdline(argc, argv);
if (verbose) if (verbose)
fprintf(stderr, "turbostat v3.7 Feb 6, 2014" fprintf(stderr, "turbostat v3.9 23-Jan, 2015"
" - Len Brown <lenb@kernel.org>\n"); " - Len Brown <lenb@kernel.org>\n");
turbostat_init(); turbostat_init();
......
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