aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2016-02-27 03:11:29 -0500
committerLen Brown <len.brown@intel.com>2016-03-13 03:55:41 -0400
commit0102b06747c7d24e334d2b27c4b43eed693676f1 (patch)
tree6da6cef237200c4bc3743676dfb0d8371b98ee82 /tools
parentfdf676e51f301d207586d9bac509b8ce055bae8a (diff)
tools/power turbostat: detect and work around syscall jitter
The accuracy of Bzy_Mhz and Busy% depend on reading the TSC, APERF, and MPERF close together in time. When there is a very short measurement interval, or a large system is profoundly idle, the changes in APERF and MPERF may be very small. They can be small enough that an expensive interrupt between reading APERF and MPERF can cause the APERF/MPERF ratio to become inaccurate, resulting in invalid calculation and display of Bzy_MHz. A dummy APERF read of APERF makes this problem much more rare. Apparently this 1st systemn call after exiting a long stretch of idle is when we typically see expensive timer interrupts that cause large jitter. For the cases that dummy APERF read fails to prevent, we compare the latency of the APERF and MPERF reads. If they differ by more than 2x, we re-issue them. Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/power/x86/turbostat/turbostat.c51
1 files changed, 50 insertions, 1 deletions
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 9896619e4382..43a6dda434ef 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1059,19 +1059,68 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1059{ 1059{
1060 int cpu = t->cpu_id; 1060 int cpu = t->cpu_id;
1061 unsigned long long msr; 1061 unsigned long long msr;
1062 int aperf_mperf_retry_count = 0;
1062 1063
1063 if (cpu_migrate(cpu)) { 1064 if (cpu_migrate(cpu)) {
1064 fprintf(outf, "Could not migrate to CPU %d\n", cpu); 1065 fprintf(outf, "Could not migrate to CPU %d\n", cpu);
1065 return -1; 1066 return -1;
1066 } 1067 }
1067 1068
1069retry:
1068 t->tsc = rdtsc(); /* we are running on local CPU of interest */ 1070 t->tsc = rdtsc(); /* we are running on local CPU of interest */
1069 1071
1070 if (has_aperf) { 1072 if (has_aperf) {
1073 unsigned long long tsc_before, tsc_between, tsc_after, aperf_time, mperf_time;
1074
1075 /*
1076 * The TSC, APERF and MPERF must be read together for
1077 * APERF/MPERF and MPERF/TSC to give accurate results.
1078 *
1079 * Unfortunately, APERF and MPERF are read by
1080 * individual system call, so delays may occur
1081 * between them. If the time to read them
1082 * varies by a large amount, we re-read them.
1083 */
1084
1085 /*
1086 * This initial dummy APERF read has been seen to
1087 * reduce jitter in the subsequent reads.
1088 */
1089
1090 if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
1091 return -3;
1092
1093 t->tsc = rdtsc(); /* re-read close to APERF */
1094
1095 tsc_before = t->tsc;
1096
1071 if (get_msr(cpu, MSR_IA32_APERF, &t->aperf)) 1097 if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
1072 return -3; 1098 return -3;
1099
1100 tsc_between = rdtsc();
1101
1073 if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf)) 1102 if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
1074 return -4; 1103 return -4;
1104
1105 tsc_after = rdtsc();
1106
1107 aperf_time = tsc_between - tsc_before;
1108 mperf_time = tsc_after - tsc_between;
1109
1110 /*
1111 * If the system call latency to read APERF and MPERF
1112 * differ by more than 2x, then try again.
1113 */
1114 if ((aperf_time > (2 * mperf_time)) || (mperf_time > (2 * aperf_time))) {
1115 aperf_mperf_retry_count++;
1116 if (aperf_mperf_retry_count < 5)
1117 goto retry;
1118 else
1119 warnx("cpu%d jitter %lld %lld",
1120 cpu, aperf_time, mperf_time);
1121 }
1122 aperf_mperf_retry_count = 0;
1123
1075 t->aperf = t->aperf * aperf_mperf_multiplier; 1124 t->aperf = t->aperf * aperf_mperf_multiplier;
1076 t->mperf = t->mperf * aperf_mperf_multiplier; 1125 t->mperf = t->mperf * aperf_mperf_multiplier;
1077 } 1126 }
@@ -3554,7 +3603,7 @@ int get_and_dump_counters(void)
3554} 3603}
3555 3604
3556void print_version() { 3605void print_version() {
3557 fprintf(outf, "turbostat version 4.10 10 Dec, 2015" 3606 fprintf(outf, "turbostat version 4.11 27 Feb 2016"
3558 " - Len Brown <lenb@kernel.org>\n"); 3607 " - Len Brown <lenb@kernel.org>\n");
3559} 3608}
3560 3609