|
@@ -3424,6 +3424,22 @@ struct perf_read_data {
|
|
|
int ret;
|
|
|
};
|
|
|
|
|
|
+static int find_cpu_to_read(struct perf_event *event, int local_cpu)
|
|
|
+{
|
|
|
+ int event_cpu = event->oncpu;
|
|
|
+ u16 local_pkg, event_pkg;
|
|
|
+
|
|
|
+ if (event->group_caps & PERF_EV_CAP_READ_ACTIVE_PKG) {
|
|
|
+ event_pkg = topology_physical_package_id(event_cpu);
|
|
|
+ local_pkg = topology_physical_package_id(local_cpu);
|
|
|
+
|
|
|
+ if (event_pkg == local_pkg)
|
|
|
+ return local_cpu;
|
|
|
+ }
|
|
|
+
|
|
|
+ return event_cpu;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Cross CPU call to read the hardware event
|
|
|
*/
|
|
@@ -3545,7 +3561,7 @@ u64 perf_event_read_local(struct perf_event *event)
|
|
|
|
|
|
static int perf_event_read(struct perf_event *event, bool group)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
+ int ret = 0, cpu_to_read, local_cpu;
|
|
|
|
|
|
/*
|
|
|
* If event is enabled and currently active on a CPU, update the
|
|
@@ -3557,7 +3573,12 @@ static int perf_event_read(struct perf_event *event, bool group)
|
|
|
.group = group,
|
|
|
.ret = 0,
|
|
|
};
|
|
|
- ret = smp_call_function_single(event->oncpu, __perf_event_read, &data, 1);
|
|
|
+
|
|
|
+ local_cpu = get_cpu();
|
|
|
+ cpu_to_read = find_cpu_to_read(event, local_cpu);
|
|
|
+ put_cpu();
|
|
|
+
|
|
|
+ ret = smp_call_function_single(cpu_to_read, __perf_event_read, &data, 1);
|
|
|
/* The event must have been read from an online CPU: */
|
|
|
WARN_ON_ONCE(ret);
|
|
|
ret = ret ? : data.ret;
|