[PATCH v2] perf/core: Skip empty AUX records with only format flags

From: Leo Yan

Date: Thu Aug 27 2026 - 10:24:49 EST


perf_aux_output_end() emits a PERF_RECORD_AUX when the recorded size is
nonzero or when any flag other than PERF_AUX_FLAG_OVERWRITE is set.

PMU format flags describe how an AUX payload is encoded. TRBE driver
sets PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW for raw trace buffers, causing
an AUX record to be emitted even when no trace data.

This is noticeable when tracing a task with strace. Ptrace stops
repeatedly end empty AUX transactions, producing many zero-sized
PERF_RECORD_AUX records. For example:

perf record -e cs_etm//u -m,128M -- strace ls

perf script -D 2>&1 |
awk '/PERF_RECORD_AUX offset/ {
for (i = 1; i <= NF; i++)
if ($i == "size:" && $(i + 1) == "0")
count++
}
END { print count }'
165

This recording contains 165 zero-sized AUX records which provide no
useful information to userspace.

Introduce a helper perf_aux_flags_need_record() to check if need to
emit an empty PERF_RECORD_AUX record for AUX flags. Allow TRUNCATED,
PARTIAL and COLLISION, which remain meaningful without trace data.
Move the comment to the helper for readable.

Keeping an explicit list also ensures that future flags are evaluated
before they are permitted to generate empty records.

Fixes: 547b60988e63 ("perf: aux: Add flags for the buffer format")
Reported-by: Tamas Petz <tamas.petz@xxxxxxx>
Reviewed-by: James Clark <james.clark@xxxxxxxxxx>
Signed-off-by: Leo Yan <leo.yan@xxxxxxx>
---
Changes in v2:
- Used flag list for generating RECORD_AUX (James).
- Link to v1: https://lore.kernel.org/r/20260825-perf_core_fix_zero_aux_records-v1-1-23b95e8d5df3@xxxxxxx
---
kernel/events/ring_buffer.c | 44 +++++++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 9fe92161715e0987520cddb873dd162fd2a77d5c..e81b987319de4707aea46243b5f04ae368e57820 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -477,6 +477,35 @@ static __always_inline bool rb_need_aux_wakeup(struct perf_buffer *rb)
return false;
}

+/*
+ * Emit an empty PERF_RECORD_AUX only for flags that report conditions which
+ * userspace needs to observe. Keep an explicit list so that future flags
+ * are evaluated before they are permitted to generate empty records.
+ *
+ * TRUNCATED, PARTIAL and COLLISION report trace loss, gaps or collisions and
+ * remain meaningful even when the record contains no trace data.
+ *
+ * OVERWRITE records by themselves are not considered useful, as they don't
+ * communicate any *new* information, aside from the short-lived offset, that
+ * becomes history at the next event sched-in and therefore isn't useful. The
+ * userspace that needs to copy out AUX data in overwrite mode should know to
+ * use user_page::aux_head for the actual offset. So, from now on we don't
+ * output AUX records that have *only* OVERWRITE flag set.
+ *
+ * PMU format flags describe how to interpret an AUX payload and provide no
+ * useful information when there is no payload, so don't include them.
+ */
+static __always_inline
+bool perf_aux_flags_need_record(struct perf_output_handle *handle)
+{
+ if (handle->aux_flags & (PERF_AUX_FLAG_TRUNCATED |
+ PERF_AUX_FLAG_PARTIAL |
+ PERF_AUX_FLAG_COLLISION))
+ return true;
+
+ return false;
+}
+
/*
* Commit the data written by hardware into the ring buffer by adjusting
* aux_head and posting a PERF_RECORD_AUX into the perf buffer. It is the
@@ -506,19 +535,8 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size)
rb->aux_head += size;
}

- /*
- * Only send RECORD_AUX if we have something useful to communicate
- *
- * Note: the OVERWRITE records by themselves are not considered
- * useful, as they don't communicate any *new* information,
- * aside from the short-lived offset, that becomes history at
- * the next event sched-in and therefore isn't useful.
- * The userspace that needs to copy out AUX data in overwrite
- * mode should know to use user_page::aux_head for the actual
- * offset. So, from now on we don't output AUX records that
- * have *only* OVERWRITE flag set.
- */
- if (size || (handle->aux_flags & ~(u64)PERF_AUX_FLAG_OVERWRITE))
+ /* Only send RECORD_AUX if we have something useful to communicate */
+ if (size || perf_aux_flags_need_record(handle))
perf_event_aux_event(handle->event, aux_head, size,
handle->aux_flags);


---
base-commit: 66498c75b4f8017f62d720d9b59675bdf3abce91
change-id: 20260825-perf_core_fix_zero_aux_records-8873172d2596

Best regards,
--
Leo Yan <leo.yan@xxxxxxx>