mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
a1e0dd7ce3
It is now possible to mmap() a ring-buffer to stream its content. Add some documentation and a code example. Link: https://lore.kernel.org/linux-trace-kernel/20240510140435.3550353-5-vdonnefort@google.com Signed-off-by: Vincent Donnefort <vdonnefort@google.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
107 lines
3.7 KiB
ReStructuredText
107 lines
3.7 KiB
ReStructuredText
.. SPDX-License-Identifier: GPL-2.0
|
|
|
|
==================================
|
|
Tracefs ring-buffer memory mapping
|
|
==================================
|
|
|
|
:Author: Vincent Donnefort <vdonnefort@google.com>
|
|
|
|
Overview
|
|
========
|
|
Tracefs ring-buffer memory map provides an efficient method to stream data
|
|
as no memory copy is necessary. The application mapping the ring-buffer becomes
|
|
then a consumer for that ring-buffer, in a similar fashion to trace_pipe.
|
|
|
|
Memory mapping setup
|
|
====================
|
|
The mapping works with a mmap() of the trace_pipe_raw interface.
|
|
|
|
The first system page of the mapping contains ring-buffer statistics and
|
|
description. It is referred to as the meta-page. One of the most important
|
|
fields of the meta-page is the reader. It contains the sub-buffer ID which can
|
|
be safely read by the mapper (see ring-buffer-design.rst).
|
|
|
|
The meta-page is followed by all the sub-buffers, ordered by ascending ID. It is
|
|
therefore effortless to know where the reader starts in the mapping:
|
|
|
|
.. code-block:: c
|
|
|
|
reader_id = meta->reader->id;
|
|
reader_offset = meta->meta_page_size + reader_id * meta->subbuf_size;
|
|
|
|
When the application is done with the current reader, it can get a new one using
|
|
the trace_pipe_raw ioctl() TRACE_MMAP_IOCTL_GET_READER. This ioctl also updates
|
|
the meta-page fields.
|
|
|
|
Limitations
|
|
===========
|
|
When a mapping is in place on a Tracefs ring-buffer, it is not possible to
|
|
either resize it (either by increasing the entire size of the ring-buffer or
|
|
each subbuf). It is also not possible to use snapshot and causes splice to copy
|
|
the ring buffer data instead of using the copyless swap from the ring buffer.
|
|
|
|
Concurrent readers (either another application mapping that ring-buffer or the
|
|
kernel with trace_pipe) are allowed but not recommended. They will compete for
|
|
the ring-buffer and the output is unpredictable, just like concurrent readers on
|
|
trace_pipe would be.
|
|
|
|
Example
|
|
=======
|
|
|
|
.. code-block:: c
|
|
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include <linux/trace_mmap.h>
|
|
|
|
#include <sys/mman.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#define TRACE_PIPE_RAW "/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw"
|
|
|
|
int main(void)
|
|
{
|
|
int page_size = getpagesize(), fd, reader_id;
|
|
unsigned long meta_len, data_len;
|
|
struct trace_buffer_meta *meta;
|
|
void *map, *reader, *data;
|
|
|
|
fd = open(TRACE_PIPE_RAW, O_RDONLY | O_NONBLOCK);
|
|
if (fd < 0)
|
|
exit(EXIT_FAILURE);
|
|
|
|
map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
|
|
if (map == MAP_FAILED)
|
|
exit(EXIT_FAILURE);
|
|
|
|
meta = (struct trace_buffer_meta *)map;
|
|
meta_len = meta->meta_page_size;
|
|
|
|
printf("entries: %llu\n", meta->entries);
|
|
printf("overrun: %llu\n", meta->overrun);
|
|
printf("read: %llu\n", meta->read);
|
|
printf("nr_subbufs: %u\n", meta->nr_subbufs);
|
|
|
|
data_len = meta->subbuf_size * meta->nr_subbufs;
|
|
data = mmap(NULL, data_len, PROT_READ, MAP_SHARED, fd, meta_len);
|
|
if (data == MAP_FAILED)
|
|
exit(EXIT_FAILURE);
|
|
|
|
if (ioctl(fd, TRACE_MMAP_IOCTL_GET_READER) < 0)
|
|
exit(EXIT_FAILURE);
|
|
|
|
reader_id = meta->reader.id;
|
|
reader = data + meta->subbuf_size * reader_id;
|
|
|
|
printf("Current reader address: %p\n", reader);
|
|
|
|
munmap(data, data_len);
|
|
munmap(meta, meta_len);
|
|
close (fd);
|
|
|
|
return 0;
|
|
}
|