mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 a1e0dd7ce3
			
		
	
	
		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;
 | |
|         }
 |