In case we monitor events system wide, we get EXIT event (when configured) twice for each task that exited. Note doubled lines with same pid/tid in following example: $ sudo ./perf record -a ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.480 MB perf.data (2518 samples) ] $ sudo ./perf report -D | grep EXIT 0 60290687567581 0x59910 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 0 60290687568354 0x59948 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 0 60290687988744 0x59ad8 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 0 60290687989198 0x59b10 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 1 60290692567895 0x62af0 [0x38]: PERF_RECORD_EXIT(1253:1253):(1253:1253) 1 60290692568322 0x62b28 [0x38]: PERF_RECORD_EXIT(1253:1253):(1253:1253) 2 60290692739276 0x69a18 [0x38]: PERF_RECORD_EXIT(1252:1252):(1252:1252) 2 60290692739910 0x69a50 [0x38]: PERF_RECORD_EXIT(1252:1252):(1252:1252) The reason is that the cpu contexts are processes each time we call perf_event_task. I'm changing the perf_event_aux logic to serve task_ctx and cpu contexts separately, which ensure we don't get EXIT event generated twice on same cpu context. This does not affect other auxiliary events, as they don't use task_ctx at all.
Unified · Split
| @@ -5682,6 +5682,17 @@ perf_event_aux_ctx(struct perf_event_context *ctx, · 5681 unmodified lines | |||
| 5682 | } | 5682 | } |
| 5683 | } | 5683 | } |
| 5684 | 5684 | ||
| 5685 | static void | ||
| 5686 | perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data, | ||
| 5687 | struct perf_event_context *task_ctx) | ||
| 5688 | { | ||
| 5689 | rcu_read_lock(); | ||
| 5690 | preempt_disable(); | ||
| 5691 | perf_event_aux_ctx(task_ctx, output, data); | ||
| 5692 | preempt_enable(); | ||
| 5693 | rcu_read_unlock(); | ||
| 5694 | } | ||
| 5695 | |||
| 5685 | static void | 5696 | static void |
| 5686 | perf_event_aux(perf_event_aux_output_cb output, void *data, | 5697 | perf_event_aux(perf_event_aux_output_cb output, void *data, |
| 5687 | struct perf_event_context *task_ctx) | 5698 | struct perf_event_context *task_ctx) |
| @@ -5691,14 +5702,23 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, · 3 unmodified lines | |||
| 5691 | struct pmu *pmu; | 5702 | struct pmu *pmu; |
| 5692 | int ctxn; | 5703 | int ctxn; |
| 5693 | 5704 | ||
| 5705 | /* | ||
| 5706 | * If we have task_ctx != NULL we only notify | ||
| 5707 | * the task context itself. The task_ctx is set | ||
| 5708 | * only for EXIT events before releasing task | ||
| 5709 | * context. | ||
| 5710 | */ | ||
| 5711 | if (task_ctx) { | ||
| 5712 | perf_event_aux_task_ctx(output, data, task_ctx); | ||
| 5713 | return; | ||
| 5714 | } | ||
| 5715 | |||
| 5694 | rcu_read_lock(); | 5716 | rcu_read_lock(); |
| 5695 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 5717 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
| 5696 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 5718 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
| 5697 | if (cpuctx->unique_pmu != pmu) | 5719 | if (cpuctx->unique_pmu != pmu) |
| 5698 | goto next; | 5720 | goto next; |
| 5699 | perf_event_aux_ctx(&cpuctx->ctx, output, data); | 5721 | perf_event_aux_ctx(&cpuctx->ctx, output, data); |
| 5700 | if (task_ctx) | ||
| 5701 | goto next; | ||
| 5702 | ctxn = pmu->task_ctx_nr; | 5722 | ctxn = pmu->task_ctx_nr; |
| 5703 | if (ctxn < 0) | 5723 | if (ctxn < 0) |
| 5704 | goto next; | 5724 | goto next; |
| @@ -5708,12 +5728,6 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, · 3 unmodified lines | |||
| 5708 | next: | 5728 | next: |
| 5709 | put_cpu_ptr(pmu->pmu_cpu_context); | 5729 | put_cpu_ptr(pmu->pmu_cpu_context); |
| 5710 | } | 5730 | } |
| 5711 | |||
| 5712 | if (task_ctx) { | ||
| 5713 | preempt_disable(); | ||
| 5714 | perf_event_aux_ctx(task_ctx, output, data); | ||
| 5715 | preempt_enable(); | ||
| 5716 | } | ||
| 5717 | rcu_read_unlock(); | 5731 | rcu_read_unlock(); |
| 5718 | } | 5732 | } |
| 5719 | 5733 | ||
| @@ -8803,10 +8817,8 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) · 3083 unmodified lines | |||
| 8803 | struct perf_event_context *child_ctx, *clone_ctx = NULL; | 8817 | struct perf_event_context *child_ctx, *clone_ctx = NULL; |
| 8804 | unsigned long flags; | 8818 | unsigned long flags; |
| 8805 | 8819 | ||
| 8806 | if (likely(!child->perf_event_ctxp[ctxn])) { | 8820 | if (likely(!child->perf_event_ctxp[ctxn])) |
| 8807 | perf_event_task(child, NULL, 0); | ||
| 8808 | return; | 8821 | return; |
| 8809 | } | ||
| 8810 | 8822 | ||
| 8811 | local_irq_save(flags); | 8823 | local_irq_save(flags); |
| 8812 | /* | 8824 | /* |
| @@ -8890,6 +8902,14 @@ void perf_event_exit_task(struct task_struct *child) · 77 unmodified lines | |||
| 8890 | 8902 | ||
| 8891 | for_each_task_context_nr(ctxn) | 8903 | for_each_task_context_nr(ctxn) |
| 8892 | perf_event_exit_task_context(child, ctxn); | 8904 | perf_event_exit_task_context(child, ctxn); |
| 8905 | |||
| 8906 | /* | ||
| 8907 | * The perf_event_exit_task_context calls perf_event_task | ||
| 8908 | * with child's task_ctx, which generates EXIT events for | ||
| 8909 | * child contexts and sets child->perf_event_ctxp[] to NULL. | ||
| 8910 | * At this point we need to send EXIT events to cpu contexts. | ||
| 8911 | */ | ||
| 8912 | perf_event_task(child, NULL, 0); | ||
| 8893 | } | 8913 | } |
| 8894 | 8914 | ||
| 8895 | static void perf_free_event(struct perf_event *event, | 8915 | static void perf_free_event(struct perf_event *event, |