Skip to content

Commit 1765bb6

Browse files
Tero KristoPeter Zijlstra
authored andcommitted
perf/core: Allow reading package events from perf_event_read_local
Per-package perf events are typically registered with a single CPU only, however they can be read across all the CPUs within the package. Currently perf_event_read maps the event CPU according to the topology information to avoid an unnecessary SMP call, however perf_event_read_local deals with hard values and rejects a read with a failure if the CPU is not the one exactly registered. Allow similar mapping within the perf_event_read_local if the perf event in question can support this. This allows users like BPF code to read the package perf events properly across different CPUs within a package. Signed-off-by: Tero Kristo <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 05276d4 commit 1765bb6

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

kernel/events/core.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4425,6 +4425,9 @@ static int __perf_event_read_cpu(struct perf_event *event, int event_cpu)
44254425
{
44264426
u16 local_pkg, event_pkg;
44274427

4428+
if ((unsigned)event_cpu >= nr_cpu_ids)
4429+
return event_cpu;
4430+
44284431
if (event->group_caps & PERF_EV_CAP_READ_ACTIVE_PKG) {
44294432
int local_cpu = smp_processor_id();
44304433

@@ -4527,6 +4530,8 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
45274530
u64 *enabled, u64 *running)
45284531
{
45294532
unsigned long flags;
4533+
int event_oncpu;
4534+
int event_cpu;
45304535
int ret = 0;
45314536

45324537
/*
@@ -4551,15 +4556,22 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
45514556
goto out;
45524557
}
45534558

4559+
/*
4560+
* Get the event CPU numbers, and adjust them to local if the event is
4561+
* a per-package event that can be read locally
4562+
*/
4563+
event_oncpu = __perf_event_read_cpu(event, event->oncpu);
4564+
event_cpu = __perf_event_read_cpu(event, event->cpu);
4565+
45544566
/* If this is a per-CPU event, it must be for this CPU */
45554567
if (!(event->attach_state & PERF_ATTACH_TASK) &&
4556-
event->cpu != smp_processor_id()) {
4568+
event_cpu != smp_processor_id()) {
45574569
ret = -EINVAL;
45584570
goto out;
45594571
}
45604572

45614573
/* If this is a pinned event it must be running on this CPU */
4562-
if (event->attr.pinned && event->oncpu != smp_processor_id()) {
4574+
if (event->attr.pinned && event_oncpu != smp_processor_id()) {
45634575
ret = -EBUSY;
45644576
goto out;
45654577
}
@@ -4569,7 +4581,7 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
45694581
* or local to this CPU. Furthermore it means its ACTIVE (otherwise
45704582
* oncpu == -1).
45714583
*/
4572-
if (event->oncpu == smp_processor_id())
4584+
if (event_oncpu == smp_processor_id())
45734585
event->pmu->read(event);
45744586

45754587
*value = local64_read(&event->count);

0 commit comments

Comments
 (0)