perf cs-etm: Flush thread stacks after decoder reset

Perf resets the CoreSight decoder when moving to a new AUX trace buffer,
this causes trace discontinunity globally.

For callchain synthesis, keeping thread-stack state after decoder reset
can leave stale call/return history attached to threads that are decoded
later, producing incorrect synthesized callchains.

Flush all host thread stacks after a decoder reset. When virtualization
is present, flush the guest thread stacks as well.

Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Leo Yan
2026-07-02 20:51:41 +01:00
committed by Namhyung Kim
parent 3ea91599b7
commit ea5075e377

View File

@@ -2033,6 +2033,45 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
return 0;
}
static int cs_etm__flush_stack_cb(struct thread *thread,
void *data __maybe_unused)
{
thread_stack__flush(thread);
return 0;
}
static void cs_etm__flush_machine_stack(struct cs_etm_queue *etmq, pid_t pid)
{
struct machine *machine;
machine = machines__find(&etmq->etm->session->machines, pid);
if (machine)
machine__for_each_thread(machine, cs_etm__flush_stack_cb, NULL);
}
static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq)
{
enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
if (!etmq->etm->synth_opts.last_branch)
return;
switch (pid_fmt) {
case CS_ETM_PIDFMT_CTXTID2:
/* Clear the guest stack if virtualization is supported */
cs_etm__flush_machine_stack(etmq, DEFAULT_GUEST_KERNEL_ID);
fallthrough;
case CS_ETM_PIDFMT_CTXTID:
cs_etm__flush_machine_stack(etmq, HOST_KERNEL_ID);
break;
case CS_ETM_PIDFMT_NONE:
default:
break;
}
}
/*
* cs_etm__get_data_block: Fetch a block from the auxtrace_buffer queue
* if need be.
@@ -2055,6 +2094,12 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq)
ret = cs_etm_decoder__reset(etmq->decoder);
if (ret)
return ret;
/*
* Since the decoder is reset, this causes a global trace
* discontinuity. Flush all thread stacks.
*/
cs_etm__flush_all_stack(etmq);
}
return etmq->buf_len;