| 1 | |
| 2 |
|
| 3 | ==================================
|
| 4 | Tracefs ring-buffer memory mapping
|
| 5 | ==================================
|
| 6 |
|
| 7 | :Author: Vincent Donnefort <[email protected]>
|
| 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 | }
|