aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/x86/turbostat/turbostat.c
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2012-03-29 21:44:40 -0400
committerLen Brown <len.brown@intel.com>2012-03-29 22:04:58 -0400
commit88c3281f7ba449992f7a33bd2452a8c6fa5503cb (patch)
tree09199b6751bbff93feb014c23fa48c736c5c6a59 /tools/power/x86/turbostat/turbostat.c
parente23da0370f80834e971142e50253f5b79be83631 (diff)
tools turbostat: reduce measurement overhead due to IPIs
turbostat uses /dev/cpu/*/msr interface to read MSRs. For modern systems, it reads 10 MSR/CPU. This can be observed as 10 "Function Call Interrupts" per CPU per sample added to /proc/interrupts. This overhead is measurable on large idle systems, and as Yoquan Song pointed out, it can even trick cpuidle into thinking the system is busy. Here turbostat re-schedules itself in-turn to each CPU so that its MSR reads will always be local. This replaces the 10 "Function Call Interrupts" with a single "Rescheduling interrupt" per sample per CPU. On an idle 32-CPU system, this shifts some residency from the shallow c1 state to the deeper c7 state: # ./turbostat.old -s %c0 GHz TSC %c1 %c3 %c6 %c7 %pc2 %pc3 %pc6 %pc7 0.27 1.29 2.29 0.95 0.02 0.00 98.77 20.23 0.00 77.41 0.00 0.25 1.24 2.29 0.98 0.02 0.00 98.75 20.34 0.03 77.74 0.00 0.27 1.22 2.29 0.54 0.00 0.00 99.18 20.64 0.00 77.70 0.00 0.26 1.22 2.29 1.22 0.00 0.00 98.52 20.22 0.00 77.74 0.00 0.26 1.38 2.29 0.78 0.02 0.00 98.95 20.51 0.05 77.56 0.00 ^C i# ./turbostat.new -s %c0 GHz TSC %c1 %c3 %c6 %c7 %pc2 %pc3 %pc6 %pc7 0.27 1.20 2.29 0.24 0.01 0.00 99.49 20.58 0.00 78.20 0.00 0.27 1.22 2.29 0.25 0.00 0.00 99.48 20.79 0.00 77.85 0.00 0.27 1.20 2.29 0.25 0.02 0.00 99.46 20.71 0.03 77.89 0.00 0.28 1.26 2.29 0.25 0.01 0.00 99.46 20.89 0.02 77.67 0.00 0.27 1.20 2.29 0.24 0.01 0.00 99.48 20.65 0.00 78.04 0.00 cc: Youquan Song <youquan.song@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools/power/x86/turbostat/turbostat.c')
-rw-r--r--tools/power/x86/turbostat/turbostat.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 6436d54378c7..fa60872b9474 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -19,6 +19,7 @@
19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20 */ 20 */
21 21
22#define _GNU_SOURCE
22#include <stdio.h> 23#include <stdio.h>
23#include <unistd.h> 24#include <unistd.h>
24#include <sys/types.h> 25#include <sys/types.h>
@@ -32,6 +33,7 @@
32#include <dirent.h> 33#include <dirent.h>
33#include <string.h> 34#include <string.h>
34#include <ctype.h> 35#include <ctype.h>
36#include <sched.h>
35 37
36#define MSR_TSC 0x10 38#define MSR_TSC 0x10
37#define MSR_NEHALEM_PLATFORM_INFO 0xCE 39#define MSR_NEHALEM_PLATFORM_INFO 0xCE
@@ -72,6 +74,8 @@ char *progname;
72int need_reinitialize; 74int need_reinitialize;
73 75
74int num_cpus; 76int num_cpus;
77cpu_set_t *cpu_mask;
78size_t cpu_mask_size;
75 79
76struct counters { 80struct counters {
77 unsigned long long tsc; /* per thread */ 81 unsigned long long tsc; /* per thread */
@@ -100,6 +104,40 @@ struct timeval tv_even;
100struct timeval tv_odd; 104struct timeval tv_odd;
101struct timeval tv_delta; 105struct timeval tv_delta;
102 106
107/*
108 * cpu_mask_init(ncpus)
109 *
110 * allocate and clear cpu_mask
111 * set cpu_mask_size
112 */
113void cpu_mask_init(int ncpus)
114{
115 cpu_mask = CPU_ALLOC(ncpus);
116 if (cpu_mask == NULL) {
117 perror("CPU_ALLOC");
118 exit(3);
119 }
120 cpu_mask_size = CPU_ALLOC_SIZE(ncpus);
121 CPU_ZERO_S(cpu_mask_size, cpu_mask);
122}
123
124void cpu_mask_uninit()
125{
126 CPU_FREE(cpu_mask);
127 cpu_mask = NULL;
128 cpu_mask_size = 0;
129}
130
131int cpu_migrate(int cpu)
132{
133 CPU_ZERO_S(cpu_mask_size, cpu_mask);
134 CPU_SET_S(cpu, cpu_mask_size, cpu_mask);
135 if (sched_setaffinity(0, cpu_mask_size, cpu_mask) == -1)
136 return -1;
137 else
138 return 0;
139}
140
103unsigned long long get_msr(int cpu, off_t offset) 141unsigned long long get_msr(int cpu, off_t offset)
104{ 142{
105 ssize_t retval; 143 ssize_t retval;
@@ -471,6 +509,11 @@ void compute_average(struct counters *delta, struct counters *avg)
471void get_counters(struct counters *cnt) 509void get_counters(struct counters *cnt)
472{ 510{
473 for ( ; cnt; cnt = cnt->next) { 511 for ( ; cnt; cnt = cnt->next) {
512 if (cpu_migrate(cnt->cpu)) {
513 need_reinitialize = 1;
514 return;
515 }
516
474 cnt->tsc = get_msr(cnt->cpu, MSR_TSC); 517 cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
475 if (do_nhm_cstates) 518 if (do_nhm_cstates)
476 cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY); 519 cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
@@ -752,6 +795,8 @@ void re_initialize(void)
752 free_all_counters(); 795 free_all_counters();
753 num_cpus = for_all_cpus(alloc_new_counters); 796 num_cpus = for_all_cpus(alloc_new_counters);
754 need_reinitialize = 0; 797 need_reinitialize = 0;
798 cpu_mask_uninit();
799 cpu_mask_init(num_cpus);
755 printf("num_cpus is now %d\n", num_cpus); 800 printf("num_cpus is now %d\n", num_cpus);
756} 801}
757 802
@@ -984,6 +1029,7 @@ void turbostat_init()
984 check_super_user(); 1029 check_super_user();
985 1030
986 num_cpus = for_all_cpus(alloc_new_counters); 1031 num_cpus = for_all_cpus(alloc_new_counters);
1032 cpu_mask_init(num_cpus);
987 1033
988 if (verbose) 1034 if (verbose)
989 print_nehalem_info(); 1035 print_nehalem_info();