← Documents Documentation/trace/ring-buffer-map.rst GitHub 원문 ↗

Linux 6.18.37 · Tracing

Tracefs 링 버퍼 메모리 매핑

Tracefs의 trace_pipe_raw를 meta-page와 sub-buffer 영역으로 mmap해 복사 없이 읽는 배치, GET_READER ioctl, 제약과 C 예제를 설명합니다.

Source pathDocumentation/trace/ring-buffer-map.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

ring-buffer-map.rst:1-106

Tracefs의 trace_pipe_raw를 meta-page와 sub-buffer 영역으로 mmap해 복사 없이 읽는 배치, GET_READER ioctl, 제약과 C 예제를 설명합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
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 }
107

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

개요

1-14

이 문서의 저자는 Vincent Donnefort다. Tracefs 링 버퍼 메모리 맵은 메모리 복사가 필요 없는 효율적인 데이터 스트리밍 방법을 제공한다.

링 버퍼를 매핑한 응용 프로그램은 `trace_pipe`와 비슷한 방식으로 그 링 버퍼의 consumer가 된다.

복사 없는 Tracefs 소비 경로
Tracefs per-CPU ring buffermmap()
응용 프로그램 주소 공간reader sub-buffer 직접 읽기
TRACE_MMAP_IOCTL_GET_READER다음 reader 획득

응용 프로그램이 링 버퍼 페이지를 직접 매핑해 중간 복사 없이 consumer 역할을 맡는다.

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

메모리 매핑 설정

15-35

매핑은 `trace_pipe_raw` 인터페이스에 `mmap()`을 적용해 만든다.

매핑의 첫 시스템 페이지에는 링 버퍼 통계와 설명이 들어 있으며 이를 meta-page라고 한다. meta-page의 중요한 필드 중 하나인 `reader`에는 매퍼가 안전하게 읽을 수 있는 sub-buffer ID가 들어 있다. 자세한 설계는 `ring-buffer-design.rst`를 참조한다.

meta-page 뒤에는 모든 sub-buffer가 ID 오름차순으로 배치된다. 따라서 reader가 매핑에서 시작하는 오프셋은 다음 식으로 바로 계산할 수 있다.

.. code-block:: c

        reader_id = meta->reader->id;
        reader_offset = meta->meta_page_size + reader_id * meta->subbuf_size;
Tracefs mmap 배치
영역오프셋내용
meta-page`0`통계, 크기, reader ID
sub-buffer 0`meta_page_size`첫 데이터 sub-buffer
sub-buffer N`meta_page_size + N * subbuf_size`ID N 데이터

meta-page 크기와 sub-buffer ID로 reader의 데이터 위치를 계산한다.

응용 프로그램이 현재 reader를 모두 소비하면 `trace_pipe_raw`의 `TRACE_MMAP_IOCTL_GET_READER` ioctl을 호출해 새 reader를 얻는다. 이 ioctl은 meta-page 필드도 함께 갱신한다.

reader 갱신
meta->reader.id 읽기현재 sub-buffer 소비
TRACE_MMAP_IOCTL_GET_READER새 reader 교환
meta-page 갱신새 reader.id와 통계 확인

현재 sub-buffer를 소비한 뒤 ioctl로 다음 안전한 reader를 받고 meta-page를 다시 읽는다.

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.

제약 사항

36-47

Tracefs 링 버퍼에 매핑이 존재하는 동안 전체 링 버퍼 크기나 각 sub-buffer 크기를 늘리는 resize는 할 수 없다. snapshot도 사용할 수 없으며, `splice`는 링 버퍼의 복사 없는 swap 대신 링 버퍼 데이터를 복사하게 된다.

같은 링 버퍼를 매핑한 다른 응용 프로그램이나 커널의 `trace_pipe` 같은 동시 reader도 허용은 되지만 권장하지 않는다. reader들이 링 버퍼를 두고 경쟁하므로 `trace_pipe`에 동시 reader를 둔 경우처럼 출력 결과를 예측할 수 없다.

mmap 활성 상태의 제약
항목결과
전체 링 버퍼 resize불가
sub-buffer resize불가
snapshot사용 불가
splicecopyless swap 대신 데이터 복사
동시 reader허용되지만 경쟁으로 출력이 예측 불가

매핑 수명 동안 바꿀 수 없는 항목과 성능상 달라지는 동작을 정리한다.

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.

C 사용 예제

48-106

예제는 CPU 0의 `/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw`를 읽기 전용·비차단 방식으로 연다.

먼저 시스템 페이지 하나만 `MAP_SHARED`로 매핑해 `struct trace_buffer_meta`로 해석한다. `entries`, `overrun`, `read`, `nr_subbufs` 통계를 출력하고 `meta_page_size`를 데이터 매핑 오프셋으로 사용한다.

전체 데이터 길이는 `subbuf_size * nr_subbufs`다. 이 길이를 meta-page 뒤에서 다시 매핑하고 `TRACE_MMAP_IOCTL_GET_READER`를 호출한다.

갱신된 `meta->reader.id`를 이용해 `data + subbuf_size * reader_id`에서 현재 reader 주소를 구한다. 마지막에는 데이터 매핑과 meta-page 매핑을 각각 해제하고 파일을 닫는다.

예제 실행 순서
open(trace_pipe_raw)meta-page mmap
통계와 meta_len 읽기sub-buffer 전체 mmap
GET_READER ioctlreader.id로 주소 계산
reader 소비data·meta munmap
close(fd)종료

파일 열기부터 두 매핑 해제까지의 자원 수명이다.

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