요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
Netlink payload
taskstats.rst:53-115Command, response와 exit notification의 generic-netlink attribute sequence를 정의합니다.
Aggregation과 scaling
taskstats.rst:116-180Per-TGID 누적, versioned extension과 high exit-rate flow control 전략을 설명합니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
=============================
Per-task statistics interface
=============================
Taskstats is a netlink-based interface for sending per-task and
per-process statistics from the kernel to userspace.
Taskstats was designed for the following benefits:
- efficiently provide statistics during lifetime of a task and on its exit
- unified interface for multiple accounting subsystems
- extensibility for use by future accounting patches
Terminology
-----------
"pid", "tid" and "task" are used interchangeably and refer to the standard
Linux task defined by struct task_struct. per-pid stats are the same as
per-task stats.
"tgid", "process" and "thread group" are used interchangeably and refer to the
tasks that share an mm_struct i.e. the traditional Unix process. Despite the
use of tgid, there is no special treatment for the task that is thread group
leader - a process is deemed alive as long as it has any task belonging to it.
Usage
-----
To get statistics during a task's lifetime, userspace opens a unicast netlink
socket (NETLINK_GENERIC family) and sends commands specifying a pid or a tgid.
The response contains statistics for a task (if pid is specified) or the sum of
statistics for all tasks of the process (if tgid is specified).
To obtain statistics for tasks which are exiting, the userspace listener
sends a register command and specifies a cpumask. Whenever a task exits on
one of the cpus in the cpumask, its per-pid statistics are sent to the
registered listener. Using cpumasks allows the data received by one listener
to be limited and assists in flow control over the netlink interface and is
explained in more detail below.
If the exiting task is the last thread exiting its thread group,
an additional record containing the per-tgid stats is also sent to userspace.
The latter contains the sum of per-pid stats for all threads in the thread
group, both past and present.
getdelays.c is a simple utility demonstrating usage of the taskstats interface
for reporting delay accounting statistics. Users can register cpumasks,
send commands and process responses, listen for per-tid/tgid exit data,
write the data received to a file and do basic flow control by increasing
receive buffer sizes.
Interface
---------
The user-kernel interface is encapsulated in include/linux/taskstats.h
To avoid this documentation becoming obsolete as the interface evolves, only
an outline of the current version is given. taskstats.h always overrides the
description here.
struct taskstats is the common accounting structure for both per-pid and
per-tgid data. It is versioned and can be extended by each accounting subsystem
that is added to the kernel. The fields and their semantics are defined in the
taskstats.h file.
The data exchanged between user and kernel space is a netlink message belonging
to the NETLINK_GENERIC family and using the netlink attributes interface.
The messages are in the format::
+----------+- - -+-------------+-------------------+
| nlmsghdr | Pad | genlmsghdr | taskstats payload |
+----------+- - -+-------------+-------------------+
The taskstats payload is one of the following three kinds:
1. Commands: Sent from user to kernel. Commands to get data on
a pid/tgid consist of one attribute, of type TASKSTATS_CMD_ATTR_PID/TGID,
containing a u32 pid or tgid in the attribute payload. The pid/tgid denotes
the task/process for which userspace wants statistics.
Commands to register/deregister interest in exit data from a set of cpus
consist of one attribute, of type
TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK and contain a cpumask in the
attribute payload. The cpumask is specified as an ascii string of
comma-separated cpu ranges e.g. to listen to exit data from cpus 1,2,3,5,7,8
the cpumask would be "1-3,5,7-8". If userspace forgets to deregister interest
in cpus before closing the listening socket, the kernel cleans up its interest
set over time. However, for the sake of efficiency, an explicit deregistration
is advisable.
2. Response for a command: sent from the kernel in response to a userspace
command. The payload is a series of three attributes of type:
a) TASKSTATS_TYPE_AGGR_PID/TGID : attribute containing no payload but indicates
a pid/tgid will be followed by some stats.
b) TASKSTATS_TYPE_PID/TGID: attribute whose payload is the pid/tgid whose stats
are being returned.
c) TASKSTATS_TYPE_STATS: attribute with a struct taskstats as payload. The
same structure is used for both per-pid and per-tgid stats.
3. New message sent by kernel whenever a task exits. The payload consists of a
series of attributes of the following type:
a) TASKSTATS_TYPE_AGGR_PID: indicates next two attributes will be pid+stats
b) TASKSTATS_TYPE_PID: contains exiting task's pid
c) TASKSTATS_TYPE_STATS: contains the exiting task's per-pid stats
d) TASKSTATS_TYPE_AGGR_TGID: indicates next two attributes will be tgid+stats
e) TASKSTATS_TYPE_TGID: contains tgid of process to which task belongs
f) TASKSTATS_TYPE_STATS: contains the per-tgid stats for exiting task's process
per-tgid stats
--------------
Taskstats provides per-process stats, in addition to per-task stats, since
resource management is often done at a process granularity and aggregating task
stats in userspace alone is inefficient and potentially inaccurate (due to lack
of atomicity).
However, maintaining per-process, in addition to per-task stats, within the
kernel has space and time overheads. To address this, the taskstats code
accumulates each exiting task's statistics into a process-wide data structure.
When the last task of a process exits, the process level data accumulated also
gets sent to userspace (along with the per-task data).
When a user queries to get per-tgid data, the sum of all other live threads in
the group is added up and added to the accumulated total for previously exited
threads of the same thread group.
Extending taskstats
-------------------
There are two ways to extend the taskstats interface to export more
per-task/process stats as patches to collect them get added to the kernel
in future:
1. Adding more fields to the end of the existing struct taskstats. Backward
compatibility is ensured by the version number within the
structure. Userspace will use only the fields of the struct that correspond
to the version its using.
2. Defining separate statistic structs and using the netlink attributes
interface to return them. Since userspace processes each netlink attribute
independently, it can always ignore attributes whose type it does not
understand (because it is using an older version of the interface).
Choosing between 1. and 2. is a matter of trading off flexibility and
overhead. If only a few fields need to be added, then 1. is the preferable
path since the kernel and userspace don't need to incur the overhead of
processing new netlink attributes. But if the new fields expand the existing
struct too much, requiring disparate userspace accounting utilities to
unnecessarily receive large structures whose fields are of no interest, then
extending the attributes structure would be worthwhile.
Flow control for taskstats
--------------------------
When the rate of task exits becomes large, a listener may not be able to keep
up with the kernel's rate of sending per-tid/tgid exit data leading to data
loss. This possibility gets compounded when the taskstats structure gets
extended and the number of cpus grows large.
To avoid losing statistics, userspace should do one or more of the following:
- increase the receive buffer sizes for the netlink sockets opened by
listeners to receive exit data.
- create more listeners and reduce the number of cpus being listened to by
each listener. In the extreme case, there could be one listener for each cpu.
Users may also consider setting the cpu affinity of the listener to the subset
of cpus to which it listens, especially if they are listening to just one cpu.
Despite these measures, if the userspace receives ENOBUFS error messages
indicated overflow of receive buffers, it should take measures to handle the
loss of data.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Per-task statistics interface 목적
1-14Taskstats는 kernel에서 userspace로 per-task와 per-process statistic을 보내는 netlink-based interface입니다. Task lifetime 중과 exit 시점의 statistic을 효율적으로 제공하고 여러 accounting subsystem에 unified interface를 제공하며 향후 accounting patch가 확장할 수 있도록 설계됐습니다.
수집 시점, subsystem 통합과 extension을 함께 지원합니다.
PID/TID와 TGID 용어
15-26`pid`, `tid`, `task`는 서로 바꿔 쓰며 `struct task_struct`로 정의한 표준 Linux task를 뜻합니다. Per-pid statistic은 per-task statistic과 같습니다.
`tgid`, `process`, `thread group`도 서로 바꿔 쓰며 `mm_struct`를 공유하는 task 집합, 즉 전통적인 Unix process를 뜻합니다. TGID라는 이름을 쓰더라도 thread-group leader를 특별 취급하지 않습니다. 그 process에 속한 task가 하나라도 있으면 process는 alive로 봅니다.
Kernel task identity와 traditional process aggregation을 구분합니다.
Lifetime query와 exit listener
27-52Task lifetime 중 statistic을 얻으려면 userspace가 `NETLINK_GENERIC` family의 unicast netlink socket을 열고 PID 또는 TGID를 지정한 command를 보냅니다. PID이면 task 하나, TGID이면 process의 모든 task statistic 합계를 response로 받습니다.
Exit하는 task statistic을 받으려면 listener가 register command와 cpumask를 보냅니다. Mask의 CPU에서 task가 exit할 때마다 per-pid statistic이 registered listener로 갑니다. Cpumask는 listener 하나가 받을 data를 제한하고 netlink flow control을 돕습니다.
Exit task가 thread group의 마지막 thread이면 per-tgid record도 추가로 전송합니다. 이 record는 과거와 현재를 포함해 thread group의 모든 thread per-pid statistic 합계입니다.
`getdelays.c`는 delay accounting statistic을 report하는 taskstats 사용 예입니다. Cpumask register, command·response 처리, per-tid/tgid exit data listen, file 저장, receive buffer 증가를 통한 기본 flow control을 보여 줍니다.
On-demand query와 asynchronous exit delivery를 구분합니다.
Generic netlink message와 payload
53-115User-kernel interface는 `include/linux/taskstats.h`에 있습니다. Interface가 진화할 때 이 문서가 obsolete되지 않도록 현재 version의 outline만 제시하며 실제 `taskstats.h` 정의가 항상 우선합니다.
`struct taskstats`는 per-pid와 per-tgid data가 공유하는 versioned accounting structure입니다. Kernel에 추가되는 각 accounting subsystem이 확장할 수 있고 field와 semantics는 header에 정의됩니다. 교환 data는 `NETLINK_GENERIC` family와 netlink attribute interface를 사용하는 message입니다.
원문의 ASCII box를 ordered protocol headers와 payload로 구조화했습니다.
첫 payload kind는 userspace→kernel command입니다. PID/TGID query는 `TASKSTATS_CMD_ATTR_PID` 또는 `TASKSTATS_CMD_ATTR_TGID` attribute 하나에 `u32` PID/TGID를 담습니다. Exit data CPU set의 register/deregister는 `TASKSTATS_CMD_ATTR_REGISTER_CPUMASK` 또는 `TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK`에 cpumask를 담습니다.
Cpumask는 comma-separated CPU range ASCII string입니다. CPU 1,2,3,5,7,8이면 `1-3,5,7-8`입니다. Socket close 전에 deregister하지 않아도 kernel이 시간에 따라 interest set을 cleanup하지만 efficiency를 위해 explicit deregistration을 권장합니다.
두 번째 kind는 command response입니다. `TASKSTATS_TYPE_AGGR_PID/TGID`가 PID/TGID와 statistic이 뒤따름을 알리고, `TASKSTATS_TYPE_PID/TGID` payload에 대상 ID, `TASKSTATS_TYPE_STATS` payload에 `struct taskstats`를 담습니다. Per-pid와 per-tgid 모두 같은 structure를 사용합니다.
세 번째 kind는 task exit 때 kernel이 새로 보내는 message입니다. `TASKSTATS_TYPE_AGGR_PID`, `TASKSTATS_TYPE_PID`, `TASKSTATS_TYPE_STATS`가 exiting task의 PID와 per-pid statistic을 구성합니다. 이어서 `TASKSTATS_TYPE_AGGR_TGID`, `TASKSTATS_TYPE_TGID`, `TASKSTATS_TYPE_STATS`가 process TGID와 per-tgid statistic을 구성합니다.
Direction과 attribute sequence를 요약합니다.
Per-TGID aggregation
116-133Resource management는 process granularity로 수행하는 경우가 많고 userspace만으로 task statistic을 aggregate하면 비효율적이며 atomicity 부족으로 부정확할 수 있어 taskstats는 per-task뿐 아니라 per-process statistic도 제공합니다.
Kernel에서 per-task와 함께 per-process statistic을 유지하면 space/time overhead가 생깁니다. 이를 줄이려고 taskstats는 exit하는 각 task statistic을 process-wide data structure에 누적합니다. Process의 마지막 task가 exit하면 누적 process-level data도 per-task data와 함께 userspace로 보냅니다.
사용자가 per-tgid data를 query하면 group의 다른 live thread statistic을 합산하고 같은 thread group에서 이미 exit한 thread의 accumulated total에 더합니다.
Exited thread total과 live thread snapshot을 조합합니다.
Taskstats 확장 방식 선택
134-159Future accounting patch가 더 많은 per-task/process statistic을 export하는 방법은 두 가지입니다. 첫째, 기존 `struct taskstats` 끝에 field를 추가합니다. Structure 내부 version number가 backward compatibility를 보장하고 userspace는 자신이 사용하는 version에 해당하는 field만 사용합니다.
둘째, 별도 statistic structure를 정의하고 netlink attribute interface로 반환합니다. Userspace는 각 attribute를 독립적으로 처리하므로 older interface가 이해하지 못하는 type은 무시할 수 있습니다.
선택은 flexibility와 overhead의 tradeoff입니다. Field가 몇 개뿐이면 새 attribute 처리 overhead가 없는 첫 방법이 낫습니다. 새 field 때문에 기존 struct가 너무 커져 여러 userspace accounting utility가 관심 없는 field까지 큰 structure로 받아야 한다면 attribute structure 확장이 적합합니다.
추가 field 수와 userspace payload overhead로 방법을 선택합니다.
Exit data flow control
160-180Task exit rate가 높으면 listener가 kernel의 per-tid/tgid exit data 송신 속도를 따라잡지 못해 data loss가 날 수 있습니다. Taskstats structure가 커지고 CPU 수가 늘수록 가능성이 커집니다.
Statistic loss를 피하려면 listener netlink socket의 receive buffer를 키우거나 listener 수를 늘리고 listener마다 감시하는 CPU 수를 줄입니다. 극단적으로 CPU마다 listener 하나를 둘 수 있습니다. 특히 CPU 하나만 들을 때는 listener CPU affinity를 대상 CPU subset에 맞추는 것도 고려합니다.
이 조치 뒤에도 receive buffer overflow를 나타내는 `ENOBUFS` error message를 받으면 userspace가 data loss를 처리해야 합니다.
Exit rate가 listener capacity를 넘을 때의 완화 순서입니다.
Query와 exit delivery
taskstats.rst:1-52Per-task/process statistic을 on-demand query하거나 selected CPU의 task exit 때 asynchronous record로 받습니다.