find_snapshot() isn't implemented for Coresight, so when a wrap occurs we only save from offset 0 to current head, modulo buffer size, rather than capturing the whole buffer. Coresight drivers currently use a monotonic head pointer even in snapshot mode, which gives a lot more information for taking snapshots than a wrapped pointer. It means we don't need to search for data at the end of the buffer to guess if a wrap has occurred, and we can go back to saving partial buffers after a wrap by checking if the next size to take is less than the buffer size.
The drivers will always be able to generate a monotonic head because TRBE has a bytes written counter, so even if we stop generating an AUX record on every overflow, we can check if the counter indicated an overwrite and offset head by a whole buffer size if it wrapped. This forces userspace to read the whole buffer rather than between last and current head. ETR and other sinks use software double buffering, so can continue as they are.
Add auxtrace_record__monotonic_find_snapshot() and use it for Coresight. A monotonic head can't be auto-detected in the default find_snapshot() by checking if head > buffer size, because before the first wrap a monotonic head looks the same as a wrapped one. The search would then falsely detect a wrap when head is near the end of the buffer, and the wrapped pointer fixup moves 'old' and 'head' a whole buffer ahead of the driver's head. With a wrapped head that doesn't matter because only the offset within the buffer is used, but with a monotonic head the next snapshot would either save already saved data again or drop up to a buffer's worth of new data.
Signed-off-by: James Clark james.clark@linaro.org --- tools/perf/arch/arm/util/cs-etm.c | 1 + .../perf/tests/shell/coresight/raw_dump_stress.sh | 5 ----- tools/perf/util/auxtrace.c | 23 ++++++++++++++++++++++ tools/perf/util/auxtrace.h | 4 ++++ 4 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 5e7d09b7170c..84a5d7392a5f 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -922,6 +922,7 @@ struct auxtrace_record *cs_etm_record_init(int *err) ptr->itr.info_fill = cs_etm_info_fill; ptr->itr.snapshot_start = cs_etm_snapshot_start; ptr->itr.snapshot_finish = cs_etm_snapshot_finish; + ptr->itr.find_snapshot = auxtrace_record__monotonic_find_snapshot; ptr->itr.reference = cs_etm_reference; ptr->itr.free = cs_etm_recording_free; ptr->itr.read_finish = auxtrace_record__read_finish; diff --git a/tools/perf/tests/shell/coresight/raw_dump_stress.sh b/tools/perf/tests/shell/coresight/raw_dump_stress.sh index bea70d825596..c9459ded4cbe 100755 --- a/tools/perf/tests/shell/coresight/raw_dump_stress.sh +++ b/tools/perf/tests/shell/coresight/raw_dump_stress.sh @@ -48,11 +48,6 @@ read -r size offset last_idx <<< "$(awk ' # everything was dumped. Allow 48 bytes difference to cover 3 frames: current # frame length, a partial frame and a final empty one, all of which aren't # dumped. -# -# TODO: for a single snapshot, offset should always be zero. However, we -# currently output AUX records in snapshot mode when we shouldn't, which -# increments the offset. Allow for that until it's fixed so we can test raw -# dumping. decode_size=$((1 + last_idx - offset)) if [ "$decode_size" -gt "$((size - 48))" ] && [ "$decode_size" -le "$((size))" ]; then echo "PASS: AUXTRACE buffer length matches dumped packet index" diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index c613efd83223..3aabf2f4bd47 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -750,6 +750,29 @@ int auxtrace_record__default_find_snapshot(struct auxtrace_record *itr, int idx, return 0; }
+/* + * auxtrace_record::find_snapshot() implementation for drivers that don't wrap + * 'head' in snapshot mode, so it's already monotonic like in full trace mode. + * No search is needed, only force a full buffer read if more than a buffer's + * worth of data was written since the last read. + */ +int auxtrace_record__monotonic_find_snapshot(struct auxtrace_record *itr __maybe_unused, + int idx, struct auxtrace_mmap *mm, + unsigned char *data __maybe_unused, + u64 *head, u64 *old) +{ + pr_debug3("%s: mmap index %d old head 0x%"PRIx64" new head 0x%"PRIx64"\n", + __func__, idx, *old, *head); + + if (*head - *old > mm->len) { + *old = *head - mm->len; + pr_debug3("%s: wrap-around detected, adjusted old head 0x%"PRIx64"\n", + __func__, *old); + } + + return 0; +} + int auxtrace_record__options(struct auxtrace_record *itr, struct evlist *evlist, struct record_opts *opts) diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 9d86f8366ad7..980acb2dc687 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -607,6 +607,10 @@ int auxtrace_record__default_find_snapshot(struct auxtrace_record *itr, int idx, struct auxtrace_mmap *mm, unsigned char *data, u64 *head, u64 *old); +int auxtrace_record__monotonic_find_snapshot(struct auxtrace_record *itr, + int idx, struct auxtrace_mmap *mm, + unsigned char *data, u64 *head, + u64 *old); void auxtrace_record__snapshot_fixup(struct auxtrace_mmap *mm, bool wrapped, u64 *head, u64 *old); u64 auxtrace_record__reference(struct auxtrace_record *itr);