aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Google) <rostedt@goodmis.org>2022-09-21 21:37:36 -0400
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-09-21 21:53:41 -0400
commit3cd1b55f321ff8dc68d340aab0d8d0f159cde094 (patch)
tree9a2b41134d41587b82c100d12cc38aa777231524
parent27ea9e11f8eb3c6f0e2f812a0d340ceff4404e2a (diff)
downloadtrace-cmd-3cd1b55f321ff8dc68d340aab0d8d0f159cde094.tar.gz
trace-cmd library: Add tracecmd_follow_event()
Add the tracecmd_follow_event() to make it easier for applications to have a callback for specific events when calling either tracecmd_iterate_events() or tracecmd_iterate_events_multi() Link: https://lore.kernel.org/linux-trace-devel/20220922013737.3302850-2-rostedt@goodmis.org Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-rw-r--r--include/trace-cmd/trace-cmd.h8
-rw-r--r--lib/trace-cmd/trace-input.c117
2 files changed, 119 insertions, 6 deletions
diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index bcbf9d78..bc5edb4d 100644
--- a/include/trace-cmd/trace-cmd.h
+++ b/include/trace-cmd/trace-cmd.h
@@ -55,6 +55,14 @@ struct tracecmd_input *tracecmd_buffer_instance_handle(struct tracecmd_input *ha
void tracecmd_set_private(struct tracecmd_input *handle, void *data);
void *tracecmd_get_private(struct tracecmd_input *handle);
+int tracecmd_follow_event(struct tracecmd_input *handle,
+ const char *system, const char *event_name,
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_event *,
+ struct tep_record *,
+ int, void *),
+ void *callback_data);
+
int tracecmd_iterate_events(struct tracecmd_input *handle,
cpu_set_t *cpus, int cpu_size,
int (*callback)(struct tracecmd_input *handle,
diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
index cdaa17bd..ce3584ee 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -43,6 +43,15 @@ struct page_map {
int ref_count;
};
+struct follow_event {
+ struct tep_event *event;
+ void *callback_data;
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_event *,
+ struct tep_record *,
+ int, void *);
+};
+
struct page {
struct list_head list;
off64_t offset;
@@ -161,6 +170,7 @@ struct tracecmd_input {
struct tep_plugin_list *plugin_list;
struct tracecmd_input *parent;
struct tracecmd_filter *filter;
+ struct follow_event *followers;
unsigned long file_state;
unsigned long long trace_id;
unsigned long long next_offset;
@@ -173,6 +183,7 @@ struct tracecmd_input {
int cpus;
int start_cpu;
int ref;
+ int nr_followers;
int nr_buffers; /* buffer instances */
bool use_trace_clock;
bool read_page;
@@ -2526,6 +2537,88 @@ tracecmd_read_next_data(struct tracecmd_input *handle, int *rec_cpu)
}
/**
+ * tracecmd_follow_event - Add callback for specific events for iterators
+ * @handle: The handle to get a callback from
+ * @system: The system of the event to track
+ * @event_name: The name of the event to track
+ * @callback: The function to call when the event is hit in an iterator
+ * @callback_data: The data to pass to @callback
+ *
+ * This attaches a callback to @handle where if tracecmd_iterate_events()
+ * or tracecmd_iterate_events_multi() is called, that if the specified
+ * event is hit, it will call @callback, with the following parameters:
+ * @handle: Same handle as passed to this function.
+ * @event: The event pointer that was found by @system and @event_name.
+ * @record; The event instance of @event.
+ * @cpu: The cpu that the event happened on.
+ * @callback_data: The same as @callback_data passed to the function.
+ *
+ * Note that when used with tracecmd_iterate_events_multi() that @cpu
+ * may be the nth CPU of all handles it is processing, so if the CPU
+ * that the @record is on is desired, then use @record->cpu.
+ *
+ * Returns 0 on success and -1 on error.
+ */
+int tracecmd_follow_event(struct tracecmd_input *handle,
+ const char *system, const char *event_name,
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_event *,
+ struct tep_record *,
+ int, void *),
+ void *callback_data)
+{
+ struct tep_handle *tep = tracecmd_get_tep(handle);
+ struct follow_event *followers;
+ struct follow_event follow;
+
+ if (!tep) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ follow.event = tep_find_event_by_name(tep, system, event_name);
+ if (!follow.event) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ follow.callback = callback;
+ follow.callback_data = callback_data;
+
+ followers = realloc(handle->followers, sizeof(*followers) *
+ (handle->nr_followers + 1));
+ if (!followers)
+ return -1;
+
+ handle->followers = followers;
+ followers[handle->nr_followers++] = follow;
+
+ return 0;
+}
+
+static int call_followers(struct tracecmd_input *handle,
+ struct tep_record *record, int cpu)
+{
+ struct tep_handle *tep = tracecmd_get_tep(handle);
+ struct follow_event *followers = handle->followers;
+ struct tep_event *event;
+ int ret = 0;
+ int i;
+
+ event = tep_find_event_by_record(tep, record);
+ if (!event)
+ return -1;
+
+ for (i = 0; i < handle->nr_followers; i++) {
+ if (handle->followers[i].event == event)
+ ret |= followers[i].callback(handle, event, record,
+ cpu, followers[i].callback_data);
+ }
+
+ return ret;
+}
+
+/**
* tracecmd_iterate_events - iterate events over a given handle
* @handle: The handle to iterate over
* @cpus: The CPU set to filter on (NULL for all CPUs)
@@ -2553,6 +2646,11 @@ int tracecmd_iterate_events(struct tracecmd_input *handle,
int cpu;
int ret = 0;
+ if (!callback && !handle->nr_followers) {
+ errno = EINVAL;
+ return -1;
+ }
+
records = calloc(handle->max_cpu, sizeof(*records));
if (!records)
return -1;
@@ -2582,12 +2680,14 @@ int tracecmd_iterate_events(struct tracecmd_input *handle,
records[next_cpu] = tracecmd_peek_data(handle, next_cpu);
if (!handle->filter ||
- tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH)
- ret = callback(handle, record, next_cpu, callback_data);
-
+ tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH) {
+ if (handle->nr_followers)
+ ret = call_followers(handle, record, next_cpu);
+ if (!ret && callback)
+ ret = callback(handle, record, next_cpu, callback_data);
+ }
tracecmd_free_record(record);
}
-
} while (next_cpu >= 0 && ret >= 0);
for (cpu = 0; cpu < handle->max_cpu; cpu++)
@@ -2674,8 +2774,13 @@ int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
records[next_cpu].record = tracecmd_peek_data(handle, cpu);
if (!handle->filter ||
- tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH)
- ret = callback(handle, record, next_cpu, callback_data);
+ tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH) {
+ if (handle->nr_followers)
+ ret = call_followers(handle, record, next_cpu);
+
+ if (!ret && callback)
+ ret = callback(handle, record, next_cpu, callback_data);
+ }
tracecmd_free_record(record);
}