Skip to content

Commit 7adafe5

Browse files
Janakarajan Natarajanshuahkh
authored andcommitted
cpupower: mperf_monitor: Introduce per_cpu_schedule flag
The per_cpu_schedule flag is used to move the cpupower process to the cpu on which we are looking to read the APERF/MPERF registers. This prevents IPIs from being generated by read_msr()s as we are already on the cpu of interest. Ex: If cpupower is running on CPU 0 and we execute read_msr(20, MSR_APERF, val) then, read_msr(20, MSR_MPERF, val) the msr module will generate an IPI from CPU 0 to CPU 20 to query for the MSR_APERF and then the MSR_MPERF in separate IPIs. This delay, caused by IPI latency, between reading the APERF and MPERF registers may cause both of them to go out of sync. The use of the per_cpu_schedule flag reduces the probability of this from happening. It comes at the cost of a negligible increase in cpu consumption caused by the migration of cpupower across each of the cpus of the system. Signed-off-by: Janakarajan Natarajan <[email protected]> Acked-by: Thomas Renninger <[email protected]> Signed-off-by: Shuah Khan <[email protected]>
1 parent d3f5d2a commit 7adafe5

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct cpuidle_monitor {
6262
unsigned int overflow_s;
6363
struct {
6464
unsigned int needs_root:1;
65+
unsigned int per_cpu_schedule:1;
6566
} flags;
6667
};
6768

tools/power/cpupower/utils/idle_monitor/mperf_monitor.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,48 @@ static int mperf_get_tsc(unsigned long long *tsc)
8686
return ret;
8787
}
8888

89+
static int get_aperf_mperf(int cpu, unsigned long long *aval,
90+
unsigned long long *mval)
91+
{
92+
int ret;
93+
94+
/*
95+
* Running on the cpu from which we read the registers will
96+
* prevent APERF/MPERF from going out of sync because of IPI
97+
* latency introduced by read_msr()s.
98+
*/
99+
if (mperf_monitor.flags.per_cpu_schedule) {
100+
if (bind_cpu(cpu))
101+
return 1;
102+
}
103+
104+
ret = read_msr(cpu, MSR_APERF, aval);
105+
ret |= read_msr(cpu, MSR_MPERF, mval);
106+
107+
return ret;
108+
}
109+
89110
static int mperf_init_stats(unsigned int cpu)
90111
{
91-
unsigned long long val;
112+
unsigned long long aval, mval;
92113
int ret;
93114

94-
ret = read_msr(cpu, MSR_APERF, &val);
95-
aperf_previous_count[cpu] = val;
96-
ret |= read_msr(cpu, MSR_MPERF, &val);
97-
mperf_previous_count[cpu] = val;
115+
ret = get_aperf_mperf(cpu, &aval, &mval);
116+
aperf_previous_count[cpu] = aval;
117+
mperf_previous_count[cpu] = mval;
98118
is_valid[cpu] = !ret;
99119

100120
return 0;
101121
}
102122

103123
static int mperf_measure_stats(unsigned int cpu)
104124
{
105-
unsigned long long val;
125+
unsigned long long aval, mval;
106126
int ret;
107127

108-
ret = read_msr(cpu, MSR_APERF, &val);
109-
aperf_current_count[cpu] = val;
110-
ret |= read_msr(cpu, MSR_MPERF, &val);
111-
mperf_current_count[cpu] = val;
128+
ret = get_aperf_mperf(cpu, &aval, &mval);
129+
aperf_current_count[cpu] = aval;
130+
mperf_current_count[cpu] = mval;
112131
is_valid[cpu] = !ret;
113132

114133
return 0;
@@ -305,6 +324,9 @@ struct cpuidle_monitor *mperf_register(void)
305324
if (init_maxfreq_mode())
306325
return NULL;
307326

327+
if (cpupower_cpu_info.vendor == X86_VENDOR_AMD)
328+
mperf_monitor.flags.per_cpu_schedule = 1;
329+
308330
/* Free this at program termination */
309331
is_valid = calloc(cpu_count, sizeof(int));
310332
mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long));

0 commit comments

Comments
 (0)