LIBTRACEEVENT(3)
π LIBTRACEEVENT(3) β the kbuffer girlies' guide π
okay so bestie, welcome to the libtraceevent manual, section 3 π«Ά this is the one about the kbuffer crew β the lil' squad that helps you parse the raw sub buffers of the Linux kernel tracing ring buffer. no cap, it's giving "I read raw kernel data for breakfast" energy π
β¨ NAME β¨
kbuffer_alloc, kbuffer_dup, kbuffer_free, kbuffer_load_subbuffer, kbuffer_subbuffer, kbuffer_refresh, kbuffer_subbuffer_size, kbuffer_start_of_data β creating a kbuffer element so you can parse the Linux kernel tracing ring buffer π¦
πΈ SYNOPSIS πΈ
#include <kbuffer.h>
enum kbuffer_endian {
KBUFFER_ENDIAN_BIG,
KBUFFER_ENDIAN_LITTLE,
KBUFFER_ENDIAN_SAME_AS_HOST,
};
enum kbuffer_long_size {
KBUFFER_LSIZE_4,
KBUFFER_LSIZE_8,
KBUFFER_LSIZE_SAME_AS_HOST,
};
struct kbuffer;
struct tep_handle;
struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
struct kbuffer *kbuffer_dup(struct kbuffer *kbuf);
void kbuffer_free(struct kbuffer *kbuf);
int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
int kbuffer_subbuffer_size(struct kbuffer *kbuf);
int kbuffer_refresh(struct kbuffer *kbuf);
int kbuffer_start_of_data(struct kbuffer *kbuf);
void *kbuffer_subbuffer(struct kbuffer *_kbuf);
π DESCRIPTION π
so these functions create a kbuffer handle that you use to parse the raw sub buffers of the Linux kernel tracing ring buffer π the ring buffer lives in the tracefs directory, and you can grab it with tracefs_instance_get_file(3) at per_cpu/cpuX/trace_pipe_raw β where X gets swapped out for the per-CPU number of whatever ring buffer you're looking at π and yeah, the kernel's ring buffer is split up per CPU, so you have to retrieve the raw ring buffer per CPU too. no shortcuts, bestie, that's just how it is π
kbuffer_alloc() creates a descriptor you can use to manage a sub buffer read by the ring buffer β¨ the size parameter says what the word size is for the given buffer β and ooh, plot twist, this also works when you're reading raw data from a machine that is not the machine calling this function π³ the endian parameter is the endianness of the machine.
if endian is set to KBUFFER_ENDIAN_SAME_AS_HOST, then the endian gets set to match the host's endianness β which is super handy when your app is reading the ring buffer data straight off the same machine it's running on π
if size is set to KBUFFER_LSIZE_SAME_AS_HOST: if the word size is 8, the kbuffer descriptor gets set to long size of 8. but if the size is 4, then it goes and does a uname(2) call, and if the machine field has the string "64" in it, it gets set to 8 byte long size and not 4 byte π this is because the ring buffer long size depends on the kernel, not user space. lowkey a whole thing but slay.
kbuffer_dup() duplicates an existing kbuffer structure into a freshly allocated new one π it keeps all the properties of the kbuf you passed in, including pointing to the same subbuffer that was loaded in the kbuf. and bestie, you must free it with kbuffer_free().
kbuffer_free() frees the resources that kbuffer_alloc() created π«Ά
kbuffer_load_subbuffer() takes a subbuffer, which is a raw data blob from the tracefs trace_pipe_raw file π the Linux tracing ring buffer is broken up into sub buffers β each sub buffer is a standalone data segment that has all the info needed to split out the individual events and time stamps. that sub buffer is exactly what kbuffer uses to walk the events. iconic.
kbuffer_subbuffer_size() returns the location of the end of the last event on the sub-buffer π¦ heads up: it does not return the size of the sub-buffer itself.
kbuffer_refresh() is for when more writes happened on the loaded kbuffer, and the size needs refreshing so you can actually read the new events written since the last kbuffer_load_subbuffer() was called on it β¨
β οΈ ok warning time: no memory barriers are implemented with this function, and any synchronization with the writer is the application's responsibility. that's on you, bestie π
kbuffer_start_of_data() returns the offset of where the actual data load of the sub-buffer begins πΈ
kbuffer_subbuffer() returns the pointer to the currently loaded subbuffer β i.e., the last subbuffer loaded by kbuffer_load_subbuffer() π if no subbuffer was loaded, NULL is returned.
β RETURN VALUE β
kbuffer_alloc()β returns an allocatedkbufferdescriptor, orNULLon error π the returned descriptor must be freed withkbuffer_free().kbuffer_load_subbuffer()β returns0on success and-1on error.kbuffer_subbuffer_size()β returns the index on the subbuffer where the end of the last event is located πkbuffer_start_of_data()β returns the offset of where the data begins on the sub-buffer loaded inkbuf.kbuffer_subbuffer()β returns the last subbuffer loaded intokbufbykbuffer_load_subbuffer(), orNULLif none was loaded.kbuffer_refresh()β returns0on success, and-1ifkbufisNULLor it doesn't have a subbuffer loaded viakbuffer_load_subbuffer()π
π EXAMPLE π
here's the whole vibe in code, bestie β go off:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <kbuffer.h>
int main (int argc, char **argv)
{
unsigned long long ts;
struct kbuffer *kbuf;
struct stat st;
char *buf;
void *event;
int ret;
int fd;
int i = 0;
if (argc < 2) {
printf("usage: %s raw-subbuffer-page\n", argv[0]);
printf(" Try: dd count=1 bs=4096 if=/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw of=/tmp/file\n");
exit(0);
}
if (stat(argv[1], &st) < 0) {
perror("stat");
exit(-1);
}
buf = malloc(st.st_size);
if (!buf) {
perror("Allocating buffer");
exit(-1);
}
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror(argv[1]);
exit(-1);
}
ret = read(fd, buf, st.st_size);
if (ret < 0) {
perror("Reading buffer");
exit(-1);
}
close(fd);
kbuf = kbuffer_alloc(KBUFFER_ENDIAN_SAME_AS_HOST,
KBUFFER_LSIZE_SAME_AS_HOST);
if (!kbuf) {
perror("Creating kbuffer");
exit(-1);
}
ret = kbuffer_load_subbuffer(kbuf, buf);
if (ret < 0) {
perror("Loading sub bufer");
exit(-1);
}
if (kbuffer_subbuffer_size(kbuf) > st.st_size) {
fprintf(stderr, "kbuffer is bigger than raw size %d > %ld\n",
kbuffer_subbuffer_size(kbuf), st.st_size);
exit(-1);
}
printf("Kbuffer data starts at %d\n", kbuffer_start_of_data(kbuf));
do {
event = kbuffer_read_event(kbuf, &ts);
if (event) {
printf(" event %3d ts:%lld\n", i++, ts);
event = kbuffer_next_event(kbuf, NULL);
}
} while (event);
if (!event)
printf("Finished sub buffer\n");
kbuffer_free(kbuf);
return 0;
}
π¦ FILES π¦
event-parse.hβ the header file you include so you have access to the library APIs π-ltraceeventβ the linker switch you add when building a program that uses the library β¨
π SEE ALSO π
libtraceevent(3), trace-cmd(1) β go read those too, iykyk π
π AUTHOR π
Steven Rostedt <rostedt@goodmis.org[1]> β author of libtraceevent π absolute legend, main character energy fr fr.
π REPORTING BUGS π
found a bug? don't be shy β report bugs to <linux-trace-devel@vger.kernel.org[2]> π
πΈ LICENSE πΈ
libtraceevent is Free Software, licensed under the GNU LGPL 2.1 π
β RESOURCES β
https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ β the source, go peek π
π NOTES π
rostedt@goodmis.orgmailto:rostedt@goodmis.orglinux-trace-devel@vger.kernel.orgmailto:linux-trace-devel@vger.kernel.org
okay that's the whole page bestie π«Ά no cap, you're now officially a kbuffer girlie. this was libtraceevent version 1.9.0, dated 06/15/2026 β and yes, it still goes by LIBTRACEEVENT(3) in the man page headers, slay π
β¨ go parse some ring buffers, you got this π
π¦ where this page comes from
- ubuntu stonking: libtraceevent-doc 1:1.9.0-2 Β· LGPL-2.1-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms