요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
==================================
Tracefs ring-buffer memory mapping
==================================
:Author: Vincent Donnefort <[email protected]>
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;
}
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
개요
1-14이 문서의 저자는 Vincent Donnefort다. Tracefs 링 버퍼 메모리 맵은 메모리 복사가 필요 없는 효율적인 데이터 스트리밍 방법을 제공한다.
링 버퍼를 매핑한 응용 프로그램은 `trace_pipe`와 비슷한 방식으로 그 링 버퍼의 consumer가 된다.
응용 프로그램이 링 버퍼 페이지를 직접 매핑해 중간 복사 없이 consumer 역할을 맡는다.
.. SPDX-License-Identifier: GPL-2.0
==================================
Tracefs ring-buffer memory mapping
==================================
:Author: Vincent Donnefort <[email protected]>
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;
meta-page 크기와 sub-buffer ID로 reader의 데이터 위치를 계산한다.
응용 프로그램이 현재 reader를 모두 소비하면 `trace_pipe_raw`의 `TRACE_MMAP_IOCTL_GET_READER` ioctl을 호출해 새 reader를 얻는다. 이 ioctl은 meta-page 필드도 함께 갱신한다.
현재 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-47Tracefs 링 버퍼에 매핑이 존재하는 동안 전체 링 버퍼 크기나 각 sub-buffer 크기를 늘리는 resize는 할 수 없다. snapshot도 사용할 수 없으며, `splice`는 링 버퍼의 복사 없는 swap 대신 링 버퍼 데이터를 복사하게 된다.
같은 링 버퍼를 매핑한 다른 응용 프로그램이나 커널의 `trace_pipe` 같은 동시 reader도 허용은 되지만 권장하지 않는다. reader들이 링 버퍼를 두고 경쟁하므로 `trace_pipe`에 동시 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 매핑을 각각 해제하고 파일을 닫는다.
파일 열기부터 두 매핑 해제까지의 자원 수명이다.
.. 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;
}
요약·해설
ring-buffer-map.rst:1-106Tracefs의 trace_pipe_raw를 meta-page와 sub-buffer 영역으로 mmap해 복사 없이 읽는 배치, GET_READER ioctl, 제약과 C 예제를 설명합니다.