Skip to content

Commit

Permalink
tools/power turbostat: relax dependency on invariant TSC
Browse files Browse the repository at this point in the history
Turbostat can be useful on systems that do not support invariant TSC,
so allow it to run on those systgems.

All arithmetic in turbostat using the TSC value is per-processsor,
so it does not depend on the TSC values being in sync acrosss processors.

Turbostat uses gettimeofday() for the measurement interval
rather than using the TSC directly, so that key metric
is also immune from variable TSC.

Turbostat prints a TSC sanity check column:

TSC_MHz = TSC_delta/interval

If this column is constant and is close to the processor
base frequency, then the TSC is behaving properly.

The other key turbostat columns are calculated this way:

Avg_Mhz = APERF_delta/interval

%Busy = MPERF_delta/TSC_delta

Bzy_MHz = TSC_delta/APERF_delta/MPERF_delta/interval

Tested on Core2 and Core2-Xeon, and so this patch includes
a few other changes to remove the assumption that target
systems are Nehalem and newer.

Signed-off-by: Len Brown <len.brown@intel.com>
  • Loading branch information
Len Brown committed Feb 9, 2015
1 parent 3a9a941 commit d789944
Showing 1 changed file with 75 additions and 39 deletions.
114 changes: 75 additions & 39 deletions tools/power/x86/turbostat/turbostat.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ unsigned int has_epb;
unsigned int units = 1000000; /* MHz etc */
unsigned int genuine_intel;
unsigned int has_invariant_tsc;
unsigned int do_nehalem_platform_info;
unsigned int do_nehalem_turbo_ratio_limit;
unsigned int do_nhm_platform_info;
unsigned int do_nhm_turbo_ratio_limit;
unsigned int do_ivt_turbo_ratio_limit;
unsigned int extra_msr_offset32;
unsigned int extra_msr_offset64;
Expand Down Expand Up @@ -284,7 +284,7 @@ void print_header(void)
outp += sprintf(outp, " CPU");
if (has_aperf)
outp += sprintf(outp, " Avg_MHz");
if (do_nhm_cstates)
if (has_aperf)
outp += sprintf(outp, " %%Busy");
if (has_aperf)
outp += sprintf(outp, " Bzy_MHz");
Expand Down Expand Up @@ -340,7 +340,7 @@ void print_header(void)
outp += sprintf(outp, " PKG_%%");
if (do_rapl & RAPL_DRAM_PERF_STATUS)
outp += sprintf(outp, " RAM_%%");
} else {
} else if (do_rapl && rapl_joules) {
if (do_rapl & RAPL_PKG)
outp += sprintf(outp, " Pkg_J");
if (do_rapl & RAPL_CORES)
Expand Down Expand Up @@ -460,25 +460,25 @@ int format_counters(struct thread_data *t, struct core_data *c,
outp += sprintf(outp, "%8d", t->cpu_id);
}

/* AvgMHz */
/* Avg_MHz */
if (has_aperf)
outp += sprintf(outp, "%8.0f",
1.0 / units * t->aperf / interval_float);

/* %c0 */
if (do_nhm_cstates) {
/* %Busy */
if (has_aperf) {
if (!skip_c0)
outp += sprintf(outp, "%8.2f", 100.0 * t->mperf/t->tsc);
else
outp += sprintf(outp, "********");
}

/* BzyMHz */
/* Bzy_MHz */
if (has_aperf)
outp += sprintf(outp, "%8.0f",
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);

/* SMI */
Expand Down Expand Up @@ -564,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);
if (do_rapl & RAPL_DRAM_PERF_STATUS)
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)
outp += sprintf(outp, fmt8,
p->energy_pkg * rapl_energy_units);
Expand All @@ -581,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);
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, interval_float);

outp += sprintf(outp, fmt8, interval_float);
}
done:
outp += sprintf(outp, "\n");
Expand Down Expand Up @@ -1022,7 +1022,7 @@ void print_verbose_header(void)
unsigned long long msr;
unsigned int ratio;

if (!do_nehalem_platform_info)
if (!do_nhm_platform_info)
return;

get_msr(0, MSR_NHM_PLATFORM_INFO, &msr);
Expand Down Expand Up @@ -1135,7 +1135,7 @@ void print_verbose_header(void)
}
fprintf(stderr, ")\n");

if (!do_nehalem_turbo_ratio_limit)
if (!do_nhm_turbo_ratio_limit)
return;

get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
Expand Down Expand Up @@ -1462,8 +1462,7 @@ void check_dev_msr()
struct stat sb;

if (stat("/dev/cpu/0/msr", &sb))
err(-5, "no /dev/cpu/0/msr\n"
"Try \"# modprobe msr\"");
err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
}

void check_permissions()
Expand Down Expand Up @@ -1496,13 +1495,27 @@ void check_permissions()
/* if all else fails, thell them to be root */
if (do_exit)
if (getuid() != 0)
warnx("Or simply run as root");
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)
return 0;
Expand All @@ -1529,13 +1542,27 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
case 0x3D: /* BDW */
case 0x4F: /* BDX */
case 0x56: /* BDX-DE */
return 1;
case 0x2E: /* Nehalem-EX Xeon - Beckton */
case 0x2F: /* Westmere-EX Xeon - Eagleton */
return 1;
default:
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)
{
if (!genuine_intel)
Expand Down Expand Up @@ -1994,8 +2021,15 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
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)
return 0;
Expand All @@ -2017,7 +2051,14 @@ int is_snb(unsigned int family, unsigned int model)
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)
return 0;
Expand Down Expand Up @@ -2069,7 +2110,7 @@ double slm_bclk(void)

double discover_bclk(unsigned int family, unsigned int model)
{
if (is_snb(family, model))
if (has_snb_msrs(family, model))
return 100.00;
else if (is_slm(family, model))
return slm_bclk();
Expand Down Expand Up @@ -2117,7 +2158,7 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk
}

/* Temperature Target MSR is Nehalem and newer only */
if (!do_nehalem_platform_info)
if (!do_nhm_platform_info)
goto guess;

if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))
Expand Down Expand Up @@ -2181,18 +2222,15 @@ void check_cpuid()
ebx = ecx = edx = 0;
__get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx);

if (max_level < 0x80000007)
errx(1, "CPUID: no invariant TSC (max_level 0x%x)", max_level);
if (max_level >= 0x80000007) {

/*
* Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
* this check is valid for both Intel and AMD
*/
__get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
has_invariant_tsc = edx & (1 << 8);

if (!has_invariant_tsc)
errx(1, "No invariant TSC");
/*
* Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
* this check is valid for both Intel and AMD
*/
__get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
has_invariant_tsc = edx & (1 << 8);
}

/*
* APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
Expand All @@ -2215,15 +2253,13 @@ void check_cpuid()
if (!has_aperf)
errx(-1, "No APERF");

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_nhm_platform_info = do_nhm_cstates = do_smi = has_nhm_msrs(family, model);
do_snb_cstates = has_snb_msrs(family, model);
do_c8_c9_c10 = has_hsw_msrs(family, model);
do_slm_cstates = is_slm(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);
rapl_probe(family, model);
perf_limit_reasons_probe(family, model);
Expand Down

0 comments on commit d789944

Please sign in to comment.