On 15/09/2026 16:49, Leo Yan wrote:
Per-thread and per-CPU timeless decoding use separate loops for the same buffer processing. Per-thread mode already collects packets in a single trace ID queue, so both modes can share the queue iteration.
Use cs_etm__run_timeless_decoder() for both modes, keeping the thread selection in the caller. Propagate packet processing and end-of-block errors through the common decoding path.
This is very similar to what I've done for the JIT patches. So if we've decided to base these patches of that one then this one won't be required or will look quite different. So I'll wait for the next version before reviewing in much more detail. The kernel changes look good though.
Assisted-by: Codex:gpt-6 Signed-off-by: Leo Yan leo.yan@arm.com
tools/perf/util/cs-etm.c | 68 ++++++++++++------------------------------------ 1 file changed, 16 insertions(+), 52 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index baa962085dba5226d9729a0ee8039374d5fcb1a0..1a53431161e995ba6b3cfdc86e338ed26e675774 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -2681,47 +2681,9 @@ static void cs_etm__clear_all_traceid_queues(struct cs_etm_queue *etmq) } } -static int cs_etm__run_per_thread_timeless_decoder(struct cs_etm_queue *etmq) +static int cs_etm__run_timeless_decoder(struct cs_etm_queue *etmq) {
- int err = 0;
- struct cs_etm_traceid_queue *tidq;
- tidq = cs_etm__etmq_get_traceid_queue(etmq, CS_ETM_PER_THREAD_TRACEID);
- if (!tidq)
return -EINVAL;- /* Go through each buffer in the queue and decode them one by one */
- while (1) {
err = cs_etm__get_data_block(etmq);if (err <= 0)return err;/* Run trace decoder until buffer consumed or end of trace */do {err = cs_etm__decode_data_block(etmq);if (err)return err;/** Process each packet in this chunk, nothing to do if* an error occurs other than hoping the next one will* be better.*/err = cs_etm__process_traceid_queue(etmq, tidq);} while (etmq->buf_len);if (err == 0)/* Flush any remaining branch stack entries */err = cs_etm__end_block(etmq, tidq);- }
- return err;
-}
-static int cs_etm__run_per_cpu_timeless_decoder(struct cs_etm_queue *etmq) -{
- int idx, err = 0;
- int idx, err; struct cs_etm_traceid_queue *tidq; struct int_node *inode;
@@ -2731,23 +2693,23 @@ static int cs_etm__run_per_cpu_timeless_decoder(struct cs_etm_queue *etmq) if (err <= 0) return err;
/* Run trace decoder until buffer consumed or end of trace */
do { err = cs_etm__decode_data_block(etmq); if (err) return err;/* Run trace decoder until the input buffer is consumed. *//*
* cs_etm__run_per_thread_timeless_decoder() runs on a* single traceID queue because each TID has a separate* buffer. But here in per-cpu mode we need to iterate* over each channel instead.
* Per-thread decoding uses a single traceID queue;* formatted per-CPU buffers can contain several. */ intlist__for_each_entry(inode, etmq->traceid_queues_list) { idx = (int)(intptr_t)inode->priv; tidq = etmq->traceid_queues[idx];
cs_etm__process_traceid_queue(etmq, tidq);
err = cs_etm__process_traceid_queue(etmq, tidq);if (err) } while (etmq->buf_len);return err; }@@ -2760,8 +2722,6 @@ static int cs_etm__run_per_cpu_timeless_decoder(struct cs_etm_queue *etmq) return err; } }
- return err; }
static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, @@ -2774,6 +2734,7 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, struct auxtrace_queue *queue = &etm->queues.queue_array[i]; struct cs_etm_queue *etmq = queue->priv; struct cs_etm_traceid_queue *tidq;
int err;if (!etmq) continue; @@ -2785,10 +2746,13 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, if (!tidq) continue;
if (tid == -1 || thread__tid(tidq->frontend_thread) == tid)cs_etm__run_per_thread_timeless_decoder(etmq);} elsecs_etm__run_per_cpu_timeless_decoder(etmq);
if (tid != -1 && thread__tid(tidq->frontend_thread) != tid)continue;}err = cs_etm__run_timeless_decoder(etmq);if (err) }return err;return 0;