LIBTRACEFS(3)
π LIBTRACEFS β the libtracefs manual, bestie edition π
okay so this is the libtracefs manual page and today we're learning about iterating over events in the ring buffer. it's giving "I read the kernel trace for fun" energy and honestly? iconic. let's go π¦
β¨ NAME β¨
tracefs_iterate_raw_events, tracefs_iterate_stop, tracefs_follow_event, tracefs_follow_missed_events, tracefs_follow_event_clear, tracefs_follow_missed_events_clear, tracefs_iterate_snapshot_events β Iterate over events in the ring buffer π
πΈ SYNOPSIS πΈ
#include <tracefs.h>
int tracefs_iterate_raw_events(struct tep_handle *tep, struct tracefs_instance *instance,
cpu_set_t *cpus, int cpu_size,
int (*callback)(struct tep_event *, struct tep_record *, int, void *),
void *callback_context);
void tracefs_iterate_stop(struct tracefs_instance *instance);
int tracefs_follow_event(struct tep_handle *tep, struct tracefs_instance *instance,
const char *system, const char *event_name,
int (*callback)(struct tep_event *,
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);
int tracefs_follow_event_clear(struct tracefs_instance *instance,
const char *system, const char *event_name);
int tracefs_follow_missed_events_clear(struct tracefs_instance *instance);
int tracefs_iterate_snapshot_events(struct tep_handle *tep, struct tracefs_instance *instance,
cpu_set_t *cpus, int cpu_size,
int (*callback)(struct tep_event *, struct tep_record *, int, void *),
void *callback_context);
like, look at all those function signatures. we love a long synopsis. π
π¦ DESCRIPTION π¦
So. Trace iterator over raw events. That's the whole vibe. Let me break it down for u bestie.
β¨ tracefs_iterate_raw_events() β¨
The tracefs_iterate_raw_events() function will read the tracefs raw data buffers and call the specified callback function for every event it encounters. Events are iterated in sorted order: oldest first π°οΈ (chronological queen behavior, no cap).
An initialized tep handler is required (See tracefs_local_events(3)). If instance is NULL, then the toplevel tracefs buffer is used, otherwise the buffer for the corresponding instance is read.
To filter only on a subset of CPUs, cpus and cpu_size may be set to only call callback with events that occurred on the CPUs specified, otherwise if cpus is NULL then the callback function will be called for all events, and cpu_size is ignored. π«Ά
The callback function will be called with the following parameters:
- A pointer to a
struct tep_eventthat corresponds to the type of event the record is - The record representing the event
- The CPU that the event occurred on
- A pointer to user specified
callback_context
If the callback returns non-zero, the iteration stops. π
π tracefs_iterate_snapshot_events() π
The tracefs_iterate_snapshot_events() works the same as tracefs_iterate_raw_events() except that it works on the snapshot buffer. same energy, different buffer, iykyk.
π tracefs_iterate_stop() π
Use tracefs_iterate_stop() to force a executing tracefs_iterate_raw_events() to halt. This can be called from either a callback that is called by the iterator (even though a return of non-zero will stop it), or from another thread. multitasking icon behavior fr fr π
π tracefs_follow_event() π
The tracefs_follow_event() is used with tracefs_iterate_raw_events() but intead of the callback being called for every event, it is only called for the specified system / event_name given to the function. (yes, "intead" β that's literally what the original says, I don't make the rules π)
The callback is the same as for tracefs_iterate_raw_events(), and the passed in callback_context will be passed to the callback as well.
β οΈ Note, if it returns something other than0, it will stop the loop before the callback oftracefs_iterate_raw_events()is called. so like, order matters bestie.
π tracefs_follow_missed_events() π
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. π (we lost events but at least we know about it)
π§ tracefs_follow_event_clear() π§
The tracefs_follow_event_clear() will remove followers from instance that match system and event_name. The matching rules, served fresh:
- If
systemandevent_nameare bothNULL, then it will remove all event followers associated toinstance. - If just
systemisNULL, then it will remove all followers that follow events that matchevent_name. - If just
event_nameisNULL, then it will remove all followers that are attached to events that are apart of asystemthat matchessystem.
π tracefs_follow_missed_events_clear() π
The tracefs_follow_missed_events_clear() will remove all followers for missed events. bye girlies π
β RETURN VALUE β
- The
tracefs_iterate_raw_events()function returns-1in case of an error or0otherwise. - Both
tracefs_follow_event_clear()andtracefs_follow_missed_events_clear()return0on success and-1on error, or if it found no followers that match and should be removed.
like, classic 0 good / -1 bad situation. we know her. π
π₯ EXAMPLE π₯
ok this is the good part, the whole demo program, verbatim, because we do NOT paraphrase code in this house:
#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;
if (counter++ > MAX_COUNT) {
my_data->stopped = true;
return 1;
}
if (!seq.buffer)
trace_seq_init(&seq);
tep_print_event(event->tep, &seq, record, "%16s-%-5d [%03d] %6.1000d %s: %s\n",
TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU,
TEP_PRINT_TIME, TEP_PRINT_NAME, TEP_PRINT_INFO);
trace_seq_terminate(&seq);
trace_seq_do_printf(&seq);
trace_seq_reset(&seq);
return 0;
}
static int sched_callback(struct tep_event *event, struct tep_record *record,
int cpu, void *data)
{
static struct tep_format_field *prev_pid;
static struct tep_format_field *next_pid;
unsigned long long pid;
int this_pid = *(int *)data;
if (!prev_pid) {
prev_pid = tep_find_field(event, "prev_pid");
next_pid = tep_find_field(event, "next_pid");
if (!prev_pid || !next_pid) {
fprintf(stderr, "No pid fields??\n");
return -1;
}
}
tep_read_number_field(prev_pid, record->data, &pid);
if (pid == this_pid)
printf("WE ARE LEAVING!\n");
tep_read_number_field(next_pid, record->data, &pid);
if (pid == this_pid)
printf("WE ARE ARRIVING!\n");
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;
int this_pid = getpid();
instance = tracefs_instance_create("my-buffer");
if (!instance)
return -1;
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);
/* Note, the clear here is to show how to clear all followers
* in case tracefs_iterate_raw_events() is called again, but
* does not want to include the followers. It's not needed
* here because tracefs_instance_free() will clean them up.
*/
tracefs_follow_event_clear(instance, NULL, NULL);
tracefs_follow_missed_events_clear(instance);
tracefs_instance_destroy(instance);
tracefs_instance_free(instance);
if (my_data.stopped) {
if (counter > MAX_COUNT)
printf("Finished max count\n");
else
printf("Finished via signal\n");
}
return 0;
}
"WE ARE LEAVING!" / "WE ARE ARRIVING!" β honestly the most iconic debug output in the whole trace world. main character printf energy. π
π FILES π
tracefs.hβ Header file to include in order to have access to the library APIs.-ltracefsβ Linker switch to add when building a program that uses the library. (don't forget her or ur linker will simply not slay)
π SEE ALSO π
libtracefs(3), libtraceevent(3), trace-cmd(1)
go read those too bestie, i'm not gatekeeping π«Ά
πΈ AUTHOR πΈ
- Steven Rostedt
<rostedt@goodmis.org[1]> - Tzvetomir Stoyanov
<tz.stoyanov@gmail.com[2]>
π¦ REPORTING BUGS π¦
Report bugs to <linux-trace-devel@vger.kernel.org[3]>
π LICENSE π
libtracefs is Free Software licensed under the GNU LGPL 2.1
π RESOURCES π
https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/
β COPYING β
Copyright (C) 2020 VMware, Inc. Free use of this software is granted under the terms of the GNU Public License (GPL).
π NOTES π
- rostedt@goodmis.org
mailto:rostedt@goodmis.org - tz.stoyanov@gmail.com
mailto:tz.stoyanov@gmail.com - linux-trace-devel@vger.kernel.org
mailto:linux-trace-devel@vger.kernel.org
okay that's the whole page, you made it to the end, proud of u π one last little sign-off from the manpage footer itself: this was libtracefs 1.8.4, dated 10/21/2026 β go iterate some events bestie, you've got this fr fr πβ¨π¦
π¦ where this page comes from
- arch rolling: libtracefs 1.8.4-1 Β· GPL-2.0-only AND LGPL-2.1-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms