aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Rostedt (Google) <rostedt@goodmis.org>2022-11-14 23:08:38 -0500
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-11-15 09:57:16 -0500
commit445014301140e795bf451b739c33ac8514d38660 (patch)
treeab12010182d4224273166c4d12f71369b21d5d3c
parent8da05d9697ab09f7b615c58ef03ffd3898e9a2da (diff)
downloadlibtracefs-445014301140e795bf451b739c33ac8514d38660.tar.gz
libtracefs: Add tracefs_follow_missed_events() API
Add the function tracefs_follow_missed_events() to allow applications to have callback when events are dropped due to overrun of the ring buffer. Link: https://lore.kernel.org/linux-trace-devel/20221115040838.2456632-5-rostedt@goodmis.org Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-rw-r--r--Documentation/libtracefs-iterator.txt56
-rw-r--r--Documentation/libtracefs.txt7
-rw-r--r--include/tracefs-local.h2
-rw-r--r--include/tracefs.h5
-rw-r--r--src/tracefs-events.c89
5 files changed, 149 insertions, 10 deletions
diff --git a/Documentation/libtracefs-iterator.txt b/Documentation/libtracefs-iterator.txt
index f53991f..b971bd0 100644
--- a/Documentation/libtracefs-iterator.txt
+++ b/Documentation/libtracefs-iterator.txt
@@ -3,7 +3,7 @@ libtracefs(3)
NAME
----
-tracefs_iterate_raw_events, tracefs_iterate_stop, tracefs_follow_event - Iterate over events in the ring buffer
+tracefs_iterate_raw_events, tracefs_iterate_stop, tracefs_follow_event, tracefs_follow_missed_events - Iterate over events in the ring buffer
SYNOPSIS
--------
@@ -22,7 +22,12 @@ int *tracefs_follow_event*(struct tep_handle pass:[*]_tep_, struct tracefs_insta
int (pass:[*]_callback_)(struct tep_event pass:[*],
struct tep_record pass:[*],
int, void pass:[*]),
- void pass:[*]_callback_data_):
+ void pass:[*]_callback_data_);
+int *tracefs_follow_missed_events*(struct tracefs_instance pass:[*]_instance_,
+ int (pass:[*]_callback_)(struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
--
DESCRIPTION
@@ -57,6 +62,12 @@ will be passed to the _callback_ as well. Note, if it returns something other
than 0, it will stop the loop before the _callback_ of *tracefs_iterate_raw_events()*
is called.
+The *tracefs_follow_missed_events()* will call the _callback_ when missed
+events are detected. It will set the _record_ parameter of the callback to the
+record that came after the missed events and _event_ will be of the type of
+event _record_ is. _cpu_ will be set to the CPU that missed the events, and
+_callback_data_ will be the content that was passed in to the function.
+
RETURN VALUE
------------
The *tracefs_iterate_raw_events()* function returns -1 in case of an error or
@@ -69,19 +80,22 @@ EXAMPLE
#include <unistd.h>
#include <tracefs.h>
#include <stdbool.h>
+#include <signal.h>
struct my_struct {
bool stopped;
};
+#define MAX_COUNT 500000
+static int counter;
+
static int callback(struct tep_event *event, struct tep_record *record,
int cpu, void *data)
{
struct my_struct *my_data = data;
static struct trace_seq seq;
- static int counter;
- if (counter++ > 10000) {
+ if (counter++ > MAX_COUNT) {
my_data->stopped = true;
return 1;
}
@@ -124,28 +138,52 @@ static int sched_callback(struct tep_event *event, struct tep_record *record,
return 0;
}
+static int missed_callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ printf("OOPS! cpu %d dropped ", cpu);
+ if (record->missed_events > 0)
+ printf("%lld ", record->missed_events);
+ printf("events\n");
+ return 0;
+}
+
+static struct tracefs_instance *instance;
+static struct my_struct my_data;
+
+static void sig(int s)
+{
+ tracefs_iterate_stop(instance);
+ my_data.stopped = true;
+}
+
int main (int argc, char **argv, char **env)
{
struct tep_handle *tep;
- struct tracefs_instance *instance;
- struct my_struct my_data = { .stopped = false };
int this_pid = getpid();
instance = tracefs_instance_create("my-buffer");
if (!instance)
return -1;
- tracefs_event_enable(instance, "sched", NULL);
+ signal(SIGINT, sig);
+
+ tracefs_event_enable(instance, NULL, NULL);
sleep(1);
tracefs_event_disable(instance, NULL, NULL);
tep = tracefs_local_events(NULL);
tep_load_plugins(tep);
+ tracefs_follow_missed_events(instance, missed_callback, NULL);
tracefs_follow_event(tep, instance, "sched", "sched_switch", sched_callback, &this_pid);
tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, &my_data);
tracefs_instance_destroy(instance);
- if (my_data.stopped)
- printf("stopped!\n");
+ if (my_data.stopped) {
+ if (counter > MAX_COUNT)
+ printf("Finished max count\n");
+ else
+ printf("Finished via signal\n");
+ }
return 0;
}
diff --git a/Documentation/libtracefs.txt b/Documentation/libtracefs.txt
index e417806..c3f448d 100644
--- a/Documentation/libtracefs.txt
+++ b/Documentation/libtracefs.txt
@@ -65,7 +65,12 @@ Trace events:
int (pass:[*]_callback_)(struct tep_event pass:[*],
struct tep_record pass:[*],
int, void pass:[*]),
- void pass:[*]_callback_data_):
+ void pass:[*]_callback_data_);
+ int *tracefs_follow_missed_events*(struct tracefs_instance pass:[*]_instance_,
+ int (pass:[*]_callback_)(struct tep_event pass:[*],
+ struct tep_record pass:[*],
+ int, void pass:[*]),
+ void pass:[*]_callback_data_);
struct tep_handle pass:[*]*tracefs_local_events*(const char pass:[*]_tracing_dir_);
struct tep_handle pass:[*]*tracefs_local_events_system*(const char pass:[*]_tracing_dir_, const char pass:[*] const pass:[*]_sys_names_);
int *tracefs_fill_local_events*(const char pass:[*]_tracing_dir_, struct tep_handle pass:[*]_tep_, int pass:[*]_parsing_failures_);
diff --git a/include/tracefs-local.h b/include/tracefs-local.h
index 4c636be..2007d26 100644
--- a/include/tracefs-local.h
+++ b/include/tracefs-local.h
@@ -35,6 +35,7 @@ struct tracefs_instance {
struct tracefs_options_mask supported_opts;
struct tracefs_options_mask enabled_opts;
struct follow_event *followers;
+ struct follow_event *missed_followers;
char *trace_dir;
char *name;
pthread_mutex_t lock;
@@ -45,6 +46,7 @@ struct tracefs_instance {
int ftrace_marker_fd;
int ftrace_marker_raw_fd;
int nr_followers;
+ int nr_missed_followers;
bool pipe_keep_going;
bool iterate_keep_going;
};
diff --git a/include/tracefs.h b/include/tracefs.h
index cb64e09..3547b5a 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -132,6 +132,11 @@ int tracefs_follow_event(struct tep_handle *tep, struct tracefs_instance *instan
struct tep_record *,
int, void *),
void *callback_data);
+int tracefs_follow_missed_events(struct tracefs_instance *instance,
+ int (*callback)(struct tep_event *,
+ struct tep_record *,
+ int, void *),
+ void *callback_data);
char *tracefs_event_get_file(struct tracefs_instance *instance,
const char *system, const char *event,
diff --git a/src/tracefs-events.c b/src/tracefs-events.c
index d5c8df4..daa81c0 100644
--- a/src/tracefs-events.c
+++ b/src/tracefs-events.c
@@ -23,6 +23,9 @@
static struct follow_event *root_followers;
static int nr_root_followers;
+static struct follow_event *root_missed_followers;
+static int nr_root_missed_followers;
+
struct cpu_iterate {
struct tracefs_cpu *tcpu;
struct tep_record record;
@@ -120,6 +123,87 @@ int read_next_record(struct tep_handle *tep, struct cpu_iterate *cpu)
return -1;
}
+/**
+ * tracefs_follow_missed_events - Add callback for missed events for iterators
+ * @instance: The instance to follow
+ * @callback: The function to call when missed events is detected
+ * @callback_data: The data to pass to @callback
+ *
+ * This attaches a callback to an @instance or the root instance if @instance
+ * is NULL, where if tracefs_iterate_raw_events() is called, that if missed
+ * events are detected, it will call @callback, with the following parameters:
+ * @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.
+ *
+ * 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 tracefs_follow_missed_events(struct tracefs_instance *instance,
+ int (*callback)(struct tep_event *,
+ struct tep_record *,
+ int, void *),
+ void *callback_data)
+{
+ struct follow_event **followers;
+ struct follow_event *follower;
+ struct follow_event follow;
+ int *nr_followers;
+
+ follow.event = NULL;
+ follow.callback = callback;
+ follow.callback_data = callback_data;
+
+ if (instance) {
+ followers = &instance->missed_followers;
+ nr_followers = &instance->nr_missed_followers;
+ } else {
+ followers = &root_missed_followers;
+ nr_followers = &nr_root_missed_followers;
+ }
+ follower = realloc(*followers, sizeof(*follower) *
+ ((*nr_followers) + 1));
+ if (!follower)
+ return -1;
+
+ *followers = follower;
+ follower[(*nr_followers)++] = follow;
+
+ return 0;
+}
+
+static int call_missed_events(struct tracefs_instance *instance,
+ struct tep_event *event, struct tep_record *record, int cpu)
+{
+ struct follow_event *followers;
+ int nr_followers;
+ int ret = 0;
+ int i;
+
+ if (instance) {
+ followers = instance->missed_followers;
+ nr_followers = instance->nr_missed_followers;
+ } else {
+ followers = root_missed_followers;
+ nr_followers = nr_root_missed_followers;
+ }
+
+ if (!followers)
+ return 0;
+
+ for (i = 0; i < nr_followers; i++) {
+ ret |= followers[i].callback(event, record,
+ cpu, followers[i].callback_data);
+ }
+
+ return ret;
+}
+
static int call_followers(struct tracefs_instance *instance,
struct tep_event *event, struct tep_record *record, int cpu)
{
@@ -128,6 +212,11 @@ static int call_followers(struct tracefs_instance *instance,
int ret = 0;
int i;
+ if (record->missed_events)
+ ret = call_missed_events(instance, event, record, cpu);
+ if (ret)
+ return ret;
+
if (instance) {
followers = instance->followers;
nr_followers = instance->nr_followers;