요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
=========================================
user_events: User-based Event Tracing
=========================================
:Author: Beau Belgrave
Overview
--------
User based trace events allow user processes to create events and trace data
that can be viewed via existing tools, such as ftrace and perf.
To enable this feature, build your kernel with CONFIG_USER_EVENTS=y.
Programs can view status of the events via
/sys/kernel/tracing/user_events_status and can both register and write
data out via /sys/kernel/tracing/user_events_data.
Programs can also use /sys/kernel/tracing/dynamic_events to register and
delete user based events via the u: prefix. The format of the command to
dynamic_events is the same as the ioctl with the u: prefix applied. This
requires CAP_PERFMON due to the event persisting, otherwise -EPERM is returned.
Typically programs will register a set of events that they wish to expose to
tools that can read trace_events (such as ftrace and perf). The registration
process tells the kernel which address and bit to reflect if any tool has
enabled the event and data should be written. The registration will give back
a write index which describes the data when a write() or writev() is called
on the /sys/kernel/tracing/user_events_data file.
The structures referenced in this document are contained within the
/include/uapi/linux/user_events.h file in the source tree.
**NOTE:** *Both user_events_status and user_events_data are under the tracefs
filesystem and may be mounted at different paths than above.*
Registering
-----------
Registering within a user process is done via ioctl() out to the
/sys/kernel/tracing/user_events_data file. The command to issue is
DIAG_IOCSREG.
This command takes a packed struct user_reg as an argument::
struct user_reg {
/* Input: Size of the user_reg structure being used */
__u32 size;
/* Input: Bit in enable address to use */
__u8 enable_bit;
/* Input: Enable size in bytes at address */
__u8 enable_size;
/* Input: Flags to use, if any */
__u16 flags;
/* Input: Address to update when enabled */
__u64 enable_addr;
/* Input: Pointer to string with event name, description and flags */
__u64 name_args;
/* Output: Index of the event to use when writing data */
__u32 write_index;
} __attribute__((__packed__));
The struct user_reg requires all the above inputs to be set appropriately.
+ size: This must be set to sizeof(struct user_reg).
+ enable_bit: The bit to reflect the event status at the address specified by
enable_addr.
+ enable_size: The size of the value specified by enable_addr.
This must be 4 (32-bit) or 8 (64-bit). 64-bit values are only allowed to be
used on 64-bit kernels, however, 32-bit can be used on all kernels.
+ flags: The flags to use, if any.
Callers should first attempt to use flags and retry without flags to ensure
support for lower versions of the kernel. If a flag is not supported -EINVAL
is returned.
+ enable_addr: The address of the value to use to reflect event status. This
must be naturally aligned and write accessible within the user program.
+ name_args: The name and arguments to describe the event, see command format
for details.
The following flags are currently supported.
+ USER_EVENT_REG_PERSIST: The event will not delete upon the last reference
closing. Callers may use this if an event should exist even after the
process closes or unregisters the event. Requires CAP_PERFMON otherwise
-EPERM is returned.
+ USER_EVENT_REG_MULTI_FORMAT: The event can contain multiple formats. This
allows programs to prevent themselves from being blocked when their event
format changes and they wish to use the same name. When this flag is used the
tracepoint name will be in the new format of "name.unique_id" vs the older
format of "name". A tracepoint will be created for each unique pair of name
and format. This means if several processes use the same name and format,
they will use the same tracepoint. If yet another process uses the same name,
but a different format than the other processes, it will use a different
tracepoint with a new unique id. Recording programs need to scan tracefs for
the various different formats of the event name they are interested in
recording. The system name of the tracepoint will also use "user_events_multi"
instead of "user_events". This prevents single-format event names conflicting
with any multi-format event names within tracefs. The unique_id is output as
a hex string. Recording programs should ensure the tracepoint name starts with
the event name they registered and has a suffix that starts with . and only
has hex characters. For example to find all versions of the event "test" you
can use the regex "^test\.[0-9a-fA-F]+$".
Upon successful registration the following is set.
+ write_index: The index to use for this file descriptor that represents this
event when writing out data. The index is unique to this instance of the file
descriptor that was used for the registration. See writing data for details.
User based events show up under tracefs like any other event under the
subsystem named "user_events". This means tools that wish to attach to the
events need to use /sys/kernel/tracing/events/user_events/[name]/enable
or perf record -e user_events:[name] when attaching/recording.
**NOTE:** The event subsystem name by default is "user_events". Callers should
not assume it will always be "user_events". Operators reserve the right in the
future to change the subsystem name per-process to accommodate event isolation.
In addition if the USER_EVENT_REG_MULTI_FORMAT flag is used the tracepoint name
will have a unique id appended to it and the system name will be
"user_events_multi" as described above.
Command Format
^^^^^^^^^^^^^^
The command string format is as follows::
name[:FLAG1[,FLAG2...]] [Field1[;Field2...]]
Supported Flags
^^^^^^^^^^^^^^^
None yet
Field Format
^^^^^^^^^^^^
::
type name [size]
Basic types are supported (__data_loc, u32, u64, int, char, char[20], etc).
User programs are encouraged to use clearly sized types like u32.
**NOTE:** *Long is not supported since size can vary between user and kernel.*
The size is only valid for types that start with a struct prefix.
This allows user programs to describe custom structs out to tools, if required.
For example, a struct in C that looks like this::
struct mytype {
char data[20];
};
Would be represented by the following field::
struct mytype myname 20
Deleting
--------
Deleting an event from within a user process is done via ioctl() out to the
/sys/kernel/tracing/user_events_data file. The command to issue is
DIAG_IOCSDEL.
This command only requires a single string specifying the event to delete by
its name. Delete will only succeed if there are no references left to the
event (in both user and kernel space). User programs should use a separate file
to request deletes than the one used for registration due to this.
**NOTE:** By default events will auto-delete when there are no references left
to the event. If programs do not want auto-delete, they must use the
USER_EVENT_REG_PERSIST flag when registering the event. Once that flag is used
the event exists until DIAG_IOCSDEL is invoked. Both register and delete of an
event that persists requires CAP_PERFMON, otherwise -EPERM is returned. When
there are multiple formats of the same event name, all events with the same
name will be attempted to be deleted. If only a specific version is wanted to
be deleted then the /sys/kernel/tracing/dynamic_events file should be used for
that specific format of the event.
Unregistering
-------------
If after registering an event it is no longer wanted to be updated then it can
be disabled via ioctl() out to the /sys/kernel/tracing/user_events_data file.
The command to issue is DIAG_IOCSUNREG. This is different than deleting, where
deleting actually removes the event from the system. Unregistering simply tells
the kernel your process is no longer interested in updates to the event.
This command takes a packed struct user_unreg as an argument::
struct user_unreg {
/* Input: Size of the user_unreg structure being used */
__u32 size;
/* Input: Bit to unregister */
__u8 disable_bit;
/* Input: Reserved, set to 0 */
__u8 __reserved;
/* Input: Reserved, set to 0 */
__u16 __reserved2;
/* Input: Address to unregister */
__u64 disable_addr;
} __attribute__((__packed__));
The struct user_unreg requires all the above inputs to be set appropriately.
+ size: This must be set to sizeof(struct user_unreg).
+ disable_bit: This must be set to the bit to disable (same bit that was
previously registered via enable_bit).
+ disable_addr: This must be set to the address to disable (same address that was
previously registered via enable_addr).
**NOTE:** Events are automatically unregistered when execve() is invoked. During
fork() the registered events will be retained and must be unregistered manually
in each process if wanted.
Status
------
When tools attach/record user based events the status of the event is updated
in realtime. This allows user programs to only incur the cost of the write() or
writev() calls when something is actively attached to the event.
The kernel will update the specified bit that was registered for the event as
tools attach/detach from the event. User programs simply check if the bit is set
to see if something is attached or not.
Administrators can easily check the status of all registered events by reading
the user_events_status file directly via a terminal. The output is as follows::
Name [# Comments]
...
Active: ActiveCount
Busy: BusyCount
For example, on a system that has a single event the output looks like this::
test
Active: 1
Busy: 0
If a user enables the user event via ftrace, the output would change to this::
test # Used by ftrace
Active: 1
Busy: 1
Writing Data
------------
After registering an event the same fd that was used to register can be used
to write an entry for that event. The write_index returned must be at the start
of the data, then the remaining data is treated as the payload of the event.
For example, if write_index returned was 1 and I wanted to write out an int
payload of the event. Then the data would have to be 8 bytes (2 ints) in size,
with the first 4 bytes being equal to 1 and the last 4 bytes being equal to the
value I want as the payload.
In memory this would look like this::
int index;
int payload;
User programs might have well known structs that they wish to use to emit out
as payloads. In those cases writev() can be used, with the first vector being
the index and the following vector(s) being the actual event payload.
For example, if I have a struct like this::
struct payload {
int src;
int dst;
int flags;
} __attribute__((__packed__));
It's advised for user programs to do the following::
struct iovec io[2];
struct payload e;
io[0].iov_base = &write_index;
io[0].iov_len = sizeof(write_index);
io[1].iov_base = &e;
io[1].iov_len = sizeof(e);
writev(fd, (const struct iovec*)io, 2);
**NOTE:** *The write_index is not emitted out into the trace being recorded.*
Example Code
------------
See sample code in samples/user_events.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
개요와 tracefs 인터페이스
1-34저자는 Beau Belgrave입니다. 사용자 기반 trace 이벤트를 이용하면 사용자 프로세스가 이벤트와 데이터를 생성하고, ftrace나 perf 같은 기존 도구가 이를 기록하고 표시할 수 있습니다.
기능을 사용하려면 커널을 `CONFIG_USER_EVENTS=y`로 빌드해야 합니다. 프로그램은 `/sys/kernel/tracing/user_events_status`에서 이벤트 상태를 보고, `/sys/kernel/tracing/user_events_data`에서 이벤트를 등록하고 데이터를 기록합니다.
`/sys/kernel/tracing/dynamic_events`에 `u:` 접두사를 붙인 명령을 써서 사용자 이벤트를 등록하거나 삭제할 수도 있습니다. 명령 본문 형식은 ioctl 형식과 같지만, 이벤트가 지속되므로 `CAP_PERFMON` 권한이 필요하며 권한이 없으면 `-EPERM`을 반환합니다.
일반적인 프로그램은 ftrace와 perf처럼 `trace_events`를 읽는 도구에 노출할 이벤트 집합을 먼저 등록합니다. 등록 과정에서 어떤 도구가 이벤트를 활성화했는지를 반영할 사용자 주소와 비트를 커널에 알려 줍니다.
등록에 성공하면 커널은 `write_index`를 돌려줍니다. 이후 같은 `user_events_data` 파일에 `write()` 또는 `writev()`할 때 이 인덱스가 뒤따르는 payload의 이벤트 형식을 식별합니다.
이 문서의 UAPI 구조체는 소스 트리의 `/include/uapi/linux/user_events.h`에 있습니다. `user_events_status`와 `user_events_data`는 tracefs 아래에 있으므로 실제 마운트 지점에 따라 문서의 절대 경로와 달라질 수 있습니다.
프로세스가 이벤트를 등록하고 활성 상태를 확인한 뒤 인덱스와 payload를 기록합니다.
상태 조회, 등록·기록, 동적 지속 이벤트 관리의 역할입니다.
=========================================
user_events: User-based Event Tracing
=========================================
:Author: Beau Belgrave
Overview
--------
User based trace events allow user processes to create events and trace data
that can be viewed via existing tools, such as ftrace and perf.
To enable this feature, build your kernel with CONFIG_USER_EVENTS=y.
Programs can view status of the events via
/sys/kernel/tracing/user_events_status and can both register and write
data out via /sys/kernel/tracing/user_events_data.
Programs can also use /sys/kernel/tracing/dynamic_events to register and
delete user based events via the u: prefix. The format of the command to
dynamic_events is the same as the ioctl with the u: prefix applied. This
requires CAP_PERFMON due to the event persisting, otherwise -EPERM is returned.
Typically programs will register a set of events that they wish to expose to
tools that can read trace_events (such as ftrace and perf). The registration
process tells the kernel which address and bit to reflect if any tool has
enabled the event and data should be written. The registration will give back
a write index which describes the data when a write() or writev() is called
on the /sys/kernel/tracing/user_events_data file.
The structures referenced in this document are contained within the
/include/uapi/linux/user_events.h file in the source tree.
**NOTE:** *Both user_events_status and user_events_data are under the tracefs
filesystem and may be mounted at different paths than above.*
DIAG_IOCSREG와 struct user_reg
35-87사용자 프로세스 안에서 이벤트를 등록하려면 `/sys/kernel/tracing/user_events_data` 파일 설명자에 `DIAG_IOCSREG` ioctl을 실행합니다. 인수는 packed `struct user_reg`입니다.
This command takes a packed struct user_reg as an argument::
struct user_reg {
/* Input: Size of the user_reg structure being used */
__u32 size;
/* Input: Bit in enable address to use */
__u8 enable_bit;
/* Input: Enable size in bytes at address */
__u8 enable_size;
/* Input: Flags to use, if any */
__u16 flags;
/* Input: Address to update when enabled */
__u64 enable_addr;
/* Input: Pointer to string with event name, description and flags */
__u64 name_args;
/* Output: Index of the event to use when writing data */
__u32 write_index;
} __attribute__((__packed__));
`size`는 호출자가 사용하는 구조체 크기인 `sizeof(struct user_reg)`로 설정합니다. 이 필드 덕분에 커널과 사용자 프로그램이 구조체 버전을 확인할 수 있습니다.
`enable_bit`는 도구가 이벤트를 사용 중인지 반영할 `enable_addr` 값의 비트 번호입니다. `enable_size`는 그 값의 바이트 크기로 4 또는 8이어야 하며, 8바이트 값은 64비트 커널에서만 허용됩니다. 4바이트 값은 모든 커널에서 사용할 수 있습니다.
`flags`에는 요청할 등록 플래그를 넣습니다. 하위 커널과 호환하려면 먼저 플래그를 사용해 시도한 뒤, 지원하지 않아 `-EINVAL`이 반환되면 플래그 없이 다시 시도하는 방식이 권장됩니다.
`enable_addr`는 이벤트 활성 상태를 반영할 사용자 프로그램 내부 값의 주소입니다. 자연 정렬되어 있어야 하고 커널이 해당 프로세스 메모리에 쓸 수 있어야 합니다.
`name_args`는 이벤트 이름, 설명, 플래그를 담은 문자열을 가리키는 포인터입니다. 성공 시 출력 필드 `write_index`가 설정되며 실제 데이터 기록 때 사용됩니다.
입력 필드와 등록 성공 시 출력되는 식별자를 구분합니다.
사용자 구조체 검증에서 write_index 반환까지의 흐름입니다.
Registering
-----------
Registering within a user process is done via ioctl() out to the
/sys/kernel/tracing/user_events_data file. The command to issue is
DIAG_IOCSREG.
This command takes a packed struct user_reg as an argument::
struct user_reg {
/* Input: Size of the user_reg structure being used */
__u32 size;
/* Input: Bit in enable address to use */
__u8 enable_bit;
/* Input: Enable size in bytes at address */
__u8 enable_size;
/* Input: Flags to use, if any */
__u16 flags;
/* Input: Address to update when enabled */
__u64 enable_addr;
/* Input: Pointer to string with event name, description and flags */
__u64 name_args;
/* Output: Index of the event to use when writing data */
__u32 write_index;
} __attribute__((__packed__));
The struct user_reg requires all the above inputs to be set appropriately.
+ size: This must be set to sizeof(struct user_reg).
+ enable_bit: The bit to reflect the event status at the address specified by
enable_addr.
+ enable_size: The size of the value specified by enable_addr.
This must be 4 (32-bit) or 8 (64-bit). 64-bit values are only allowed to be
used on 64-bit kernels, however, 32-bit can be used on all kernels.
+ flags: The flags to use, if any.
Callers should first attempt to use flags and retry without flags to ensure
support for lower versions of the kernel. If a flag is not supported -EINVAL
is returned.
+ enable_addr: The address of the value to use to reflect event status. This
must be naturally aligned and write accessible within the user program.
+ name_args: The name and arguments to describe the event, see command format
for details.
지속 이벤트와 다중 형식
88-130`USER_EVENT_REG_PERSIST`는 마지막 참조가 닫혀도 이벤트를 자동 삭제하지 않습니다. 프로세스가 닫히거나 등록을 해제한 뒤에도 이벤트가 남아야 할 때 사용하며 `CAP_PERFMON`이 없으면 `-EPERM`입니다.
`USER_EVENT_REG_MULTI_FORMAT`은 같은 논리 이름에 여러 이벤트 형식을 허용합니다. 프로그램이 형식을 변경하면서 같은 이름을 계속 사용해야 할 때, 기존 형식 사용자와의 충돌로 등록이 막히는 일을 피합니다.
다중 형식을 사용하면 tracepoint 이름은 기존 `name` 대신 `name.unique_id`가 됩니다. 이름과 형식의 고유한 쌍마다 tracepoint 하나가 생성되므로 같은 이름과 형식을 쓰는 여러 프로세스는 같은 tracepoint를 공유하고, 형식이 다르면 새 unique ID를 받습니다.
기록 프로그램은 tracefs를 검색해 관심 이름의 여러 형식을 찾아야 합니다. 다중 형식 이벤트의 subsystem은 `user_events`가 아니라 `user_events_multi`이며, 단일 형식 이름과의 충돌을 막습니다.
`unique_id`는 16진수 문자열입니다. 예를 들어 `test`의 모든 형식을 찾을 때는 이름이 `test.`로 시작하고 뒤가 16진수뿐인지 `^test\.[0-9a-fA-F]+$` 같은 정규식으로 확인해야 합니다.
등록 성공 후 `write_index`는 등록에 사용한 파일 설명자 인스턴스에 대해 고유합니다. 다른 파일 설명자에서 받은 인덱스와 혼용해서는 안 됩니다.
기본 단일 형식 이벤트는 tracefs의 `user_events` subsystem 아래에 나타납니다. 도구는 `/sys/kernel/tracing/events/user_events/[name]/enable` 또는 `perf record -e user_events:[name]`으로 연결하고 기록합니다.
다만 subsystem 이름이 영원히 `user_events`라고 가정하면 안 됩니다. 향후 프로세스별 이벤트 격리를 위해 운영자가 이름을 바꿀 수 있고, 다중 형식 플래그를 쓰면 이미 `user_events_multi`와 unique ID 규칙이 적용됩니다.
수명과 이름·형식 처리에 영향을 주는 두 플래그입니다.
이름과 형식의 조합이 재사용 여부를 결정합니다.
The following flags are currently supported.
+ USER_EVENT_REG_PERSIST: The event will not delete upon the last reference
closing. Callers may use this if an event should exist even after the
process closes or unregisters the event. Requires CAP_PERFMON otherwise
-EPERM is returned.
+ USER_EVENT_REG_MULTI_FORMAT: The event can contain multiple formats. This
allows programs to prevent themselves from being blocked when their event
format changes and they wish to use the same name. When this flag is used the
tracepoint name will be in the new format of "name.unique_id" vs the older
format of "name". A tracepoint will be created for each unique pair of name
and format. This means if several processes use the same name and format,
they will use the same tracepoint. If yet another process uses the same name,
but a different format than the other processes, it will use a different
tracepoint with a new unique id. Recording programs need to scan tracefs for
the various different formats of the event name they are interested in
recording. The system name of the tracepoint will also use "user_events_multi"
instead of "user_events". This prevents single-format event names conflicting
with any multi-format event names within tracefs. The unique_id is output as
a hex string. Recording programs should ensure the tracepoint name starts with
the event name they registered and has a suffix that starts with . and only
has hex characters. For example to find all versions of the event "test" you
can use the regex "^test\.[0-9a-fA-F]+$".
Upon successful registration the following is set.
+ write_index: The index to use for this file descriptor that represents this
event when writing out data. The index is unique to this instance of the file
descriptor that was used for the registration. See writing data for details.
User based events show up under tracefs like any other event under the
subsystem named "user_events". This means tools that wish to attach to the
events need to use /sys/kernel/tracing/events/user_events/[name]/enable
or perf record -e user_events:[name] when attaching/recording.
**NOTE:** The event subsystem name by default is "user_events". Callers should
not assume it will always be "user_events". Operators reserve the right in the
future to change the subsystem name per-process to accommodate event isolation.
In addition if the USER_EVENT_REG_MULTI_FORMAT flag is used the tracepoint name
will have a unique id appended to it and the system name will be
"user_events_multi" as described above.
이벤트 명령과 필드 형식
131-164등록 문자열의 전체 형식은 `name[:FLAG1[,FLAG2...]] [Field1[;Field2...]]`입니다. 현재 명령 문자열 수준에서 지원되는 플래그는 아직 없습니다.
Command Format
^^^^^^^^^^^^^^
The command string format is as follows::
name[:FLAG1[,FLAG2...]] [Field1[;Field2...]]
Supported Flags
^^^^^^^^^^^^^^^
None yet
Field Format
^^^^^^^^^^^^
::
type name [size]
필드는 `type name [size]` 형식입니다. `__data_loc`, `u32`, `u64`, `int`, `char`, `char[20]` 같은 기본 자료형을 지원하며 사용자 프로그램에는 폭이 명확한 `u32` 같은 형식을 권장합니다.
`long`은 사용자 공간과 커널에서 크기가 달라질 수 있으므로 지원하지 않습니다. ABI에서 크기가 모호한 형식 대신 명시적 폭을 사용해야 합니다.
선택적 `size`는 `struct` 접두사로 시작하는 자료형에서만 유효합니다. 사용자 프로그램이 사용자 정의 구조체의 바이트 크기를 기록 도구에 설명할 때 사용합니다.
예제의 `struct mytype`은 20바이트 char 배열을 가지므로 이벤트 필드에서는 `struct mytype myname 20`으로 표현합니다.
For example, a struct in C that looks like this::
struct mytype {
char data[20];
};
Would be represented by the following field::
struct mytype myname 20
기본형과 사용자 정의 구조체의 표기 제약입니다.
Command Format
^^^^^^^^^^^^^^
The command string format is as follows::
name[:FLAG1[,FLAG2...]] [Field1[;Field2...]]
Supported Flags
^^^^^^^^^^^^^^^
None yet
Field Format
^^^^^^^^^^^^
::
type name [size]
Basic types are supported (__data_loc, u32, u64, int, char, char[20], etc).
User programs are encouraged to use clearly sized types like u32.
**NOTE:** *Long is not supported since size can vary between user and kernel.*
The size is only valid for types that start with a struct prefix.
This allows user programs to describe custom structs out to tools, if required.
For example, a struct in C that looks like this::
struct mytype {
char data[20];
};
Would be represented by the following field::
struct mytype myname 20
DIAG_IOCSDEL로 이벤트 삭제
165-185사용자 프로세스에서 이벤트를 삭제하려면 `/sys/kernel/tracing/user_events_data`에 `DIAG_IOCSDEL` ioctl을 실행합니다. 인수는 삭제할 이벤트 이름 문자열 하나입니다.
사용자 공간과 커널 공간에 이벤트 참조가 하나도 없을 때만 삭제에 성공합니다. 등록에 사용한 파일과 별도의 파일 설명자를 열어 삭제를 요청하는 것이 권장됩니다.
기본 이벤트는 참조가 없어지면 자동 삭제됩니다. 자동 삭제를 원하지 않으면 등록 때 `USER_EVENT_REG_PERSIST`를 사용하며, 이후 `DIAG_IOCSDEL`을 호출할 때까지 이벤트가 남습니다.
지속 이벤트의 등록과 삭제에는 모두 `CAP_PERFMON`이 필요하고, 없으면 `-EPERM`입니다. 같은 이름의 형식이 여러 개면 이름 삭제는 그 이름의 모든 이벤트 삭제를 시도합니다.
다중 형식 중 특정 버전만 지우려면 `/sys/kernel/tracing/dynamic_events`에서 그 이벤트의 구체적인 형식을 지정해 삭제해야 합니다.
참조와 플래그에 따른 이벤트 수명입니다.
Deleting
--------
Deleting an event from within a user process is done via ioctl() out to the
/sys/kernel/tracing/user_events_data file. The command to issue is
DIAG_IOCSDEL.
This command only requires a single string specifying the event to delete by
its name. Delete will only succeed if there are no references left to the
event (in both user and kernel space). User programs should use a separate file
to request deletes than the one used for registration due to this.
**NOTE:** By default events will auto-delete when there are no references left
to the event. If programs do not want auto-delete, they must use the
USER_EVENT_REG_PERSIST flag when registering the event. Once that flag is used
the event exists until DIAG_IOCSDEL is invoked. Both register and delete of an
event that persists requires CAP_PERFMON, otherwise -EPERM is returned. When
there are multiple formats of the same event name, all events with the same
name will be attempted to be deleted. If only a specific version is wanted to
be deleted then the /sys/kernel/tracing/dynamic_events file should be used for
that specific format of the event.
등록 해제와 struct user_unreg
186-226`DIAG_IOCSUNREG`은 이벤트를 시스템에서 삭제하지 않고, 이 프로세스가 해당 이벤트의 상태 갱신을 더 이상 원하지 않는다고 커널에 알립니다. 실제 객체를 제거하는 `DIAG_IOCSDEL`과 구분해야 합니다.
등록 해제도 `/sys/kernel/tracing/user_events_data` 파일 설명자에 ioctl을 실행하며, packed `struct user_unreg`를 인수로 넘깁니다.
This command takes a packed struct user_unreg as an argument::
struct user_unreg {
/* Input: Size of the user_unreg structure being used */
__u32 size;
/* Input: Bit to unregister */
__u8 disable_bit;
/* Input: Reserved, set to 0 */
__u8 __reserved;
/* Input: Reserved, set to 0 */
__u16 __reserved2;
/* Input: Address to unregister */
__u64 disable_addr;
} __attribute__((__packed__));
`size`는 `sizeof(struct user_unreg)`입니다. `disable_bit`는 등록 당시 `enable_bit`와 같은 비트이고, `disable_addr`는 등록 당시 `enable_addr`와 같은 주소여야 합니다. 두 reserved 필드는 0으로 설정합니다.
`execve()`가 호출되면 이벤트 등록은 자동으로 해제됩니다. 반면 `fork()`에서는 등록 상태가 자식 프로세스에 유지되므로, 필요하다면 각 프로세스가 직접 등록 해제해야 합니다.
등록 때 사용한 비트와 주소를 동일하게 지정합니다.
시스템 이벤트 수명에 미치는 영향이 다릅니다.
Unregistering
-------------
If after registering an event it is no longer wanted to be updated then it can
be disabled via ioctl() out to the /sys/kernel/tracing/user_events_data file.
The command to issue is DIAG_IOCSUNREG. This is different than deleting, where
deleting actually removes the event from the system. Unregistering simply tells
the kernel your process is no longer interested in updates to the event.
This command takes a packed struct user_unreg as an argument::
struct user_unreg {
/* Input: Size of the user_unreg structure being used */
__u32 size;
/* Input: Bit to unregister */
__u8 disable_bit;
/* Input: Reserved, set to 0 */
__u8 __reserved;
/* Input: Reserved, set to 0 */
__u16 __reserved2;
/* Input: Address to unregister */
__u64 disable_addr;
} __attribute__((__packed__));
The struct user_unreg requires all the above inputs to be set appropriately.
+ size: This must be set to sizeof(struct user_unreg).
+ disable_bit: This must be set to the bit to disable (same bit that was
previously registered via enable_bit).
+ disable_addr: This must be set to the address to disable (same address that was
previously registered via enable_addr).
**NOTE:** Events are automatically unregistered when execve() is invoked. During
fork() the registered events will be retained and must be unregistered manually
in each process if wanted.
활성 상태 비트와 상태 파일
227-259도구가 사용자 이벤트에 연결하거나 기록을 시작하면 이벤트 상태가 실시간으로 바뀝니다. 프로그램은 실제 소비자가 있을 때만 `write()` 또는 `writev()` 비용을 지도록 등록한 상태 비트를 먼저 검사할 수 있습니다.
도구가 attach 또는 detach할 때 커널은 등록된 사용자 주소의 지정 비트를 갱신합니다. 프로그램은 이 비트가 설정되었는지만 확인하면 현재 이벤트 소비자가 있는지 알 수 있습니다.
관리자는 `user_events_status` 파일을 읽어 모든 등록 이벤트의 상태를 확인할 수 있습니다. 각 이벤트 이름에는 사용 주체를 설명하는 주석이 붙을 수 있고, 마지막에는 `Active`와 `Busy` 개수가 표시됩니다.
Administrators can easily check the status of all registered events by reading
the user_events_status file directly via a terminal. The output is as follows::
Name [# Comments]
...
Active: ActiveCount
Busy: BusyCount
For example, on a system that has a single event the output looks like this::
test
Active: 1
Busy: 0
If a user enables the user event via ftrace, the output would change to this::
test # Used by ftrace
Active: 1
Busy: 1
예제에서 이벤트 `test` 하나만 등록되어 있고 아직 소비자가 없으면 `Active: 1`, `Busy: 0`입니다. ftrace가 이벤트를 활성화하면 이름 뒤에 `# Used by ftrace`가 붙고 `Busy: 1`로 바뀝니다.
등록 수와 실제 사용 중인 수를 구분합니다.
소비자가 있을 때만 시스템 호출로 payload를 기록합니다.
Status
------
When tools attach/record user based events the status of the event is updated
in realtime. This allows user programs to only incur the cost of the write() or
writev() calls when something is actively attached to the event.
The kernel will update the specified bit that was registered for the event as
tools attach/detach from the event. User programs simply check if the bit is set
to see if something is attached or not.
Administrators can easily check the status of all registered events by reading
the user_events_status file directly via a terminal. The output is as follows::
Name [# Comments]
...
Active: ActiveCount
Busy: BusyCount
For example, on a system that has a single event the output looks like this::
test
Active: 1
Busy: 0
If a user enables the user event via ftrace, the output would change to this::
test # Used by ftrace
Active: 1
Busy: 1
write_index와 payload 기록
260-304이벤트를 등록한 파일 설명자는 데이터 기록에도 사용합니다. 반환받은 `write_index`를 버퍼 맨 앞에 두고, 그 뒤의 바이트를 이벤트 payload로 배치해야 합니다.
예를 들어 `write_index`가 1이고 int payload 하나를 기록한다면 전체 데이터는 int 두 개, 즉 8바이트입니다. 앞 4바이트는 값 1인 인덱스이고 뒤 4바이트는 기록할 payload 값입니다.
For example, if write_index returned was 1 and I wanted to write out an int
payload of the event. Then the data would have to be 8 bytes (2 ints) in size,
with the first 4 bytes being equal to 1 and the last 4 bytes being equal to the
value I want as the payload.
In memory this would look like this::
int index;
int payload;
8바이트 예제의 메모리 순서입니다.
프로그램이 잘 알려진 구조체를 payload로 내보내려면 `writev()`를 사용할 수 있습니다. 첫 iovec는 `write_index`, 이후 iovec들은 실제 이벤트 payload를 가리킵니다.
예제의 packed `struct payload`는 `src`, `dst`, `flags` 세 int 필드를 가집니다. `io[0]`에는 인덱스 주소와 크기, `io[1]`에는 구조체 주소와 크기를 넣고 두 벡터를 한 번에 기록합니다.
For example, if I have a struct like this::
struct payload {
int src;
int dst;
int flags;
} __attribute__((__packed__));
It's advised for user programs to do the following::
struct iovec io[2];
struct payload e;
io[0].iov_base = &write_index;
io[0].iov_len = sizeof(write_index);
io[1].iov_base = &e;
io[1].iov_len = sizeof(e);
writev(fd, (const struct iovec*)io, 2);
인덱스 벡터 뒤에 하나 이상의 payload 벡터를 연결합니다.
`write_index`는 커널이 어떤 이벤트 형식인지 선택하는 데만 사용되고 기록되는 trace payload 자체에는 포함되지 않습니다. 전체 예제 코드는 `samples/user_events`에서 볼 수 있습니다.
Writing Data
------------
After registering an event the same fd that was used to register can be used
to write an entry for that event. The write_index returned must be at the start
of the data, then the remaining data is treated as the payload of the event.
For example, if write_index returned was 1 and I wanted to write out an int
payload of the event. Then the data would have to be 8 bytes (2 ints) in size,
with the first 4 bytes being equal to 1 and the last 4 bytes being equal to the
value I want as the payload.
In memory this would look like this::
int index;
int payload;
User programs might have well known structs that they wish to use to emit out
as payloads. In those cases writev() can be used, with the first vector being
the index and the following vector(s) being the actual event payload.
For example, if I have a struct like this::
struct payload {
int src;
int dst;
int flags;
} __attribute__((__packed__));
It's advised for user programs to do the following::
struct iovec io[2];
struct payload e;
io[0].iov_base = &write_index;
io[0].iov_len = sizeof(write_index);
io[1].iov_base = &e;
io[1].iov_len = sizeof(e);
writev(fd, (const struct iovec*)io, 2);
**NOTE:** *The write_index is not emitted out into the trace being recorded.*
Example Code
------------
See sample code in samples/user_events.
요약·해설
user_events.rst:1-304user_events는 사용자 프로그램이 커널 trace 이벤트 생산자가 되게 합니다. 등록 시 상태 비트와 이벤트 형식을 연결하고, 소비자가 붙어 있을 때만 파일 설명자 고유의 write_index와 payload를 기록하면 불필요한 시스템 호출 비용을 피할 수 있습니다.