Skip to contentSkip to conversation

perf/core: addressing 4x slowdown during per-process profiling of STREAM benchmark on Intel Xeon Phi

PATCH Superseded Alexey Budankov 2 participants 2 messages Jun 21, 2017 – Jun 23, 2017 perf events

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

PATCH v4 1/4 perf/core: addressing 4x slowdown during per-process profiling of STREAM benchmark on Intel Xeon Phi

perf/core: use rb trees for pinned/flexible groups

By default, the userspace perf tool opens per-cpu task-bound events when sampling, so for N logical events requested by the user, the tool will open N * NR_CPUS events.

In the kernel, we mux events with a hrtimer, periodically rotating the
flexible group list and trying to schedule each group in turn. We skip groups whose cpu filter doesn't match. So when we get unlucky, we can walk N * (NR_CPUS - 1) groups pointlessly for each hrtimer invocation.

This has been observed to result in significant overhead when running the STREAM benchmark on 272 core Xeon Phi systems.

One way to avoid this is to place our events into an rb tree sorted by CPU, so that our hrtimer can skip to the current CPU's list and ignore everything else.

As a step towards that, this patch introduces rb tree for group lists.

---

 include/linux/perf_event.h |  33 +++-
 kernel/events/core.c       | 463 
+++++++++++++++++++++++++++++++++++----------
 2 files changed, 397 insertions(+), 99 deletions(-)

1. introduced group_node, group_list, group_list_entry into struct perf_event type;

2. introduced perf_event_groups type for pinned and flexible groups; new type objects combine rb tree and list for safe whole tree iterations;

3. introduced new functions:

get_event_groups()
add_event_to_groups()
del_event_from_groups()

perf_event_groups_empty()
perf_event_groups_init()
perf_event_groups_insert()
perf_event_groups_delete()
perf_event_groups_rotate(..., int cpu)
perf_event_groups_iterate_cpu(..., int cpu)
perf_event_groups_iterate()

struct group_sched_params
group_sched_out_callback()
sched_in_group()
ctx_pinned_sched_in_callback()
ctx_flexible_sched_in_callback()

struct inherit_task_group_params
inherit_task_group_callback()

see comments in the patch for more details;

4. removed functions:

ctx_group_list()
ctx_pinned_sched_in()
ctx_flexible_sched_in()

5. functions changed to adopt new API:

perf_event_alloc(),
perf_event_init_context(),
__perf_event_init_context(),
list_add_event(),
list_del_event(),
ctx_sched_in(),
ctx_sched_out(),
perf_event_context_sched_in(),
inherit_task_group(),
rotate_ctx()

The patch was tested under perf_fuzzer and tests on Xeon Phi: https://github.com/deater/perf_event_tests.
No new issues were found in comparison to the clean kernel.

---

include/linux/perf_event.h +31 -2
index 24a6358..d2fb0e7 100644
@@ -572,6 +572,26 @@ struct perf_event {
 	 */
 	struct list_head		group_entry;
 	struct list_head		sibling_list;
+	/*
+	 * Node on the pinned or flexible tree located at the event context;
+	 * the node may be empty in case its event is not directly attached
+	 * to the tree but to group_list list of the event directly
+	 * attached to the tree;
+	 */
+	struct rb_node            	group_node;
+	/*
+	 * List keeps groups allocated for the same cpu;
+	 * the list may be empty in case its event is not directly
+	 * attached to the tree but to group_list list of the event directly
+	 * attached to the tree;
+	 */
+	struct list_head 	       	group_list;
+	/*
+	 * Entry into the group_list list above;
+	 * the entry may be attached to the self group_list list above
+	 * in case the event is directly attached to the tree;
+	 */
+	struct list_head		group_list_entry;
 
 	/*
 	 * We need storage to track the entries in perf_pmu_migrate_context; we
@@ -721,6 +741,15 @@ struct perf_event {
 #endif /* CONFIG_PERF_EVENTS */
 };
 
+/*
+ * event groups keep group leader events arranged as an rb tree with
+ * event->cpu key and as a list for the whole tree iterations;
+ */
+struct perf_event_groups {
+	struct rb_root	 tree;
+	struct list_head list;
+};
+
 /**
  * struct perf_event_context - event context structure
  *
@@ -741,8 +770,8 @@ struct perf_event_context {
 	struct mutex			mutex;
 
 	struct list_head		active_ctx_list;
-	struct list_head		pinned_groups;
-	struct list_head		flexible_groups;
+	struct perf_event_groups	pinned_groups;
+	struct perf_event_groups        flexible_groups;
 	struct list_head		event_list;
 	int				nr_events;
 	int				nr_active;
kernel/events/core.c +366 -97

603 lines not on this page · raw message

reviewer
#1 lore raw

Hi,

As a heads-up, it looks like something is mangling these patches. I see that the @@ lines in patches are line-wrapped, which from git am's PoV means the patches are corrupt.

kernel/events/core.c static enum event_type_t · line 1458

Quoted 6 lines · Alexey Budankov
kernel/events/core.c +0 -0
index bc63f8d..fc37e30 100644
@@ -1458,8 +1458,12 @@ static enum event_type_t
 get_event_type(struct perf_event *event)

e.g. the last two lines above should be one line.

kernel/events/core.c ctx_group_list(struct perf_event *event, · line 1471

Quoted 2 lines
kernel/events/core.c +0 -0
@@ -1467,6 +1471,223 @@ ctx_group_list(struct perf_event *event,
 struct perf_event_context *ctx)

Likewise.

kernel/events/core.c list_add_event(struct perf_event *event, · line 1706

Quoted 2 lines
kernel/events/core.c +0 -0
@@ -1485,12 +1706,8 @@ list_add_event(struct perf_event *event,
 struct perf_event_context *ctx)

Likewise.

kernel/events/core.c list_del_event(struct perf_event *event, · line 1898

Quoted 2 lines
kernel/events/core.c +0 -0
@@ -1681,7 +1898,7 @@ list_del_event(struct perf_event *event,
 struct perf_event_context *ctx)

Likewise.

... and so on throughout the patch.

I'm only seeing this on patches from you, and I see this both from my arm.com account and a gmail account subscribed to LKML, whether I export this from mutt or from the gmail web interface.

Can you check if your MTA is doing something here?

It's possible to fix this up manually, but it's rather tedious.

Thanks,
Mark.