Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Vincent Donnefort and committed by
Steven Rostedt (Google)
a1e0dd7c cf9f0f7c

+107
+1
Documentation/trace/index.rst
··· 29 29 timerlat-tracer 30 30 intel_th 31 31 ring-buffer-design 32 + ring-buffer-map 32 33 stm 33 34 sys-t 34 35 coresight/index
+106
Documentation/trace/ring-buffer-map.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ================================== 4 + Tracefs ring-buffer memory mapping 5 + ================================== 6 + 7 + :Author: Vincent Donnefort <vdonnefort@google.com> 8 + 9 + Overview 10 + ======== 11 + Tracefs ring-buffer memory map provides an efficient method to stream data 12 + as no memory copy is necessary. The application mapping the ring-buffer becomes 13 + then a consumer for that ring-buffer, in a similar fashion to trace_pipe. 14 + 15 + Memory mapping setup 16 + ==================== 17 + The mapping works with a mmap() of the trace_pipe_raw interface. 18 + 19 + The first system page of the mapping contains ring-buffer statistics and 20 + description. It is referred to as the meta-page. One of the most important 21 + fields of the meta-page is the reader. It contains the sub-buffer ID which can 22 + be safely read by the mapper (see ring-buffer-design.rst). 23 + 24 + The meta-page is followed by all the sub-buffers, ordered by ascending ID. It is 25 + therefore effortless to know where the reader starts in the mapping: 26 + 27 + .. code-block:: c 28 + 29 + reader_id = meta->reader->id; 30 + reader_offset = meta->meta_page_size + reader_id * meta->subbuf_size; 31 + 32 + When the application is done with the current reader, it can get a new one using 33 + the trace_pipe_raw ioctl() TRACE_MMAP_IOCTL_GET_READER. This ioctl also updates 34 + the meta-page fields. 35 + 36 + Limitations 37 + =========== 38 + When a mapping is in place on a Tracefs ring-buffer, it is not possible to 39 + either resize it (either by increasing the entire size of the ring-buffer or 40 + each subbuf). It is also not possible to use snapshot and causes splice to copy 41 + the ring buffer data instead of using the copyless swap from the ring buffer. 42 + 43 + Concurrent readers (either another application mapping that ring-buffer or the 44 + kernel with trace_pipe) are allowed but not recommended. They will compete for 45 + the ring-buffer and the output is unpredictable, just like concurrent readers on 46 + trace_pipe would be. 47 + 48 + Example 49 + ======= 50 + 51 + .. code-block:: c 52 + 53 + #include <fcntl.h> 54 + #include <stdio.h> 55 + #include <stdlib.h> 56 + #include <unistd.h> 57 + 58 + #include <linux/trace_mmap.h> 59 + 60 + #include <sys/mman.h> 61 + #include <sys/ioctl.h> 62 + 63 + #define TRACE_PIPE_RAW "/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw" 64 + 65 + int main(void) 66 + { 67 + int page_size = getpagesize(), fd, reader_id; 68 + unsigned long meta_len, data_len; 69 + struct trace_buffer_meta *meta; 70 + void *map, *reader, *data; 71 + 72 + fd = open(TRACE_PIPE_RAW, O_RDONLY | O_NONBLOCK); 73 + if (fd < 0) 74 + exit(EXIT_FAILURE); 75 + 76 + map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); 77 + if (map == MAP_FAILED) 78 + exit(EXIT_FAILURE); 79 + 80 + meta = (struct trace_buffer_meta *)map; 81 + meta_len = meta->meta_page_size; 82 + 83 + printf("entries: %llu\n", meta->entries); 84 + printf("overrun: %llu\n", meta->overrun); 85 + printf("read: %llu\n", meta->read); 86 + printf("nr_subbufs: %u\n", meta->nr_subbufs); 87 + 88 + data_len = meta->subbuf_size * meta->nr_subbufs; 89 + data = mmap(NULL, data_len, PROT_READ, MAP_SHARED, fd, meta_len); 90 + if (data == MAP_FAILED) 91 + exit(EXIT_FAILURE); 92 + 93 + if (ioctl(fd, TRACE_MMAP_IOCTL_GET_READER) < 0) 94 + exit(EXIT_FAILURE); 95 + 96 + reader_id = meta->reader.id; 97 + reader = data + meta->subbuf_size * reader_id; 98 + 99 + printf("Current reader address: %p\n", reader); 100 + 101 + munmap(data, data_len); 102 + munmap(meta, meta_len); 103 + close (fd); 104 + 105 + return 0; 106 + }