← Documents Documentation/trace/rv/monitor_rtapp.rst GitHub 원문 ↗

Linux 6.18.37 · Tracing

실시간 애플리케이션 모니터

실시간 애플리케이션의 page fault와 부적절한 sleep 및 wakeup으로 생기는 지연을 pagefault·sleep 하위 monitor가 탐지하는 규칙을 설명합니다.

Source pathDocumentation/trace/rv/monitor_rtapp.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약·해설

monitor_rtapp.rst:1-133

실시간 애플리케이션의 page fault와 부적절한 sleep 및 wakeup으로 생기는 지연을 pagefault·sleep 하위 monitor가 탐지하는 규칙을 설명합니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 Real-time application monitors
2 ==============================
3
4 - Name: rtapp
5 - Type: container for multiple monitors
6 - Author: Nam Cao <[email protected]>
7
8 Description
9 -----------
10
11 Real-time applications may have design flaws such that they experience
12 unexpected latency and fail to meet their time requirements. Often, these flaws
13 follow a few patterns:
14
15 - Page faults: A real-time thread may access memory that does not have a
16 mapped physical backing or must first be copied (such as for copy-on-write).
17 Thus a page fault is raised and the kernel must first perform the expensive
18 action. This causes significant delays to the real-time thread
19 - Priority inversion: A real-time thread blocks waiting for a lower-priority
20 thread. This causes the real-time thread to effectively take on the
21 scheduling priority of the lower-priority thread. For example, the real-time
22 thread needs to access a shared resource that is protected by a
23 non-pi-mutex, but the mutex is currently owned by a non-real-time thread.
24
25 The `rtapp` monitor detects these patterns. It aids developers to identify
26 reasons for unexpected latency with real-time applications. It is a container of
27 multiple sub-monitors described in the following sections.
28
29 Monitor pagefault
30 +++++++++++++++++
31
32 The `pagefault` monitor reports real-time tasks raising page faults. Its
33 specification is::
34
35 RULE = always (RT imply not PAGEFAULT)
36
37 To fix warnings reported by this monitor, `mlockall()` or `mlock()` can be used
38 to ensure physical backing for memory.
39
40 This monitor may have false negatives because the pages used by the real-time
41 threads may just happen to be directly available during testing. To minimize
42 this, the system can be put under memory pressure (e.g. invoking the OOM killer
43 using a program that does `ptr = malloc(SIZE_OF_RAM); memset(ptr, 0,
44 SIZE_OF_RAM);`) so that the kernel executes aggressive strategies to recycle as
45 much physical memory as possible.
46
47 Monitor sleep
48 +++++++++++++
49
50 The `sleep` monitor reports real-time threads sleeping in a manner that may
51 cause undesirable latency. Real-time applications should only put a real-time
52 thread to sleep for one of the following reasons:
53
54 - Cyclic work: real-time thread sleeps waiting for the next cycle. For this
55 case, only the `clock_nanosleep` syscall should be used with `TIMER_ABSTIME`
56 (to avoid time drift) and `CLOCK_MONOTONIC` (to avoid the clock being
57 changed). No other method is safe for real-time. For example, threads
58 waiting for timerfd can be woken by softirq which provides no real-time
59 guarantee.
60 - Real-time thread waiting for something to happen (e.g. another thread
61 releasing shared resources, or a completion signal from another thread). In
62 this case, only futexes (FUTEX_LOCK_PI, FUTEX_LOCK_PI2 or one of
63 FUTEX_WAIT_*) should be used. Applications usually do not use futexes
64 directly, but use PI mutexes and PI condition variables which are built on
65 top of futexes. Be aware that the C library might not implement conditional
66 variables as safe for real-time. As an alternative, the librtpi library
67 exists to provide a conditional variable implementation that is correct for
68 real-time applications in Linux.
69
70 Beside the reason for sleeping, the eventual waker should also be
71 real-time-safe. Namely, one of:
72
73 - An equal-or-higher-priority thread
74 - Hard interrupt handler
75 - Non-maskable interrupt handler
76
77 This monitor's warning usually means one of the following:
78
79 - Real-time thread is blocked by a non-real-time thread (e.g. due to
80 contention on a mutex without priority inheritance). This is priority
81 inversion.
82 - Time-critical work waits for something which is not safe for real-time (e.g.
83 timerfd).
84 - The work executed by the real-time thread does not need to run at real-time
85 priority at all. This is not a problem for the real-time thread itself, but
86 it is potentially taking the CPU away from other important real-time work.
87
88 Application developers may purposely choose to have their real-time application
89 sleep in a way that is not safe for real-time. It is debatable whether that is a
90 problem. Application developers must analyze the warnings to make a proper
91 assessment.
92
93 The monitor's specification is::
94
95 RULE = always ((RT and SLEEP) imply (RT_FRIENDLY_SLEEP or ALLOWLIST))
96
97 RT_FRIENDLY_SLEEP = (RT_VALID_SLEEP_REASON or KERNEL_THREAD)
98 and ((not WAKE) until RT_FRIENDLY_WAKE)
99
100 RT_VALID_SLEEP_REASON = FUTEX_WAIT
101 or RT_FRIENDLY_NANOSLEEP
102
103 RT_FRIENDLY_NANOSLEEP = CLOCK_NANOSLEEP
104 and NANOSLEEP_TIMER_ABSTIME
105 and NANOSLEEP_CLOCK_MONOTONIC
106
107 RT_FRIENDLY_WAKE = WOKEN_BY_EQUAL_OR_HIGHER_PRIO
108 or WOKEN_BY_HARDIRQ
109 or WOKEN_BY_NMI
110 or KTHREAD_SHOULD_STOP
111
112 ALLOWLIST = BLOCK_ON_RT_MUTEX
113 or FUTEX_LOCK_PI
114 or TASK_IS_RCU
115 or TASK_IS_MIGRATION
116
117 Beside the scenarios described above, this specification also handle some
118 special cases:
119
120 - `KERNEL_THREAD`: kernel tasks do not have any pattern that can be recognized
121 as valid real-time sleeping reasons. Therefore sleeping reason is not
122 checked for kernel tasks.
123 - `KTHREAD_SHOULD_STOP`: a non-real-time thread may stop a real-time kernel
124 thread by waking it and waiting for it to exit (`kthread_stop()`). This
125 wakeup is safe for real-time.
126 - `ALLOWLIST`: to handle known false positives with the kernel.
127 - `BLOCK_ON_RT_MUTEX` is included in the allowlist due to its implementation.
128 In the release path of rt_mutex, a boosted task is de-boosted before waking
129 the rt_mutex's waiter. Consequently, the monitor may see a real-time-unsafe
130 wakeup (e.g. non-real-time task waking real-time task). This is actually
131 real-time-safe because preemption is disabled for the duration.
132 - `FUTEX_LOCK_PI` is included in the allowlist for the same reason as
133 `BLOCK_ON_RT_MUTEX`.
134

3. 한국어 전문 번역

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

설명

1-28

`rtapp`은 Nam Cao가 작성한 여러 monitor의 컨테이너이다. 실시간 애플리케이션의 설계 결함 때문에 예기치 않은 지연이 발생하고 시간 요구 사항을 지키지 못하는 흔한 패턴을 탐지한다.

페이지 폴트는 실시간 thread가 물리 메모리에 아직 매핑되지 않았거나 copy-on-write 때문에 먼저 복사해야 하는 메모리에 접근할 때 발생한다. 커널이 비용이 큰 처리를 먼저 수행하므로 실시간 thread가 크게 지연된다.

우선순위 역전은 실시간 thread가 더 낮은 우선순위의 thread를 기다리며 차단될 때 생긴다. 예를 들어 공유 자원을 보호하는 non-PI mutex를 비실시간 thread가 소유하고 있으면 실시간 thread는 사실상 그 낮은 thread의 scheduling 우선순위로 실행되는 것과 같은 영향을 받는다.

`rtapp` monitor는 이런 패턴을 탐지해 개발자가 실시간 애플리케이션의 예상 밖 지연 원인을 찾도록 돕는다. 아래에서 설명하는 여러 하위 monitor를 묶는다.

rtapp이 겨냥하는 지연 패턴
패턴원인영향
Page fault물리 backing 부재 또는 copy-on-write비용이 큰 fault 처리 동안 지연
Priority inversion낮은 우선순위 thread 또는 non-PI mutex 대기실시간 작업의 유효 우선순위 저하

실시간 thread의 지연을 메모리 준비와 scheduling 의존성으로 나누어 보여준다.

Real-time application monitors
==============================

- Name: rtapp
- Type: container for multiple monitors
- Author: Nam Cao <[email protected]>

Description
-----------

Real-time applications may have design flaws such that they experience
unexpected latency and fail to meet their time requirements. Often, these flaws
follow a few patterns:

  - Page faults: A real-time thread may access memory that does not have a
    mapped physical backing or must first be copied (such as for copy-on-write).
    Thus a page fault is raised and the kernel must first perform the expensive
    action. This causes significant delays to the real-time thread
  - Priority inversion: A real-time thread blocks waiting for a lower-priority
    thread. This causes the real-time thread to effectively take on the
    scheduling priority of the lower-priority thread. For example, the real-time
    thread needs to access a shared resource that is protected by a
    non-pi-mutex, but the mutex is currently owned by a non-real-time thread.

The `rtapp` monitor detects these patterns. It aids developers to identify
reasons for unexpected latency with real-time applications. It is a container of
multiple sub-monitors described in the following sections.

pagefault monitor

29-46

`pagefault` monitor는 실시간 task가 page fault를 발생시키면 보고한다. 명세는 다음과 같다.

RULE = always (RT imply not PAGEFAULT)

보고된 경고를 해결하려면 `mlockall()` 또는 `mlock()`으로 메모리의 물리 backing을 미리 보장할 수 있다.

시험 중 실시간 thread가 쓰는 page가 우연히 즉시 사용 가능하면 이 monitor에 false negative가 생길 수 있다. 이를 줄이려면 `ptr = malloc(SIZE_OF_RAM); memset(ptr, 0, SIZE_OF_RAM);` 같은 프로그램으로 OOM killer를 유발하는 등 시스템에 메모리 압박을 가해, 커널이 물리 메모리를 최대한 회수하는 공격적인 전략을 실행하게 할 수 있다.

pagefault 경고 대응
RT task memory accessPAGEFAULT 발생 여부 검사
monitor warningmlockall() 또는 mlock() 적용
false negative 완화시험 환경에 memory pressure 부여

실시간 task의 page fault를 관찰하고 물리 backing을 사전에 고정한다.

Monitor pagefault
+++++++++++++++++

The `pagefault` monitor reports real-time tasks raising page faults. Its
specification is::

  RULE = always (RT imply not PAGEFAULT)

To fix warnings reported by this monitor, `mlockall()` or `mlock()` can be used
to ensure physical backing for memory.

This monitor may have false negatives because the pages used by the real-time
threads may just happen to be directly available during testing.  To minimize
this, the system can be put under memory pressure (e.g.  invoking the OOM killer
using a program that does `ptr = malloc(SIZE_OF_RAM); memset(ptr, 0,
SIZE_OF_RAM);`) so that the kernel executes aggressive strategies to recycle as
much physical memory as possible.

sleep monitor의 판단 기준

47-92

`sleep` monitor는 바람직하지 않은 지연을 일으킬 수 있는 방식으로 실시간 thread가 잠들 때 보고한다. 실시간 애플리케이션은 주기 작업을 기다리거나 특정 사건을 기다리는 두 부류의 이유로만 실시간 thread를 재워야 한다.

주기 작업에서는 시간 drift를 피하도록 `TIMER_ABSTIME`, 시계 변경 영향을 피하도록 `CLOCK_MONOTONIC`을 지정한 `clock_nanosleep` syscall만 사용해야 한다. timerfd를 기다리는 thread는 실시간 보장이 없는 softirq에 의해 깨어날 수 있으므로 안전하지 않다.

공유 자원의 해제나 다른 thread의 완료 신호를 기다릴 때는 `FUTEX_LOCK_PI`, `FUTEX_LOCK_PI2`, 또는 `FUTEX_WAIT_*` 중 하나인 futex만 사용해야 한다. 애플리케이션은 보통 futex를 직접 쓰지 않고 그 위에 구현된 PI mutex와 PI condition variable을 쓴다.

C library의 condition variable이 실시간 안전성을 보장하지 않을 수 있음에 유의해야 한다. 대안인 `librtpi`는 Linux 실시간 애플리케이션에 올바른 condition variable 구현을 제공한다.

잠드는 이유뿐 아니라 최종적으로 깨우는 주체도 실시간에 안전해야 한다. 허용되는 주체는 같거나 더 높은 우선순위의 thread, hard interrupt handler, non-maskable interrupt handler이다.

경고는 보통 non-PI mutex 경합 같은 우선순위 역전, timerfd처럼 실시간에 안전하지 않은 사건의 대기, 또는 해당 작업 자체에 실시간 우선순위가 필요하지 않음을 뜻한다. 마지막 경우 그 thread 자체의 문제는 아니지만 다른 중요한 실시간 작업의 CPU 시간을 빼앗을 수 있다.

개발자가 의도적으로 실시간에 안전하지 않은 sleep 방식을 선택할 수도 있으므로 경고 자체만으로 결함을 확정할 수 없다. 애플리케이션 개발자가 각 경고를 분석해 적절히 판단해야 한다.

실시간에 안전한 sleep 조건
구분허용 조건
주기 작업`clock_nanosleep` + `TIMER_ABSTIME` + `CLOCK_MONOTONIC`
사건 대기`FUTEX_LOCK_PI`, `FUTEX_LOCK_PI2`, `FUTEX_WAIT_*`
wake 주체동일 이상 우선순위 thread, hard IRQ, NMI

sleep 이유와 wake 주체를 모두 검사해야 한다.

Monitor sleep
+++++++++++++

The `sleep` monitor reports real-time threads sleeping in a manner that may
cause undesirable latency. Real-time applications should only put a real-time
thread to sleep for one of the following reasons:

  - Cyclic work: real-time thread sleeps waiting for the next cycle. For this
    case, only the `clock_nanosleep` syscall should be used with `TIMER_ABSTIME`
    (to avoid time drift) and `CLOCK_MONOTONIC` (to avoid the clock being
    changed). No other method is safe for real-time. For example, threads
    waiting for timerfd can be woken by softirq which provides no real-time
    guarantee.
  - Real-time thread waiting for something to happen (e.g. another thread
    releasing shared resources, or a completion signal from another thread). In
    this case, only futexes (FUTEX_LOCK_PI, FUTEX_LOCK_PI2 or one of
    FUTEX_WAIT_*) should be used.  Applications usually do not use futexes
    directly, but use PI mutexes and PI condition variables which are built on
    top of futexes. Be aware that the C library might not implement conditional
    variables as safe for real-time. As an alternative, the librtpi library
    exists to provide a conditional variable implementation that is correct for
    real-time applications in Linux.

Beside the reason for sleeping, the eventual waker should also be
real-time-safe. Namely, one of:

  - An equal-or-higher-priority thread
  - Hard interrupt handler
  - Non-maskable interrupt handler

This monitor's warning usually means one of the following:

  - Real-time thread is blocked by a non-real-time thread (e.g. due to
    contention on a mutex without priority inheritance). This is priority
    inversion.
  - Time-critical work waits for something which is not safe for real-time (e.g.
    timerfd).
  - The work executed by the real-time thread does not need to run at real-time
    priority at all.  This is not a problem for the real-time thread itself, but
    it is potentially taking the CPU away from other important real-time work.

Application developers may purposely choose to have their real-time application
sleep in a way that is not safe for real-time. It is debatable whether that is a
problem. Application developers must analyze the warnings to make a proper
assessment.

sleep monitor 명세

93-116

최상위 규칙은 실시간 task가 잠들 때 `RT_FRIENDLY_SLEEP` 또는 `ALLOWLIST` 조건을 충족하도록 요구한다.

  RULE = always ((RT and SLEEP) imply (RT_FRIENDLY_SLEEP or ALLOWLIST))

  RT_FRIENDLY_SLEEP = (RT_VALID_SLEEP_REASON or KERNEL_THREAD)
                  and ((not WAKE) until RT_FRIENDLY_WAKE)

  RT_VALID_SLEEP_REASON = FUTEX_WAIT
                       or RT_FRIENDLY_NANOSLEEP

  RT_FRIENDLY_NANOSLEEP = CLOCK_NANOSLEEP
                      and NANOSLEEP_TIMER_ABSTIME
                      and NANOSLEEP_CLOCK_MONOTONIC

  RT_FRIENDLY_WAKE = WOKEN_BY_EQUAL_OR_HIGHER_PRIO
                  or WOKEN_BY_HARDIRQ
                  or WOKEN_BY_NMI
                  or KTHREAD_SHOULD_STOP

  ALLOWLIST = BLOCK_ON_RT_MUTEX
           or FUTEX_LOCK_PI
           or TASK_IS_RCU
           or TASK_IS_MIGRATION

`RT_FRIENDLY_SLEEP`은 유효한 sleep 이유 또는 kernel thread라는 조건과, `RT_FRIENDLY_WAKE`가 발생할 때까지 `WAKE`가 발생하지 않는다는 시간 조건을 결합한다.

유효한 sleep 이유는 futex wait 또는 안전한 `CLOCK_NANOSLEEP`이며, 안전한 nanosleep은 `NANOSLEEP_TIMER_ABSTIME`과 `NANOSLEEP_CLOCK_MONOTONIC`을 모두 요구한다.

안전한 wake는 동일 이상 우선순위, hard IRQ, NMI, 또는 `KTHREAD_SHOULD_STOP`이다. 알려진 예외는 `BLOCK_ON_RT_MUTEX`, `FUTEX_LOCK_PI`, `TASK_IS_RCU`, `TASK_IS_MIGRATION`으로 허용 목록에 둔다.

RT_FRIENDLY_SLEEP 판정
RT and SLEEP유효 sleep 이유 또는 KERNEL_THREAD 검사
not WAKE until RT_FRIENDLY_WAKE안전한 깨움까지 시간 조건 검사
ALLOWLIST알려진 커널 예외 수용
조건 불충족monitor warning

sleep 원인과 미래의 wake 주체를 LTL 하위 표현식으로 조합한다.

The monitor's specification is::

  RULE = always ((RT and SLEEP) imply (RT_FRIENDLY_SLEEP or ALLOWLIST))

  RT_FRIENDLY_SLEEP = (RT_VALID_SLEEP_REASON or KERNEL_THREAD)
                  and ((not WAKE) until RT_FRIENDLY_WAKE)

  RT_VALID_SLEEP_REASON = FUTEX_WAIT
                       or RT_FRIENDLY_NANOSLEEP

  RT_FRIENDLY_NANOSLEEP = CLOCK_NANOSLEEP
                      and NANOSLEEP_TIMER_ABSTIME
                      and NANOSLEEP_CLOCK_MONOTONIC

  RT_FRIENDLY_WAKE = WOKEN_BY_EQUAL_OR_HIGHER_PRIO
                  or WOKEN_BY_HARDIRQ
                  or WOKEN_BY_NMI
                  or KTHREAD_SHOULD_STOP

  ALLOWLIST = BLOCK_ON_RT_MUTEX
           or FUTEX_LOCK_PI
           or TASK_IS_RCU
           or TASK_IS_MIGRATION

특수 사례

117-133

`KERNEL_THREAD`는 유효한 실시간 sleep 이유로 식별할 수 있는 공통 패턴이 없으므로 sleep 이유를 검사하지 않는다.

`KTHREAD_SHOULD_STOP`은 비실시간 thread가 실시간 kernel thread를 깨우고 종료를 기다리는 `kthread_stop()` 경로이다. 이 wakeup은 실시간에 안전하다.

`ALLOWLIST`는 커널에서 알려진 false positive를 처리한다. `BLOCK_ON_RT_MUTEX`는 rt_mutex 해제 경로가 waiter를 깨우기 전에 boosted task의 boost를 해제하므로 허용한다. monitor에는 비실시간 task가 실시간 task를 깨우는 것처럼 보일 수 있지만, 그 구간에는 preemption이 비활성화되어 실제로는 안전하다.

`FUTEX_LOCK_PI`도 `BLOCK_ON_RT_MUTEX`와 같은 구현상의 이유로 허용 목록에 포함한다.

Beside the scenarios described above, this specification also handle some
special cases:

  - `KERNEL_THREAD`: kernel tasks do not have any pattern that can be recognized
    as valid real-time sleeping reasons. Therefore sleeping reason is not
    checked for kernel tasks.
  - `KTHREAD_SHOULD_STOP`: a non-real-time thread may stop a real-time kernel
    thread by waking it and waiting for it to exit (`kthread_stop()`). This
    wakeup is safe for real-time.
  - `ALLOWLIST`: to handle known false positives with the kernel.
  - `BLOCK_ON_RT_MUTEX` is included in the allowlist due to its implementation.
    In the release path of rt_mutex, a boosted task is de-boosted before waking
    the rt_mutex's waiter. Consequently, the monitor may see a real-time-unsafe
    wakeup (e.g. non-real-time task waking real-time task). This is actually
    real-time-safe because preemption is disabled for the duration.
  - `FUTEX_LOCK_PI` is included in the allowlist for the same reason as
    `BLOCK_ON_RT_MUTEX`.