Skip to contentSkip to conversation

perf/core: set cgroup in cpu contexts for new cgroup events

PATCH In review David Carrillo-Cisneros 4 participants 5 messages Aug 2, 2016 – Aug 10, 2016 perf events

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 perf/core: set cgroup in cpu contexts for new cgroup events

There is an optimization in perf_cgroup_sched_{in,out} that skips the switch of cgroup events if the old and new cgroups in a task switch are the same. This optimization interacts with the current code in two ways that cause a cpu context's cgroup (cpuctx->cgrp) to be NULL even if a cgroup event matches the current task. These are:

1. On creation of the first cgroup event in a CPU: In current code, cpuctx->cpu is only set in perf_cgroup_sched_in, but due to the aforesaid optimization, perf_cgroup_sched_in will run until the next cgroup switches in that cpu. This may happen late or never happen, depending on system's number of cgroups, cpu load, etc.

2. On deletion of the last cgroup event in a cpuctx: In list_del_event, cpuctx->cgrp is set NULL. Any new cgroup event will not be sched in because cpuctx->cgrp == NULL until a cgroup switch occurs and perf_cgroup_sched_in is executed (updating cpuctx->cgrp).

This patch fixes both problems by setting cpuctx->cgrp in list_add_event, mirroring what list_del_event does when removing a cgroup event from CPU context, as introduced in:
commit 68cacd29167b ("perf_events: Fix stale ->cgrp pointer in update_cgrp_time_from_cpuctx()")

With this patch, cpuctx->cgrp is always set/clear when installing/removing the first/last cgroup event in/from the cpu context. With cpuctx->cgrp correctly set, event_filter_match works as intended when events are sched in/out.

The problem is easy to observe in a machine with only one cgroup:

  $ perf stat -e cycles -I 1000 -C 0 -G /
  #          time             counts unit events
      1.000161699      <not counted>      cycles                    /
      2.000355591      <not counted>      cycles                    /
      3.000565154      <not counted>      cycles                    /
      4.000951350      <not counted>      cycles                    /

After the fix, the output is as expected:

  $ perf stat -e cycles -I 1000 -a -G /
  #         time             counts unit events
     1.004699159          627342882      cycles                    /
     2.007397156          615272690      cycles                    /
     3.010019057          616726074      cycles                    /

Rebased at peterz/queue/perf/core.

Changes in v2:
- Fix build error when no CONFIG_CGROUP_PERF.
- Unify add and del cases into list_update_cgroup_event.
- Remove cgroup exclusive variables from builds without CONFIG_CGROUP_PERF.

---
 include/linux/perf_event.h |  4 ++++
 kernel/events/core.c       | 54 ++++++++++++++++++++++++++++++----------------
 2 files changed, 40 insertions(+), 18 deletions(-)
include/linux/perf_event.h +4 -0
index 7921f4f..0e97ae2 100644
@@ -730,7 +730,9 @@ struct perf_event_context {
 	u64				parent_gen;
 	u64				generation;
 	int				pin_count;
+#ifdef CONFIG_CGROUP_PERF
 	int				nr_cgroups;	 /* cgroup evts */
+#endif
 	void				*task_ctx_data; /* pmu specific data */
 	struct rcu_head			rcu_head;
 };
@@ -756,7 +758,9 @@ struct perf_cpu_context {
 	unsigned int			hrtimer_active;
 
 	struct pmu			*unique_pmu;
+#ifdef CONFIG_CGROUP_PERF
 	struct perf_cgroup		*cgrp;
+#endif
 };
 
 struct perf_output_handle {
kernel/events/core.c +36 -18

90 lines not on this page · raw message

Signature · 1 line
2.8.0.rc3.226.g39d4020
#1 lore raw

Hi,

Quoted 47 lines · David Carrillo-Cisneros

There is an optimization in perf_cgroup_sched_{in,out} that skips the switch of cgroup events if the old and new cgroups in a task switch are the same. This optimization interacts with the current code in two ways that cause a cpu context's cgroup (cpuctx->cgrp) to be NULL even if a cgroup event matches the current task. These are:

1. On creation of the first cgroup event in a CPU: In current code, cpuctx->cpu is only set in perf_cgroup_sched_in, but due to the aforesaid optimization, perf_cgroup_sched_in will run until the next cgroup switches in that cpu. This may happen late or never happen, depending on system's number of cgroups, cpu load, etc.

2. On deletion of the last cgroup event in a cpuctx: In list_del_event, cpuctx->cgrp is set NULL. Any new cgroup event will not be sched in because cpuctx->cgrp == NULL until a cgroup switch occurs and perf_cgroup_sched_in is executed (updating cpuctx->cgrp).

This patch fixes both problems by setting cpuctx->cgrp in list_add_event, mirroring what list_del_event does when removing a cgroup event from CPU context, as introduced in:
commit 68cacd29167b ("perf_events: Fix stale ->cgrp pointer in update_cgrp_time_from_cpuctx()")

With this patch, cpuctx->cgrp is always set/clear when installing/removing the first/last cgroup event in/from the cpu context. With cpuctx->cgrp correctly set, event_filter_match works as intended when events are sched in/out.

The problem is easy to observe in a machine with only one cgroup:

  $ perf stat -e cycles -I 1000 -C 0 -G /
  #          time             counts unit events
      1.000161699      <not counted>      cycles                    /
      2.000355591      <not counted>      cycles                    /
      3.000565154      <not counted>      cycles                    /
      4.000951350      <not counted>      cycles                    /

After the fix, the output is as expected:

  $ perf stat -e cycles -I 1000 -a -G /
  #         time             counts unit events
     1.004699159          627342882      cycles                    /
     2.007397156          615272690      cycles                    /
     3.010019057          616726074      cycles                    /

Rebased at peterz/queue/perf/core.

Quoted 7 lines

Changes in v2:
- Fix build error when no CONFIG_CGROUP_PERF.
- Unify add and del cases into list_update_cgroup_event.
- Remove cgroup exclusive variables from builds without CONFIG_CGROUP_PERF.

Is this supposed to fix the bug I reported here?

https://www.mail-archive.com/[email protected]/msg1197757.html

If so, you may want to add:

1) Fixes: f2fb6bef92514 ("perf/core: Optimize side-band event delivery")
2) Reported-by: Vegard Nossum <[email protected]>
3) a link to the thread

and I can give it a test to see if it fixes the problem I was running into.

If not, please ignore :-)

Thanks,

Vegard

#2 lore raw

Hi Vegard,

I don't think this patch fixes your bug, but it touches some code that may be related.

David

Quoted 76 lines · Vegard Nossum

Hi,

Quoted 47 lines · David Carrillo-Cisneros

There is an optimization in perf_cgroup_sched_{in,out} that skips the switch of cgroup events if the old and new cgroups in a task switch are the same. This optimization interacts with the current code in two ways that cause a cpu context's cgroup (cpuctx->cgrp) to be NULL even if a cgroup event matches the current task. These are:

1. On creation of the first cgroup event in a CPU: In current code, cpuctx->cpu is only set in perf_cgroup_sched_in, but due to the aforesaid optimization, perf_cgroup_sched_in will run until the next cgroup switches in that cpu. This may happen late or never happen, depending on system's number of cgroups, cpu load, etc.

2. On deletion of the last cgroup event in a cpuctx: In list_del_event, cpuctx->cgrp is set NULL. Any new cgroup event will not be sched in because cpuctx->cgrp == NULL until a cgroup switch occurs and perf_cgroup_sched_in is executed (updating cpuctx->cgrp).

This patch fixes both problems by setting cpuctx->cgrp in list_add_event, mirroring what list_del_event does when removing a cgroup event from CPU context, as introduced in:
commit 68cacd29167b ("perf_events: Fix stale ->cgrp pointer in update_cgrp_time_from_cpuctx()")

With this patch, cpuctx->cgrp is always set/clear when installing/removing the first/last cgroup event in/from the cpu context. With cpuctx->cgrp correctly set, event_filter_match works as intended when events are sched in/out.

The problem is easy to observe in a machine with only one cgroup:

  $ perf stat -e cycles -I 1000 -C 0 -G /
  #          time             counts unit events
      1.000161699      <not counted>      cycles                    /
      2.000355591      <not counted>      cycles                    /
      3.000565154      <not counted>      cycles                    /
      4.000951350      <not counted>      cycles                    /

After the fix, the output is as expected:

  $ perf stat -e cycles -I 1000 -a -G /
  #         time             counts unit events
     1.004699159          627342882      cycles                    /
     2.007397156          615272690      cycles                    /
     3.010019057          616726074      cycles                    /

Rebased at peterz/queue/perf/core.

Quoted 7 lines

Changes in v2:
- Fix build error when no CONFIG_CGROUP_PERF.
- Unify add and del cases into list_update_cgroup_event.
- Remove cgroup exclusive variables from builds without CONFIG_CGROUP_PERF.

Is this supposed to fix the bug I reported here?

https://www.mail-archive.com/[email protected]/msg1197757.html

If so, you may want to add:

1) Fixes: f2fb6bef92514 ("perf/core: Optimize side-band event delivery")
2) Reported-by: Vegard Nossum <[email protected]>
3) a link to the thread

and I can give it a test to see if it fixes the problem I was running into.

If not, please ignore :-)

Thanks,

Vegard

#4 lore raw

[tip:perf/core] perf/core: Set cgroup in CPU contexts for new cgroup events

In reply to David Carrillo-Cisneros
perf/core: Set cgroup in CPU contexts for new cgroup events
Commit-ID:  db4a835601b73cf8d6cd8986381d966b8e13d2d9
Gitweb:     http://git.kernel.org/tip/db4a835601b73cf8d6cd8986381d966b8e13d2d9
Author:     David Carrillo-Cisneros <[email protected]>
AuthorDate: Tue, 2 Aug 2016 00:48:12 -0700
Committer:  Ingo Molnar <[email protected]>
CommitDate: Wed, 10 Aug 2016 13:05:52 +0200

perf/core: Set cgroup in CPU contexts for new cgroup events

There's a perf stat bug easy to observer on a machine with only one cgroup:

  $ perf stat -e cycles -I 1000 -C 0 -G /
  #          time             counts unit events
      1.000161699      <not counted>      cycles                    /
      2.000355591      <not counted>      cycles                    /
      3.000565154      <not counted>      cycles                    /
      4.000951350      <not counted>      cycles                    /

We'd expect some output there.

The underlying problem is that there is an optimization in perf_cgroup_sched_{in,out}() that skips the switch of cgroup events if the old and new cgroups in a task switch are the same.

This optimization interacts with the current code in two ways that cause a CPU context's cgroup (cpuctx->cgrp) to be NULL even if a cgroup event matches the current task. These are:

1. On creation of the first cgroup event in a CPU: In current code, cpuctx->cpu is only set in perf_cgroup_sched_in, but due to the aforesaid optimization, perf_cgroup_sched_in will run until the next cgroup switches in that CPU. This may happen late or never happen, depending on system's number of cgroups, CPU load, etc.

2. On deletion of the last cgroup event in a cpuctx: In list_del_event, cpuctx->cgrp is set NULL. Any new cgroup event will not be sched in because cpuctx->cgrp == NULL until a cgroup switch occurs and perf_cgroup_sched_in is executed (updating cpuctx->cgrp).

This patch fixes both problems by setting cpuctx->cgrp in list_add_event, mirroring what list_del_event does when removing a cgroup event from CPU context, as introduced in:

commit 68cacd29167b ("perf_events: Fix stale ->cgrp pointer in update_cgrp_time_from_cpuctx()")

With this patch, cpuctx->cgrp is always set/clear when installing/removing the first/last cgroup event in/from the CPU context. With cpuctx->cgrp correctly set, event_filter_match works as intended when events are sched in/out.

After the fix, the output is as expected:

  $ perf stat -e cycles -I 1000 -a -G /
  #         time             counts unit events
     1.004699159          627342882      cycles                    /
     2.007397156          615272690      cycles                    /
     3.010019057          616726074      cycles                    /
Cc Alexander Shishkin <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Kan Liang <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Paul Turner <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Vegard Nossum <[email protected]>
Cc Vince Weaver <[email protected]>
---
 include/linux/perf_event.h |  4 ++++
 kernel/events/core.c       | 54 ++++++++++++++++++++++++++++++----------------
 2 files changed, 40 insertions(+), 18 deletions(-)
include/linux/perf_event.h +4 -0
index 8ed43261..2b6b43c 100644
@@ -743,7 +743,9 @@ struct perf_event_context {
 	u64				parent_gen;
 	u64				generation;
 	int				pin_count;
+#ifdef CONFIG_CGROUP_PERF
 	int				nr_cgroups;	 /* cgroup evts */
+#endif
 	void				*task_ctx_data; /* pmu specific data */
 	struct rcu_head			rcu_head;
 };
@@ -769,7 +771,9 @@ struct perf_cpu_context {
 	unsigned int			hrtimer_active;
 
 	struct pmu			*unique_pmu;
+#ifdef CONFIG_CGROUP_PERF
 	struct perf_cgroup		*cgrp;
+#endif
 };
 
 struct perf_output_handle {
kernel/events/core.c +36 -18

90 lines not on this page · raw message