While collecting samples using "perf record", function
"__cmd_record" checks if monitoring is done. Once recording
is done, event list will be disabled using "evlist__disable".
After this, event fd won't be read and event will be removed.

Before removing the event, if any additional data needs
to be captured/written to perf.data, currently its not
possible. Introduce arch_record__collect_final_data to
collect additional data before closing the event

Signed-off-by: Athira Rajeev <[email protected]>
---
 tools/perf/builtin-record.c | 29 +++++++++++++++++++++++++++++
 tools/perf/util/record.h    |  4 ++++
 2 files changed, 33 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ebd3ed0c9b3e..1312f7223455 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -2426,6 +2426,34 @@ static unsigned long record__waking(struct record *rec)
        return waking;
 }
 
+/*
+ * Weak symbol - architecture can override to indicate if more
+ * data needs to be collected before finishing output.
+ *
+ * Returns: 1 if more data exists, 0 if collection is complete
+ */
+__weak int arch_perf_record__need_read(struct evlist *evlist __maybe_unused)
+{
+       return 0;  /* Default: no arch-specific data to collect */
+}
+
+static void record__final_data(struct record *rec)
+{
+       /*
+        * Collect any remaining architecture-specific data.
+        * The arch code checks if more data exists, and we do the actual
+        * reading here since we have access to record__mmap_read_all().
+        */
+       while (arch_perf_record__need_read(rec->evlist)) {
+               if (record__mmap_read_all(rec, false) < 0)
+                       break;
+               /* Re-enable events for next batch */
+               evlist__enable(rec->evlist);
+       }
+
+       return;
+}
+
 static int __cmd_record(struct record *rec, int argc, const char **argv)
 {
        int err;
@@ -2853,6 +2881,7 @@ static int __cmd_record(struct record *rec, int argc, 
const char **argv)
                 */
                if (done && !disabled && !target__none(&opts->target)) {
                        trigger_off(&auxtrace_snapshot_trigger);
+                       record__final_data(rec);
                        evlist__disable(rec->evlist);
                        disabled = true;
                }
diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h
index 93627c9a7338..21f51efd36fc 100644
--- a/tools/perf/util/record.h
+++ b/tools/perf/util/record.h
@@ -8,6 +8,8 @@
 #include <linux/stddef.h>
 #include <linux/perf_event.h>
 #include "util/target.h"
+#include "util/evlist.h"
+#include "util/util.h"
 
 struct option;
 
@@ -95,4 +97,6 @@ static inline bool record_opts__no_switch_events(const struct 
record_opts *opts)
        return opts->record_switch_events_set && !opts->record_switch_events;
 }
 
+int arch_perf_record__need_read(struct evlist *evlist);
+
 #endif // _PERF_RECORD_H
-- 
2.52.0


Reply via email to