aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Google) <rostedt@goodmis.org>2022-08-05 11:40:35 -0400
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-08-05 11:45:10 -0400
commitb37903ae5fb53db147519f3e51b28e2647ed8de9 (patch)
tree5b2cbd9a157f3afc3016f31246af3bceb54531e8
parentd83b6628927326d158ccd5766dea42cb5925b051 (diff)
downloadtrace-cmd-b37903ae5fb53db147519f3e51b28e2647ed8de9.tar.gz
tracecmd library: Add tracecmd_iterate_events_multi()
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. Link: https://lore.kernel.org/linux-trace-devel/20220805154040.2014381-5-rostedt@goodmis.org Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-rw-r--r--include/trace-cmd/trace-cmd.h6
-rw-r--r--lib/trace-cmd/trace-input.c91
2 files changed, 97 insertions, 0 deletions
diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index b9123575..86a34869 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 e990600a..5df10716 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