diff mbox series

[4/9] tracecmd library: Add tracecmd_iterate_events_multi()

Message ID 20220805154040.2014381-5-rostedt@goodmis.org (mailing list archive)
State Accepted
Commit b37903ae5fb53db147519f3e51b28e2647ed8de9
Headers show
Series trace-cmd library: Add and use new helper functions | expand

Commit Message

Steven Rostedt Aug. 5, 2022, 3:40 p.m. UTC
From: "Steven Rostedt (Google)" <rostedt@goodmis.org>

Add a helper function that takes an array of tracecmd_input handles and
calls the callback for each event in order of the record's timestamp for
each handle.

Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 include/trace-cmd/trace-cmd.h |  6 +++
 lib/trace-cmd/trace-input.c   | 91 +++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)
diff mbox series

Patch

diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index b91235751d64..86a3486972cc 100644
--- a/include/trace-cmd/trace-cmd.h
+++ b/include/trace-cmd/trace-cmd.h
@@ -54,6 +54,12 @@  int tracecmd_iterate_events(struct tracecmd_input *handle,
 					    struct tep_record *,
 					    int, void *),
 			    void *callback_data);
+int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
+				  int nr_handles,
+				  int (*callback)(struct tracecmd_input *handle,
+						  struct tep_record *,
+						  int, void *),
+				  void *callback_data);
 
 void tracecmd_set_loglevel(enum tep_loglevel level);
 
diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
index e990600ad6b1..5df10716013d 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -170,6 +170,7 @@  struct tracecmd_input {
 	int			page_map_size;
 	int			max_cpu;
 	int			cpus;
+	int			start_cpu;
 	int			ref;
 	int			nr_buffers;	/* buffer instances */
 	bool			use_trace_clock;
@@ -2581,6 +2582,96 @@  int tracecmd_iterate_events(struct tracecmd_input *handle,
 	return ret;
 }
 
+struct record_handle {
+	struct tep_record		*record;
+	struct tracecmd_input		*handle;
+};
+
+/**
+ * tracecmd_iterate_events_multi - iterate events over multiple handles
+ * @handles: An array of handles to iterate over
+ * @nr_handles: The number of handles in the @handles array.
+ * @callback: The callback function for each event
+ * @callback_data: The data to pass to the @callback.
+ *
+ * Will loop over all CPUs for each handle in @handles and call the
+ * @callback in the order of the timestamp for each event's record
+ * for each handle.
+ *
+ * Returns the -1 on error, or the value of the callbacks.
+ */
+int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
+				  int nr_handles,
+				  int (*callback)(struct tracecmd_input *handle,
+						  struct tep_record *,
+						  int, void *),
+				  void *callback_data)
+{
+	struct tracecmd_input *handle;
+	struct record_handle *records;
+	struct tep_record *record;
+	unsigned long long last_timestamp = 0;
+	int next_cpu;
+	int cpus = 0;
+	int all_cpus = 0;
+	int cpu;
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < nr_handles; i++) {
+		handle = handles[i];
+		cpus += handle->max_cpu;
+	}
+
+	records = calloc(cpus, sizeof(*records));
+	if (!records)
+		return -1;
+
+	for (i = 0; i < nr_handles; i++) {
+		handle = handles[i];
+		handle->start_cpu = all_cpus;
+		for (cpu = 0; cpu < handle->max_cpu; cpu++) {
+			records[all_cpus + cpu].record = tracecmd_peek_data(handle, cpu);
+			records[all_cpus + cpu].handle = handle;
+		}
+		all_cpus += cpu;
+	}
+
+	do {
+		next_cpu = -1;
+		for (cpu = 0; cpu < all_cpus; cpu++) {
+			record = records[cpu].record;
+			if (!record)
+				continue;
+
+			if (next_cpu < 0 || record->ts < last_timestamp) {
+				next_cpu = cpu;
+				last_timestamp = record->ts;
+			}
+		}
+		if (next_cpu >= 0) {
+			record = records[next_cpu].record;
+			handle = records[next_cpu].handle;
+			cpu = next_cpu - handle->start_cpu;
+			/* Need to call read_data to increment to the next record */
+			record = tracecmd_read_data(handle, cpu);
+			records[next_cpu].record = tracecmd_peek_data(handle, cpu);
+
+			ret = callback(handle, record, cpu, callback_data);
+			tracecmd_free_record(record);
+		}
+
+	} while (next_cpu >= 0 && ret >= 0);
+
+	/*
+	 * The records array contains only records that were taken via
+	 * tracecmd_peek_data(), and do not need to be freed.
+	 */
+	free(records);
+
+	return ret;
+}
+
 /**
  * tracecmd_peek_next_data - return the next record
  * @handle: input handle to the trace.dat file