aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Google) <rostedt@goodmis.org>2022-11-06 14:44:41 -0500
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-11-09 18:19:35 -0500
commitf3fd28c5159830c6c5c69b3423767514742f84fc (patch)
treed3bd84209b5c981f3f2da4d535db59da00a7fcb4
parentf63e19662039ba8e9a2ddfdf6b703f7c10de5c84 (diff)
downloadtrace-cmd-f3fd28c5159830c6c5c69b3423767514742f84fc.tar.gz
trace-cmd library: Add tracecmd_follow_missed_events() API
Add the function tracecmd_follow_missed_events() to let applications add a hook for when any events are missed. The callback will be called even if filtering is enabled. Link: https://lore.kernel.org/linux-trace-devel/20221106144441.1fb08fd5@rorschach.local.home Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-rw-r--r--Documentation/libtracecmd/libtracecmd-iterate.txt38
-rw-r--r--Documentation/libtracecmd/libtracecmd.txt6
-rw-r--r--include/trace-cmd/trace-cmd.h7
-rw-r--r--lib/trace-cmd/trace-input.c80
4 files changed, 130 insertions, 1 deletions
diff --git a/Documentation/libtracecmd/libtracecmd-iterate.txt b/Documentation/libtracecmd/libtracecmd-iterate.txt
index c0a99f30..5c1eece0 100644
--- a/Documentation/libtracecmd/libtracecmd-iterate.txt
+++ b/Documentation/libtracecmd/libtracecmd-iterate.txt
@@ -4,7 +4,7 @@ libtracecmd(3)
NAME
----
tracecmd_iterate_events, tracecmd_iterate_events_multi, tracecmd_follow_event,
-tracecmd_filter_add - Read events from a trace file
+tracecmd_follow_missed_events, tracecmd_filter_add - Read events from a trace file
SYNOPSIS
--------
@@ -31,6 +31,12 @@ int *tracecmd_follow_event*(struct tracecmd_input pass:[*]_handle_,
struct tep_record pass:[*],
int, void pass:[*]),
void pass:[*]_callback_data_);
+int *tracecmd_follow_missed_events*(struct tracecmd_input pass:[*]_handle_,
+ int (pass:[*]_callback_)(struct tracecmd_input pass:[*],
+ struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
struct tracecmd_filter pass:[*]*tracecmd_filter_add*(struct tracecmd_input *_handle_,
const char pass:[*]_filter_str_, bool _neg_);
--
@@ -80,6 +86,9 @@ event is on.
The *tracecmd_follow_event()* function will attach to a trace file descriptor _handle_
and call the _callback_ when the event described by _system_ and _name_ matches an event
in the iteration of *tracecmd_iterate_events()* or *tracecmd_iterate_events_multi()*.
+Note, the _cpu_ is the nth CPU for both *tracecmd_iterate_events()* and
+*tracecmd_iterate_events_multi()*. If the actual CPU of the _record_ is needed, use
+_record_->cpu.
For *tracecmd_iterate_events_multi()*, the _callback_ is only called if the _handle_
matches the current trace file descriptor within _handles_. The _callback_data_ is
passed as the last parameter to the _callback()_ function. Note, this _callback()_
@@ -90,6 +99,21 @@ The _callback()_ prototype for *tracecmd_follow_event()_ is:
int _callback()_(struct tracecmd_input pass:[*]_handle_, struct tep_event pass:[*]_event,
struct tep_record pass:[*]_record_, int _cpu_, void pass:[*]_data_);
+The *tracecmd_follow_missed_events()* function will attach to a trace file descriptor
+_handle_ and call the _callback_ when missed events are detected. The _event_ will
+hold the type of event that the _record_ is. The _record_ will hold the information
+of the missed events. The _cpu_ is the nth CPU for both *tracecmd_iterate_events()*
+and *tracecmd_iterate_events_multi()*. If the CPU that the missed events are for is
+needed, use _record_->cpu. If _record_->missed_events is a positive number, then it
+holds the number of missed events since the last event on its CPU, otherwise it
+will be negative, and that will mean that the number of missed events is unknown but
+missed events exist since the last event on the CPU.
+The _callback_ and _callback_data_ is the same format as *tracecmd_follow_event()* above.
+The missed events _callback_ is called before any of the other _callbacks_ and any
+filters that were added by *tracecmd_filter_add()* are ignored.
+If _callback_ returns a non zero, it will stop the iterator before it calls any of the
+other iterator callbacks for the given record.
+
The *tracecmd_filter_add()* function, adds a filter to _handle_ that affects
both *tracecmd_iterate_events()* and *tracecmd_iterate_events_multi()*.
The _filter_str_ is a character string defining a filter in a format that
@@ -148,6 +172,17 @@ static int print_event(struct tracecmd_input *handle, struct tep_event *event,
return print_events(handle, record, cpu, data);
}
+static int missed_events(struct tracecmd_input *handle, struct tep_event *event,
+ struct tep_record *record, int cpu, void *data)
+{
+ if (record->missed_events > 0)
+ printf("CPU [%03d] has %d missed events\n",
+ record->cpu, record->missed_events);
+ else
+ printf("CPU [%03d] has missed events\n", record->cpu);
+ return 0;
+}
+
static void usage(const char *argv0)
{
printf("usage: [-c cpu][-f filter][-e event] %s trace.dat [trace.dat ...]\n",
@@ -218,6 +253,7 @@ int main(int argc, char **argv)
exit(-1);
}
}
+ tracecmd_follow_missed_events(handles[nr_handles], missed_events, NULL);
nr_handles++;
}
diff --git a/Documentation/libtracecmd/libtracecmd.txt b/Documentation/libtracecmd/libtracecmd.txt
index b1e07df5..a820ed32 100644
--- a/Documentation/libtracecmd/libtracecmd.txt
+++ b/Documentation/libtracecmd/libtracecmd.txt
@@ -47,6 +47,12 @@ Iterating over events in a trace file:
struct tep_record pass:[*],
int, void pass:[*]),
void pass:[*]_callback_data_);
+ int *tracecmd_follow_missed_events*(struct tracecmd_input pass:[*]_handle_,
+ int (pass:[*]_callback_)(struct tracecmd_input pass:[*],
+ struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
struct tracecmd_filter pass:[*]*tracecmd_filter_add*(struct tracecmd_input *_handle_,
const char pass:[*]_filter_str_, bool _neg_);
diff --git a/include/trace-cmd/trace-cmd.h b/include/trace-cmd/trace-cmd.h
index c34503ac..61ab4f03 100644
--- a/include/trace-cmd/trace-cmd.h
+++ b/include/trace-cmd/trace-cmd.h
@@ -63,6 +63,13 @@ int tracecmd_follow_event(struct tracecmd_input *handle,
int, void *),
void *callback_data);
+int tracecmd_follow_missed_events(struct tracecmd_input *handle,
+ 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 6a8ca2e8..aa54e7fa 100644
--- a/lib/trace-cmd/trace-input.c
+++ b/lib/trace-cmd/trace-input.c
@@ -171,6 +171,7 @@ struct tracecmd_input {
struct tracecmd_input *parent;
struct tracecmd_filter *filter;
struct follow_event *followers;
+ struct follow_event *missed_followers;
struct tracecmd_cpu_map *map;
unsigned long file_state;
unsigned long long trace_id;
@@ -185,6 +186,7 @@ struct tracecmd_input {
int start_cpu;
int ref;
int nr_followers;
+ int nr_missed_followers;
int nr_buffers; /* buffer instances */
bool use_trace_clock;
bool read_page;
@@ -2626,6 +2628,57 @@ int tracecmd_follow_event(struct tracecmd_input *handle,
return 0;
}
+/**
+ * tracecmd_follow_missed_events - Add callback for missed events for iterators
+ * @handle: The handle to get a callback from
+ * @callback: The function to call when missed events is detected
+ * @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 missed events
+ * is detected, it will call @callback, with the following parameters:
+ * @handle: Same handle as passed to this function.
+ * @event: The event pointer of the record with the missing events
+ * @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.
+ *
+ * If the count of missing events is available, @record->missed_events
+ * will have a positive number holding the number of missed events since
+ * the last event on the same CPU, or just -1 if that number is unknown
+ * but missed events did happen.
+ *
+ * Returns 0 on success and -1 on error.
+ */
+int tracecmd_follow_missed_events(struct tracecmd_input *handle,
+ int (*callback)(struct tracecmd_input *handle,
+ struct tep_event *,
+ struct tep_record *,
+ int, void *),
+ void *callback_data)
+{
+ struct follow_event *followers;
+ struct follow_event follow;
+
+ follow.event = NULL;
+ follow.callback = callback;
+ follow.callback_data = callback_data;
+
+ followers = realloc(handle->missed_followers, sizeof(*followers) *
+ (handle->nr_missed_followers + 1));
+ if (!followers)
+ return -1;
+
+ handle->missed_followers = followers;
+ followers[handle->nr_missed_followers++] = follow;
+
+ return 0;
+}
+
static int call_followers(struct tracecmd_input *handle,
struct tep_record *record, int cpu)
{
@@ -2648,6 +2701,27 @@ static int call_followers(struct tracecmd_input *handle,
return ret;
}
+static int call_missed_events(struct tracecmd_input *handle,
+ struct tep_record *record, int cpu)
+{
+ struct tep_handle *tep = tracecmd_get_tep(handle);
+ struct follow_event *followers = handle->missed_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_missed_followers; i++) {
+ ret |= followers[i].callback(handle, event, record,
+ cpu, followers[i].callback_data);
+ }
+
+ return ret;
+}
+
static int call_callbacks(struct tracecmd_input *handle, struct tep_record *record,
int next_cpu,
int (*callback)(struct tracecmd_input *handle,
@@ -2660,6 +2734,12 @@ static int call_callbacks(struct tracecmd_input *handle, struct tep_record *reco
if (!record)
return 0;
+ if (record->missed_events)
+ ret = call_missed_events(handle, record, next_cpu);
+
+ if (ret)
+ return ret;
+
if (!handle->filter ||
tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH) {
if (handle->nr_followers)