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 | 5696 | static void |
| 5686 | 5697 | perf_event_aux(perf_event_aux_output_cb output, void *data, |
| 5687 | 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 | 5702 | struct pmu *pmu; |
| 5692 | 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 | 5716 | rcu_read_lock(); |
| 5695 | 5717 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
| 5696 | 5718 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
| 5697 | 5719 | if (cpuctx->unique_pmu != pmu) |
| 5698 | 5720 | goto next; |
| 5699 | 5721 | perf_event_aux_ctx(&cpuctx->ctx, output, data); |
| 5700 | − if (task_ctx) | |
| 5701 | − goto next; | |
| 5702 | 5722 | ctxn = pmu->task_ctx_nr; |
| 5703 | 5723 | if (ctxn < 0) |
| 5704 | 5724 | goto next; |
| @@ -5708,12 +5728,6 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, · 3 unmodified lines | ||
| 5708 | 5728 | next: |
| 5709 | 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 | 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 | 8817 | struct perf_event_context *child_ctx, *clone_ctx = NULL; |
| 8804 | 8818 | unsigned long flags; |
| 8805 | 8819 | |
| 8806 | − if (likely(!child->perf_event_ctxp[ctxn])) { | |
| 8807 | − perf_event_task(child, NULL, 0); | |
| 8820 | + if (likely(!child->perf_event_ctxp[ctxn])) | |
| 8808 | 8821 | return; |
| 8809 | − } | |
| 8810 | 8822 | |
| 8811 | 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 | 8903 | for_each_task_context_nr(ctxn) |
| 8892 | 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 | 8915 | static void perf_free_event(struct perf_event *event, |