요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
period/runtime 인터페이스
sched-rt-group.rst:80-152sched_rt_period_us는 회계 주기, sched_rt_runtime_us는 그 주기 안에서 RT class가 쓸 수 있는 시간입니다. cgroup RT group scheduling을 사용하는 경우 각 group도 같은 형태의 period/runtime 한계를 가지며 부모-자식 계층 제약을 검증합니다.
runtime을 -1로 설정하면 제한을 사실상 해제할 수 있지만 RT task 오류가 시스템 전체 starvation으로 이어질 수 있습니다. 제품에서는 watchdog만 믿기보다 유한한 budget과 CPU affinity를 함께 설계하는 편이 안전합니다.
task grouping 기준과 향후 확장
sched-rt-group.rst:153-191RT group은 사용자, 컨테이너 또는 서비스 단위의 정책 경계를 만들 수 있습니다. 어떤 기준을 택하더라도 실제 interrupt thread, kernel thread와 복구 서비스가 어느 group과 CPU에서 실행되는지까지 포함해 budget을 산정해야 합니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
==========================
Real-Time group scheduling
==========================
.. CONTENTS
0. WARNING
1. Overview
1.1 The problem
1.2 The solution
2. The interface
2.1 System-wide settings
2.2 Default behaviour
2.3 Basis for grouping tasks
3. Future plans
0. WARNING
==========
Fiddling with these settings can result in an unstable system, the knobs are
root only and assumes root knows what he is doing.
Most notable:
* very small values in sched_rt_period_us can result in an unstable
system when the period is smaller than either the available hrtimer
resolution, or the time it takes to handle the budget refresh itself.
* very small values in sched_rt_runtime_us can result in an unstable
system when the runtime is so small the system has difficulty making
forward progress (NOTE: the migration thread and kstopmachine both
are real-time processes).
1. Overview
===========
1.1 The problem
---------------
Real-time scheduling is all about determinism, a group has to be able to rely on
the amount of bandwidth (eg. CPU time) being constant. In order to schedule
multiple groups of real-time tasks, each group must be assigned a fixed portion
of the CPU time available. Without a minimum guarantee a real-time group can
obviously fall short. A fuzzy upper limit is of no use since it cannot be
relied upon. Which leaves us with just the single fixed portion.
1.2 The solution
----------------
CPU time is divided by means of specifying how much time can be spent running
in a given period. We allocate this "run time" for each real-time group which
the other real-time groups will not be permitted to use.
Any time not allocated to a real-time group will be used to run normal priority
tasks (SCHED_OTHER). Any allocated run time not used will also be picked up by
SCHED_OTHER.
Let's consider an example: a frame fixed real-time renderer must deliver 25
frames a second, which yields a period of 0.04s per frame. Now say it will also
have to play some music and respond to input, leaving it with around 80% CPU
time dedicated for the graphics. We can then give this group a run time of 0.8
* 0.04s = 0.032s.
This way the graphics group will have a 0.04s period with a 0.032s run time
limit. Now if the audio thread needs to refill the DMA buffer every 0.005s, but
needs only about 3% CPU time to do so, it can do with a 0.03 * 0.005s =
0.00015s. So this group can be scheduled with a period of 0.005s and a run time
of 0.00015s.
The remaining CPU time will be used for user input and other tasks. Because
real-time tasks have explicitly allocated the CPU time they need to perform
their tasks, buffer underruns in the graphics or audio can be eliminated.
NOTE: the above example is not fully implemented yet. We still
lack an EDF scheduler to make non-uniform periods usable.
2. The Interface
================
2.1 System wide settings
------------------------
The system wide settings are configured under the /proc virtual file system:
/proc/sys/kernel/sched_rt_period_us:
The scheduling period that is equivalent to 100% CPU bandwidth.
/proc/sys/kernel/sched_rt_runtime_us:
A global limit on how much time real-time scheduling may use. This is always
less or equal to the period_us, as it denotes the time allocated from the
period_us for the real-time tasks. Without CONFIG_RT_GROUP_SCHED enabled,
this only serves for admission control of deadline tasks. With
CONFIG_RT_GROUP_SCHED=y it also signifies the total bandwidth available to
all real-time groups.
* Time is specified in us because the interface is s32. This gives an
operating range from 1us to about 35 minutes.
* sched_rt_period_us takes values from 1 to INT_MAX.
* sched_rt_runtime_us takes values from -1 to sched_rt_period_us.
* A run time of -1 specifies runtime == period, ie. no limit.
* sched_rt_runtime_us/sched_rt_period_us > 0.05 inorder to preserve
bandwidth for fair dl_server. For accurate value check average of
runtime/period in /sys/kernel/debug/sched/fair_server/cpuX/
2.2 Default behaviour
---------------------
The default values for sched_rt_period_us (1000000 or 1s) and
sched_rt_runtime_us (950000 or 0.95s). This gives 0.05s to be used by
SCHED_OTHER (non-RT tasks). These defaults were chosen so that a run-away
real-time tasks will not lock up the machine but leave a little time to recover
it. By setting runtime to -1 you'd get the old behaviour back.
By default all bandwidth is assigned to the root group and new groups get the
period from /proc/sys/kernel/sched_rt_period_us and a run time of 0. If you
want to assign bandwidth to another group, reduce the root group's bandwidth
and assign some or all of the difference to another group.
Real-time group scheduling means you have to assign a portion of total CPU
bandwidth to the group before it will accept real-time tasks. Therefore you will
not be able to run real-time tasks as any user other than root until you have
done that, even if the user has the rights to run processes with real-time
priority!
2.3 Basis for grouping tasks
----------------------------
Enabling CONFIG_RT_GROUP_SCHED lets you explicitly allocate real
CPU bandwidth to task groups.
This uses the cgroup virtual file system and "<cgroup>/cpu.rt_runtime_us"
to control the CPU time reserved for each control group.
For more information on working with control groups, you should read
Documentation/admin-guide/cgroup-v1/cgroups.rst as well.
Group settings are checked against the following limits in order to keep the
configuration schedulable:
\Sum_{i} runtime_{i} / global_period <= global_runtime / global_period
For now, this can be simplified to just the following (but see Future plans):
\Sum_{i} runtime_{i} <= global_runtime
3. Future plans
===============
There is work in progress to make the scheduling period for each group
("<cgroup>/cpu.rt_period_us") configurable as well.
The constraint on the period is that a subgroup must have a smaller or
equal period to its parent. But realistically its not very useful _yet_
as its prone to starvation without deadline scheduling.
Consider two sibling groups A and B; both have 50% bandwidth, but A's
period is twice the length of B's.
* group A: period=100000us, runtime=50000us
- this runs for 0.05s once every 0.1s
* group B: period= 50000us, runtime=25000us
- this runs for 0.025s twice every 0.1s (or once every 0.05 sec).
This means that currently a while (1) loop in A will run for the full period of
B and can starve B's tasks (assuming they are of lower priority) for a whole
period.
The next project will be SCHED_EDF (Earliest Deadline First scheduling) to bring
full deadline scheduling to the linux kernel. Deadline scheduling the above
groups and treating end of the period as a deadline will ensure that they both
get their allocated time.
Implementing SCHED_EDF might take a while to complete. Priority Inheritance is
the biggest challenge as the current linux PI infrastructure is geared towards
the limited static priority levels 0-99. With deadline scheduling you need to
do deadline inheritance (since priority is inversely proportional to the
deadline delta (deadline - now)).
This means the whole PI machinery will have to be reworked - and that is one of
the most complex pieces of code we have.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
RT bandwidth 설정 주의 사항
1-34RT group knob를 잘못 설정하면 system이 불안정해질 수 있다. root만 변경할 수 있으며 period, runtime, timer resolution과 kernel RT thread의 실행 요구를 이해해야 한다.
sched_rt_period_us가 hrtimer resolution보다 작거나 budget refresh handler 자체가 실행되는 시간보다 짧으면 period를 안정적으로 갱신할 수 없다.
sched_rt_runtime_us가 너무 작으면 system이 forward progress를 내기 어렵다. CPU migration thread와 kstopmachine도 real-time process이므로 RT runtime을 거의 없애면 scheduler와 CPU 관리 자체가 정지할 수 있다.
고정 bandwidth reservation
35-79real-time scheduling의 목표는 determinism이다. 여러 RT task group을 함께 실행하려면 각 group이 항상 의존할 수 있는 고정 CPU time fraction을 받아야 한다. 최소 보장 없는 group은 필요한 CPU를 받지 못할 수 있고, 모호한 상한은 timing 분석에 사용할 수 없다.
해결 방법은 period 안에서 group이 실행할 수 있는 runtime을 지정하는 것이다. 한 RT group에 할당한 runtime은 다른 RT group이 사용할 수 없다. 어떤 RT group에도 할당하지 않은 CPU time과 group이 사용하지 않은 runtime은 SCHED_OTHER task가 사용한다.
초당 25 frame을 만드는 renderer는 frame period가 0.04s다. graphics에 CPU 80%를 예약하면 runtime은 0.8*0.04=0.032s가 된다. 따라서 graphics group은 period 40ms마다 최대 32ms를 실행한다.
audio thread가 5ms마다 DMA buffer를 채우고 CPU 3%가 필요하면 period=0.005s, runtime=0.03*0.005=0.00015s, 즉 150us를 예약한다. 남은 CPU는 input과 일반 task가 사용한다.
| group | period | runtime | bandwidth |
|---|---|---|---|
| graphics | 40ms | 32ms | 80% |
| audio | 5ms | 0.15ms | 3% |
| SCHED_OTHER | 고정 reservation 없음 | 미할당·미사용 시간 | 나머지 |
원문은 period가 서로 다른 group을 완전히 활용하려면 EDF가 필요해 예제가 당시 완전 구현된 것은 아니라고 적는다. 이 문구는 뒤의 future plans와 함께 문서의 역사적 배경을 반영한다.
system-wide procfs interface
80-130| 파일 | 의미 |
|---|---|
| /proc/sys/kernel/sched_rt_period_us | CPU bandwidth 100%에 대응하는 global scheduling period |
| /proc/sys/kernel/sched_rt_runtime_us | 각 global period에서 RT scheduling에 허용하는 총 runtime |
sched_rt_runtime_us는 period 이하이며 period에서 RT task에 떼어 준 시간이다. CONFIG_RT_GROUP_SCHED가 없으면 deadline task admission control에만 쓰이고, 설정하면 모든 RT group이 사용할 총 bandwidth도 제한한다.
- interface가 s32 microsecond이므로 약 1us에서 35분까지 표현한다.
- sched_rt_period_us 범위는 1부터 INT_MAX다.
- sched_rt_runtime_us 범위는 -1부터 sched_rt_period_us다.
- runtime=-1은 runtime=period, 즉 RT runtime 제한 없음이다.
- fair dl_server bandwidth를 보존하려면 runtime/period가 0.05보다 커야 하며 정확한 값은 /sys/kernel/debug/sched/fair_server/cpuX/의 평균 ratio를 확인한다.
기본 period는 1,000,000us(1s), runtime은 950,000us(0.95s)다. 각 second의 50ms를 SCHED_OTHER에 남겨 runaway RT task가 machine 전체를 lockup해도 관리·복구 작업이 실행될 기회를 준다. runtime=-1은 예전의 무제한 동작을 복원한다.
초기에는 모든 bandwidth가 root group에 배정되고 새 group은 global period와 runtime 0을 받는다. 다른 group에 bandwidth를 주려면 먼저 root group 할당을 줄이고 그 차이 일부 또는 전부를 자식에 배정한다.
RT priority 실행 권한이 있는 non-root 사용자라도 속한 group에 RT bandwidth가 0이면 real-time task를 실행할 수 없다. group scheduling에서는 permission과 별도로 bandwidth reservation이 필요하다.
cgroup별 RT bandwidth
131-152CONFIG_RT_GROUP_SCHED를 켜면 cgroup v1 CPU controller의 <cgroup>/cpu.rt_runtime_us로 task group마다 실제 RT CPU bandwidth를 배분한다. cgroup 기본 운용은 admin-guide/cgroup-v1/cgroups 문서를 참고한다.
설정을 schedulable하게 유지하려면 모든 자식 group의 bandwidth 합이 global 또는 parent가 가진 bandwidth를 넘지 않아야 한다.
sum_i(runtime_i / global_period) <= global_runtime / global_period
# 현재 같은 global period를 쓰므로
sum_i(runtime_i) <= global_runtime
runtime을 새 group에 추가할 때 root 또는 parent에서 같은 양을 빼지 않으면 admission check가 거부한다. 이 계층 제약은 존재하지 않는 CPU time을 중복 예약하지 못하게 한다.
서로 다른 group period와 EDF 필요성
153-190원문은 <cgroup>/cpu.rt_period_us로 group별 period를 설정하는 작업을 future plan으로 설명한다. 자식 period는 parent period보다 작거나 같아야 하지만, fixed-priority scheduling에서는 서로 다른 period가 starvation을 만들 수 있다.
sibling group A와 B가 모두 50% bandwidth를 갖되 A period가 B의 두 배라고 가정한다. A는 100ms마다 50ms를 한 번 실행하고, B는 50ms마다 25ms씩 100ms 동안 두 번 실행해야 한다.
group A: period=100000us, runtime=50000us
-> 100ms마다 50ms
group B: period=50000us, runtime=25000us
-> 50ms마다 25ms
A의 무한 loop가 B보다 높은 priority라면 A가 연속 50ms를 실행해 B의 period 하나 전체를 굶길 수 있다. 두 group의 평균 bandwidth가 각각 50%라는 사실만으로 각 period 안의 service timing은 보장되지 않는다.
A가 먼저 50ms를 연속 사용하면 B의 첫 50ms deadline window를 모두 점유할 수 있다.
원문은 period 끝을 deadline으로 취급하는 SCHED_EDF와 deadline inheritance가 필요하다고 설명한다. static priority 0-99를 전제로 한 당시 PI infrastructure를 deadline-now에 반비례하는 동적 priority inheritance로 재작업하는 것이 가장 큰 과제로 제시된다.
이 마지막 절은 역사적 계획을 담고 있다. 같은 v6.18 Documentation의 sched-deadline.rst는 현재 SCHED_DEADLINE/CBS/EDF 구현과 interface를 별도로 설명한다.
RT task 독점과 시스템 보호
sched-rt-group.rst:1-79SCHED_FIFO와 SCHED_RR task는 runnable 상태인 동안 일반 task보다 먼저 선택됩니다. 잘못된 RT loop가 CPU를 놓지 않으면 shell, watchdog과 복구 daemon까지 실행되지 않을 수 있으므로 시스템은 RT class가 사용할 수 있는 전체 시간을 제한합니다.
자식 group에 분배한 RT runtime의 합은 부모가 가진 runtime을 넘을 수 없습니다. 일부 시간을 비RT task에 남겨 복구 가능성을 유지합니다.