mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 09:13:38 +00:00
Documentation: tracing: Add ring-buffer mapping
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>
This commit is contained in:
parent
cf9f0f7c4c
commit
a1e0dd7ce3
@ -29,6 +29,7 @@ Linux Tracing Technologies
|
|||||||
timerlat-tracer
|
timerlat-tracer
|
||||||
intel_th
|
intel_th
|
||||||
ring-buffer-design
|
ring-buffer-design
|
||||||
|
ring-buffer-map
|
||||||
stm
|
stm
|
||||||
sys-t
|
sys-t
|
||||||
coresight/index
|
coresight/index
|
||||||
|
106
Documentation/trace/ring-buffer-map.rst
Normal file
106
Documentation/trace/ring-buffer-map.rst
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
.. 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user