diff options
| author | Leo Yan <leo.yan@arm.com> | 2026-07-02 20:51:41 +0100 |
|---|---|---|
| committer | Namhyung Kim <namhyung@kernel.org> | 2026-07-03 16:51:59 -0700 |
| commit | ea5075e3776846d4941dddf1549426ebd3feb81f (patch) | |
| tree | b511e8d34d449bc92f8114f76345469c1e758ecf | |
| parent | 3ea91599b7b6e05cd21dfa1214f251dfe7770468 (diff) | |
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>
| -rw-r--r-- | tools/perf/util/cs-etm.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index ba9ffb7bdb4b..996317687ce7 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -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; |
