[PATCH 0/9] perf cs-etm: Add branch history to existing samples

James Clark james.clark at linaro.org
Wed Aug 12 07:26:56 PDT 2026



On 03/08/2026 10:01, Amir Ayupov wrote:
> This series implements --itrace=L for Arm CoreSight ETM: decoded branch

Hi Amir,

How did you send this? The cover letter seems to be on a different 
thread to the patches.

> history is attached to the PMU samples already present in the recording,
> rather than to synthesised instruction samples.
> 
> The motivating use case is context-sensitive PGO, which wants a callchain
> and a branch stack describing the same point in time. Recording a cycles
> event with call-graph=fp and aux-action=pause supplies the callchain, and
> the ETM trace leading up to that sample supplies the branch stack, without
> having to trace a long-running process continuously.
> 
> Intel PT has had this since commit f0a0251cee80 ("perf intel-pt: Add
> support for synthesizing branch stacks for regular events"), so this
> deliberately follows intel-pt: the same --itrace=L option and the same
> thread_stack__br_sample_late() call.
> 
> Patches 1 to 4 are independent fixes and infrastructure the feature needs:
> 
>    1  makes an inconsistent HEADER_GROUP_DESC non-fatal. AUX recordings
>       using aux-action pause/resume produce a group descriptor the strict
>       reader rejects, which makes an otherwise readable perf.data
>       unreadable, so without this the recipe in patch 9 cannot be decoded
>       at all. Useful on its own.
>    2  reports hw_idx as -1 rather than 0 in reconstructed branch stacks,
>       since they have no hardware index.
>    3  bounds a wrapped memcpy in thread_stack__br_sample(). Latent today,
>       reachable once a caller keeps a ring larger than the requested output
>       depth.
>    4  adds a dlfilter that drops samples with an empty branch stack.
> 
> Patch 5 is a no-functional-change refactor splitting
> cs_etm__process_timestamped_queues() into its three parts. Heap seeding
> moves to cs_etm__update_queues(), gated on queues.new_data and mirroring
> intel_pt_update_queues(); the end-of-session flush moves to
> cs_etm__flush_timestamped_queues(); and the decode loop is left on its own
> so patch 6 can drive it once per sample. Neither seeding nor flushing can
> be repeated, which is why they have to come out first. The moved code is
> unchanged, so both loops appear as context in the diff.
> 
> Patch 6 is the feature and patch 7 adds a shell test.
> 
> Patch 8 is where review attention is most useful. --itrace=L attaches
> whatever the thread stack holds when a sample is processed. With a duty
> cycled trace most samples fire while the trace is off; they have nothing
> newly decoded, but the thread stack still holds the previous window, so
> they were being given branches that ran an arbitrary amount of time
> earlier. On a 12 s capture with pause period 100003 and resume period
> 8350251, of 335291 samples that received branch history only 3371 were
> backed by trace decoded for that sample.
> 
> A trace window belongs to exactly one sample, and with AUX pause and
> resume the sample is what stops the trace, so the pairing is one to one by

What happens when aux-pause isn't used and there isn't a 1:1 pairing? 
There is a lot of description of that which implies that it doesn't work 
if there isn't. But as far as I can tell it works just as well by using 
the timestamps?

> construction. Patch 8 therefore takes the branch history when attaching it
> instead of copying it, and a later sample with nothing newly decoded finds
> an empty branch stack, which the dlfilter removes.
> thread_stack__br_sample() is unchanged, so lowercase --itrace=l keeps the
> overlapping branch stacks it produces today.
> 
> Patch 9 documents the workflow.
> 
> Because the sample is what stops the trace, the history attached to it
> lines up well with the callchain: on a brstack capture the leaf of the
> callchain matched the function containing the newest branch stack entry's
> target for 93.5% of attached samples. The residual comes from the decode
> loop stopping on interpolated timestamps, so a few branches that ran just
> after the sample can still be included. Trimming those with the sample ip
> raises it to 96.8%, but that matters far more for free-running ETM
> strobing than for pause and resume, so I have left it out of this series
> and will send it separately.
> 
> Patch 8 could be squashed into patch 6, since patch 6 on its own produces
> mostly stale history. I kept them apart so the decode mechanism and the
> attachment policy can be reviewed separately, but I am happy to fold them.
> 
> Testing
> -------
> 
> Built with:
> 
>    make -C tools/perf NO_LIBELF=1 NO_LIBTRACEEVENT=1 CORESIGHT=1
> 
> Every patch builds individually. checkpatch reports only "does MAINTAINERS
> need updating?" for the two new files and "quoted string split across
> lines" for the dlfilter description string, which matches how
> dlfilter-show-cycles.c already writes it.
> 
> Tested on Arm Neoverse V2 with CoreSight ETM:
> 
>    - perf test "CoreSight branch history on existing samples": Ok, 3 for 3
>    - captures from 5 MiB to 2.5 GiB decoded with --itrace=L64, no decode
>      errors
>    - the other CoreSight tests are unchanged by this series; four of them
>      fail identically at the base commit on this machine

Can you report or investigate these failures please. None of the tests 
should be failing on TRBE hardware, at least on the latest 
perf-tools-next branch. You can try applying "[PATCH 00/14] perf cs-etm: 
Per-thread mode fixes and snapshot wrap support" to be sure, but I don't 
think that fixes any current failures.

> 
> Amir Ayupov (9):
>    perf header: Tolerate inconsistent HEADER_GROUP_DESC
>    perf thread-stack: Report branch stack hw_idx as not available
>    perf thread-stack: Bound wrapped branch stack copy
>    perf dlfilter: Add non-empty branch stack filter
>    perf cs-etm: Split up cs_etm__process_timestamped_queues()
>    perf cs-etm: Add branch history to existing samples
>    perf test cs-etm: Test branch history on existing samples
>    perf cs-etm: Consume branch history when attaching it to a sample
>    Documentation: coresight: Document context-sensitive PGO workflow
> 
>   .../trace/coresight/coresight-perf.rst        |  62 +++++
>   tools/perf/Makefile.perf                      |   1 +
>   .../dlfilters/dlfilter-nonempty-brstack.c     |  26 ++
>   .../tests/shell/coresight/add_last_branch.sh  | 175 +++++++++++++
>   tools/perf/util/cs-etm.c                      | 242 ++++++++++++++++--
>   tools/perf/util/header.c                      |  42 ++-
>   tools/perf/util/thread-stack.c                |  21 +-
>   tools/perf/util/thread-stack.h                |   1 +
>   8 files changed, 544 insertions(+), 26 deletions(-)
>   create mode 100644 tools/perf/dlfilters/dlfilter-nonempty-brstack.c
>   create mode 100755 tools/perf/tests/shell/coresight/add_last_branch.sh
> 
> 
> base-commit: da85966dfd23a3b03e00ee3bce6ad301f0a2b229




More information about the linux-arm-kernel mailing list