[PATCH 09/14] perf cs-etm: Queue partial AUX records
James Clark
james.clark at linaro.org
Tue Aug 11 08:30:12 PDT 2026
In snapshot mode AUX records may straddle the boundary of multiple trace
buffers. Currently we only queue AUX records whose range is contained
wholly within a single buffer.
Fix it by queuing any partial AUX range that overlaps any buffer.
Signed-off-by: James Clark <james.clark at linaro.org>
---
tools/perf/util/cs-etm.c | 54 +++++++++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 24 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 28f5ce63ba80..5bafee31cf4b 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -3197,7 +3197,8 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o
union perf_event *auxtrace_event_union;
struct perf_record_auxtrace *auxtrace_event;
union perf_event auxtrace_fragment;
- __u64 aux_offset, aux_size;
+ __u64 aux_start, aux_end, auxtrace_start, auxtrace_end;
+ __u64 frag_start, frag_end, frag_size;
enum cs_etm_format format;
struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
@@ -3245,42 +3246,41 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o
}
if (aux_event->flags & PERF_AUX_FLAG_OVERWRITE) {
- /*
- * Clamp size in snapshot mode. The buffer size is clamped in
- * __auxtrace_mmap__read() for snapshots, so the aux record size doesn't reflect
- * the buffer size.
- */
- aux_size = min(aux_event->aux_size, auxtrace_event->size);
-
/*
* In this mode, the head also points to the end of the buffer so aux_offset
* needs to have the size subtracted so it points to the beginning as in normal mode
*/
- aux_offset = aux_event->aux_offset - aux_size;
+ aux_start = aux_event->aux_offset - aux_event->aux_size;
+ aux_end = aux_event->aux_offset;
} else {
- aux_size = aux_event->aux_size;
- aux_offset = aux_event->aux_offset;
+ aux_start = aux_event->aux_offset;
+ aux_end = aux_event->aux_offset + aux_event->aux_size;
}
- if (aux_offset >= auxtrace_event->offset &&
- aux_offset + aux_size <= auxtrace_event->offset + auxtrace_event->size) {
+ auxtrace_start = auxtrace_event->offset;
+ auxtrace_end = auxtrace_start + auxtrace_event->size;
+ frag_start = max(aux_start, auxtrace_start);
+ frag_end = min(aux_end, auxtrace_end);
+
+ if (frag_start < frag_end) {
struct cs_etm_queue *etmq = cs_etm__get_queue(etm, sample->cpu);
if (!etmq)
return -EINVAL;
/*
- * If this AUX event was inside this buffer somewhere, create a new auxtrace event
- * based on the sizes of the aux event, and queue that fragment.
+ * If this AUX event overlaps this buffer, create a new auxtrace event
+ * for the overlapping range and queue that fragment.
*/
+ frag_size = frag_end - frag_start;
auxtrace_fragment.auxtrace = *auxtrace_event;
- auxtrace_fragment.auxtrace.size = aux_size;
- auxtrace_fragment.auxtrace.offset = aux_offset;
+ auxtrace_fragment.auxtrace.size = frag_size;
+ auxtrace_fragment.auxtrace.offset = frag_start;
auxtrace_fragment.auxtrace.idx = etmq->queue_nr;
- file_offset += aux_offset - auxtrace_event->offset + auxtrace_event->header.size;
+ file_offset += frag_start - auxtrace_start + auxtrace_event->header.size;
pr_debug3("CS ETM: Queue buffer size: %#"PRI_lx64" offset: %#"PRI_lx64
- " tid: %d cpu: %d\n", aux_size, aux_offset, sample->tid, sample->cpu);
+ " tid: %d cpu: %d\n", frag_size, frag_start, sample->tid, sample->cpu);
err = auxtrace_queues__add_event(&etm->queues, session, &auxtrace_fragment,
file_offset, NULL);
if (err)
@@ -3320,6 +3320,7 @@ static int cs_etm__queue_aux_records_cb(struct perf_session *session, union perf
struct auxtrace_index *auxtrace_index;
struct evsel *evsel;
size_t i;
+ bool found = false;
/* Don't care about any other events, we're only queuing buffers for AUX events */
if (event->header.type != PERF_RECORD_AUX)
@@ -3353,11 +3354,14 @@ static int cs_etm__queue_aux_records_cb(struct perf_session *session, union perf
ret = cs_etm__queue_aux_fragment(session, ent->file_offset,
ent->sz, &event->aux, &sample);
/*
- * Stop search on error or successful values. Continue search on
- * 1 ('not found')
+ * Stop search on error values. Continue search on
+ * 1 ('not found') or 0 ('queued')
*/
- if (ret != 1)
+ if (ret < 0)
goto out;
+
+ if (!ret)
+ found = true;
}
}
@@ -3365,8 +3369,10 @@ static int cs_etm__queue_aux_records_cb(struct perf_session *session, union perf
* Couldn't find the buffer corresponding to this aux record, something went wrong. Warn but
* don't exit with an error because it will still be possible to decode other aux records.
*/
- pr_err("CS ETM: Couldn't find auxtrace buffer for aux_offset: %#"PRI_lx64
- " tid: %d cpu: %d\n", event->aux.aux_offset, sample.tid, sample.cpu);
+ if (!found) {
+ pr_err("CS ETM: Couldn't find auxtrace buffer for aux_offset: %#"PRI_lx64
+ " tid: %d cpu: %d\n", event->aux.aux_offset, sample.tid, sample.cpu);
+ }
ret = 0;
out:
perf_sample__exit(&sample);
--
2.43.0
More information about the linux-arm-kernel
mailing list