|  | .. 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; | 
|  | } |