[PATCH 3/6] perf cs-etm: Synthesize missing HW_ID mappings for raw trace
From: James Clark
Date: Fri Aug 21 2026 - 06:04:43 EST
From: Leo Yan <leo.yan@xxxxxxx>
The CoreSight driver emits PERF_RECORD_AUX_OUTPUT_HW_ID via
perf_report_aux_output_id(). If the perf ring buffer is full,
perf_report_aux_output_id() can fail to emit the record and return
silently.
When at least one HW_ID record is present in the file, perf skips the
legacy metadata-only trace ID mapping path. Therefore any raw AUX queue
whose HW_ID record was dropped can be left with an empty traceid_list,
and cs_etm__create_queue_decoders() will not create a decoder for that
queue.
Backfill missing mappings for non-empty UNFORMATTED queues whose trace
ID map is still empty after the HW_ID record scan. Real HW_ID mappings
remain preferred and are not overwritten in case someone is trying to
link what the kernel outputs to the raw trace dump.
Signed-off-by: Leo Yan <leo.yan@xxxxxxx>
Signed-off-by: James Clark <james.clark@xxxxxxxxxx>
---
tools/perf/util/cs-etm.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 44e20067da1f..dd15e91b7b38 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -427,6 +427,39 @@ static int cs_etm__process_trace_id_v0_1(struct cs_etm_auxtrace *etm, int cpu,
return 0;
}
+static int cs_etm__synth_unformatted_trace_ids(struct cs_etm_auxtrace *etm)
+{
+ struct auxtrace_queues *queues = &etm->queues;
+
+ for (unsigned int i = 0; i < queues->nr_queues; i++) {
+ struct auxtrace_queue *queue = &queues->queue_array[i];
+ struct cs_etm_queue *etmq = queue->priv;
+ u64 *cpu_data;
+ u8 trace_id;
+ int ret;
+
+ if (list_empty(&queue->head) || !etmq || etmq->format != UNFORMATTED)
+ continue;
+
+ if (!intlist__empty(etmq->traceid_list))
+ continue;
+
+ cpu_data = get_cpu_data(etm, queue->cpu);
+ if (!cpu_data)
+ return -EINVAL;
+
+ ret = cs_etm__metadata_get_trace_id(&trace_id, cpu_data);
+ if (ret)
+ return ret;
+
+ ret = cs_etm__insert_trace_id_node(etmq, trace_id, cpu_data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int cs_etm__metadata_get_trace_id(u8 *trace_chan_id, u64 *cpu_metadata)
{
u64 cs_etm_magic = cpu_metadata[CS_ETM_MAGIC];
@@ -3801,6 +3834,16 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
goto err_free_queues;
}
+ /*
+ * Add fake IDs for any unformatted queues missing them. The IDs
+ * themselves are only cosmetic in unformatted mode (raw dump output),
+ * but a decoder won't be created if one was dropped and Perf can be
+ * resilient to this.
+ */
+ err = cs_etm__synth_unformatted_trace_ids(etm);
+ if (err)
+ goto err_free_queues;
+
err = cs_etm__create_decoders(etm);
if (err)
goto err_free_queues;
--
2.43.0