[tip:perf/core] perf/core: Try parent PMU first when initializing a child event

From: tip-bot for Kan Liang
Date: Mon Jan 30 2017 - 07:00:36 EST

Commit-ID: 40999312c703f80e8d31bc77cf00e6e84d36e091
Gitweb: http://git.kernel.org/tip/40999312c703f80e8d31bc77cf00e6e84d36e091
Author: Kan Liang <kan.liang@xxxxxxxxx>
AuthorDate: Wed, 18 Jan 2017 08:21:01 -0500
Committer: Ingo Molnar <mingo@xxxxxxxxxx>
CommitDate: Mon, 30 Jan 2017 12:01:16 +0100

perf/core: Try parent PMU first when initializing a child event

perf has additional overhead when monitoring the task which
frequently generates child tasks.

perf_init_event() is one of the hotspots for the additional overhead:

Currently, to get the PMU, it tries to search the type in pmu_idr at
first. But it is not always successful, especially for the widely used
PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE events. So it has to go to the
slow path which go through the whole PMUs list.

It will be a big performance issue, if the PMUs list is long (e.g. server
with many uncore boxes) and the task frequently generates child tasks.

The child event inherits its parent event. So the child event should
try its parent PMU first.

Here is some data from the overhead test on Broadwell server:

perf record -e $TEST_EVENTS -- ./loop.sh 50000

start=$(date +%s%N)
while [ "$i" -le "$1" ]
date > /dev/null
i=`expr $i + 1`
end=$(date +%s%N)
elapsed=`expr $end - $start`

Event# Original elapsed time Elapsed time with patch delta
1 196,573,192,397 189,162,029,998 -3.77%
2 257,567,753,013 241,620,788,683 -6.19%
4 398,730,726,971 370,518,938,714 -7.08%
8 824,983,761,120 740,702,489,329 -10.22%
16 1,883,411,923,498 1,672,027,508,355 -11.22%

... which shows a nice performance improvement.

Signed-off-by: Kan Liang <kan.liang@xxxxxxxxx>
Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
Cc: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx>
Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Cc: Stephane Eranian <eranian@xxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Vince Weaver <vincent.weaver@xxxxxxxxx>
Link: http://lkml.kernel.org/r/1484745662-15928-2-git-send-email-kan.liang@xxxxxxxxx
[ Tidied up the changelog and the code comment. ]
Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx>
kernel/events/core.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index cbcee23..88676ff 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9022,6 +9022,14 @@ static struct pmu *perf_init_event(struct perf_event *event)

idx = srcu_read_lock(&pmus_srcu);

+ /* Try parent's PMU first: */
+ if (event->parent && event->parent->pmu) {
+ pmu = event->parent->pmu;
+ ret = perf_try_init_event(pmu, event);
+ if (!ret)
+ goto unlock;
+ }
pmu = idr_find(&pmu_idr, event->attr.type);