Re: [PATCH V9 02/13] perf/core: Add aux_pause, aux_resume, aux_start_paused

From: Peter Zijlstra
Date: Thu Jul 18 2024 - 05:39:14 EST


On Mon, Jul 15, 2024 at 07:07:01PM +0300, Adrian Hunter wrote:
> Hardware traces, such as instruction traces, can produce a vast amount of
> trace data, so being able to reduce tracing to more specific circumstances
> can be useful.
>
> The ability to pause or resume tracing when another event happens, can do
> that.
>
> Add ability for an event to "pause" or "resume" AUX area tracing.
>
> Add aux_pause bit to perf_event_attr to indicate that, if the event
> happens, the associated AUX area tracing should be paused. Ditto
> aux_resume. Do not allow aux_pause and aux_resume to be set together.
>
> Add aux_start_paused bit to perf_event_attr to indicate to an AUX area
> event that it should start in a "paused" state.
>
> Add aux_paused to struct hw_perf_event for AUX area events to keep track of
> the "paused" state. aux_paused is initialized to aux_start_paused.
>
> Add PERF_EF_PAUSE and PERF_EF_RESUME modes for ->stop() and ->start()
> callbacks. Call as needed, during __perf_event_output(). Add

Why in __perf_event_output() rather than in __perf_event_overflow().
Specifically, before bpf_overflow_handler().

That is, what do we want BPF to be able to do here? To me it seems
strange that BPF would be able to affect this functionality. You want
this pause/resume to happen irrespective of how the rest of the event is
processed, no?

> aux_in_pause_resume to struct perf_buffer to prevent races with the NMI
> handler. Pause/resume in NMI context will miss out if it coincides with
> another pause/resume.

I'm struggling here. That variable is only ever used inside that one
function. So it must be self-recursion. Are you thinking something like:

swevent_overflow()
...
event_aux_pause()
<NMI>
event_overflow()
...
event_aux_pause()

?

Where two events in the group, one software and one hardware, are both
trying to control the AUX thing? Because I don't think the PT-PMI ever
gets here.

> To use aux_pause or aux_resume, an event must be in a group with the AUX
> area event as the group leader.


> @@ -402,6 +411,15 @@ struct pmu {
> *
> * ->start() with PERF_EF_RELOAD will reprogram the counter
> * value, must be preceded by a ->stop() with PERF_EF_UPDATE.
> + *
> + * ->stop() with PERF_EF_PAUSE will stop as simply as possible. Will not
> + * overlap another ->stop() with PERF_EF_PAUSE nor ->start() with
> + * PERF_EF_RESUME.
> + *
> + * ->start() with PERF_EF_RESUME will start as simply as possible but
> + * only if the counter is not otherwise stopped. Will not overlap
> + * another ->start() with PERF_EF_RESUME nor ->stop() with
> + * PERF_EF_PAUSE.
> */
> void (*start) (struct perf_event *event, int flags);
> void (*stop) (struct perf_event *event, int flags);

Notably, they *can* race with ->stop/start without EF_PAUSE/RESUME.