요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
Periodic와 idle dynticks
no_hz.rst:33-103Periodic mode는 모든 CPU에 HZ 주기의 scheduling-clock interrupt를 보냅니다. 단순하지만 idle CPU를 불필요하게 깨워 power state를 방해합니다. NO_HZ_IDLE은 idle 진입 시 다음 timer deadline까지 tick을 멈추고 exit 때 elapsed tick accounting을 보정합니다.
Idle dynticks는 일반 workload의 기본 선택이지만 tick stop과 restart 계산 비용이 있습니다. 매우 짧게 idle을 반복하는 workload에서는 절감보다 overhead가 클 수 있어 boot parameter와 trace로 비교합니다.
Adaptive ticks와 housekeeping CPU
no_hz.rst:104-176NO_HZ_FULL은 지정 CPU에 runnable task가 하나뿐일 때 scheduler tick을 대부분 멈춰 application jitter를 줄입니다. 최소 한 CPU는 periodic timekeeping과 kernel housekeeping을 담당해야 하며 모든 CPU를 adaptive tick 대상으로 둘 수 없습니다.
nohz_full= CPU list, isolcpus와 IRQ affinity만 설정한다고 완전한 isolation이 되지는 않습니다. Workqueue, timer, unbound kthread, perf event와 device interrupt를 housekeeping CPU로 옮기고 target CPU에서 둘 이상의 runnable task가 생기지 않게 해야 합니다.
RCU quiescent state와 callback offload
no_hz.rst:177-198RCU는 tick을 이용해 CPU 상태를 관찰해 왔으므로 full dynticks CPU가 user mode에서 오래 실행될 때 quiescent state 추적이 정확해야 합니다. rcu_nocbs로 callback processing을 housekeeping CPU에 offload하면 isolated CPU의 jitter를 더 줄일 수 있습니다.
Tick이 실제로 멈췄는지 검증
no_hz.rst:199-222- Kernel config와 boot command line에서 대상 CPU list를 확인한다.
- trace_irqsoff, timer, sched와 power tracepoint로 periodic interrupt를 관찰한다.
- IRQ affinity, workqueue cpumask와 kernel thread placement를 확인한다.
- Application p99와 maximum latency를 periodic mode와 비교한다.
알려진 제한과 trade-off
no_hz.rst:223-318POSIX CPU timer, perf sampling, scheduler load balancing과 여러 runnable task는 tick을 다시 필요하게 만들 수 있습니다. Full dynticks는 throughput을 자동으로 높이는 기능이 아니라 kernel activity를 다른 CPU와 시점으로 옮기는 isolation 기법입니다.
Housekeeping CPU 수가 너무 적으면 offload된 work와 interrupt가 그곳에 몰려 전체 성능이 떨어집니다. Target latency와 시스템 처리량을 함께 측정하여 CPU partition을 정합니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
======================================
NO_HZ: Reducing Scheduling-Clock Ticks
======================================
This document describes Kconfig options and boot parameters that can
reduce the number of scheduling-clock interrupts, thereby improving energy
efficiency and reducing OS jitter. Reducing OS jitter is important for
some types of computationally intensive high-performance computing (HPC)
applications and for real-time applications.
There are three main ways of managing scheduling-clock interrupts
(also known as "scheduling-clock ticks" or simply "ticks"):
1. Never omit scheduling-clock ticks (CONFIG_HZ_PERIODIC=y or
CONFIG_NO_HZ=n for older kernels). You normally will -not-
want to choose this option.
2. Omit scheduling-clock ticks on idle CPUs (CONFIG_NO_HZ_IDLE=y or
CONFIG_NO_HZ=y for older kernels). This is the most common
approach, and should be the default.
3. Omit scheduling-clock ticks on CPUs that are either idle or that
have only one runnable task (CONFIG_NO_HZ_FULL=y). Unless you
are running realtime applications or certain types of HPC
workloads, you will normally -not- want this option.
These three cases are described in the following three sections, followed
by a third section on RCU-specific considerations, a fourth section
discussing testing, and a fifth and final section listing known issues.
Never Omit Scheduling-Clock Ticks
=================================
Very old versions of Linux from the 1990s and the very early 2000s
are incapable of omitting scheduling-clock ticks. It turns out that
there are some situations where this old-school approach is still the
right approach, for example, in heavy workloads with lots of tasks
that use short bursts of CPU, where there are very frequent idle
periods, but where these idle periods are also quite short (tens or
hundreds of microseconds). For these types of workloads, scheduling
clock interrupts will normally be delivered any way because there
will frequently be multiple runnable tasks per CPU. In these cases,
attempting to turn off the scheduling clock interrupt will have no effect
other than increasing the overhead of switching to and from idle and
transitioning between user and kernel execution.
This mode of operation can be selected using CONFIG_HZ_PERIODIC=y (or
CONFIG_NO_HZ=n for older kernels).
However, if you are instead running a light workload with long idle
periods, failing to omit scheduling-clock interrupts will result in
excessive power consumption. This is especially bad on battery-powered
devices, where it results in extremely short battery lifetimes. If you
are running light workloads, you should therefore read the following
section.
In addition, if you are running either a real-time workload or an HPC
workload with short iterations, the scheduling-clock interrupts can
degrade your applications performance. If this describes your workload,
you should read the following two sections.
Omit Scheduling-Clock Ticks For Idle CPUs
=========================================
If a CPU is idle, there is little point in sending it a scheduling-clock
interrupt. After all, the primary purpose of a scheduling-clock interrupt
is to force a busy CPU to shift its attention among multiple duties,
and an idle CPU has no duties to shift its attention among.
An idle CPU that is not receiving scheduling-clock interrupts is said to
be "dyntick-idle", "in dyntick-idle mode", "in nohz mode", or "running
tickless". The remainder of this document will use "dyntick-idle mode".
The CONFIG_NO_HZ_IDLE=y Kconfig option causes the kernel to avoid sending
scheduling-clock interrupts to idle CPUs, which is critically important
both to battery-powered devices and to highly virtualized mainframes.
A battery-powered device running a CONFIG_HZ_PERIODIC=y kernel would
drain its battery very quickly, easily 2-3 times as fast as would the
same device running a CONFIG_NO_HZ_IDLE=y kernel. A mainframe running
1,500 OS instances might find that half of its CPU time was consumed by
unnecessary scheduling-clock interrupts. In these situations, there
is strong motivation to avoid sending scheduling-clock interrupts to
idle CPUs. That said, dyntick-idle mode is not free:
1. It increases the number of instructions executed on the path
to and from the idle loop.
2. On many architectures, dyntick-idle mode also increases the
number of expensive clock-reprogramming operations.
Therefore, systems with aggressive real-time response constraints often
run CONFIG_HZ_PERIODIC=y kernels (or CONFIG_NO_HZ=n for older kernels)
in order to avoid degrading from-idle transition latencies.
There is also a boot parameter "nohz=" that can be used to disable
dyntick-idle mode in CONFIG_NO_HZ_IDLE=y kernels by specifying "nohz=off".
By default, CONFIG_NO_HZ_IDLE=y kernels boot with "nohz=on", enabling
dyntick-idle mode.
Omit Scheduling-Clock Ticks For CPUs With Only One Runnable Task
================================================================
If a CPU has only one runnable task, there is little point in sending it
a scheduling-clock interrupt because there is no other task to switch to.
Note that omitting scheduling-clock ticks for CPUs with only one runnable
task implies also omitting them for idle CPUs.
The CONFIG_NO_HZ_FULL=y Kconfig option causes the kernel to avoid
sending scheduling-clock interrupts to CPUs with a single runnable task,
and such CPUs are said to be "adaptive-ticks CPUs". This is important
for applications with aggressive real-time response constraints because
it allows them to improve their worst-case response times by the maximum
duration of a scheduling-clock interrupt. It is also important for
computationally intensive short-iteration workloads: If any CPU is
delayed during a given iteration, all the other CPUs will be forced to
wait idle while the delayed CPU finishes. Thus, the delay is multiplied
by one less than the number of CPUs. In these situations, there is
again strong motivation to avoid sending scheduling-clock interrupts.
By default, no CPU will be an adaptive-ticks CPU. The "nohz_full="
boot parameter specifies the adaptive-ticks CPUs. For example,
"nohz_full=1,6-8" says that CPUs 1, 6, 7, and 8 are to be adaptive-ticks
CPUs. Note that you are prohibited from marking all of the CPUs as
adaptive-tick CPUs: At least one non-adaptive-tick CPU must remain
online to handle timekeeping tasks in order to ensure that system
calls like gettimeofday() returns accurate values on adaptive-tick CPUs.
(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no running
user processes to observe slight drifts in clock rate.) Note that this
means that your system must have at least two CPUs in order for
CONFIG_NO_HZ_FULL=y to do anything for you.
Finally, adaptive-ticks CPUs must have their RCU callbacks offloaded.
This is covered in the "RCU IMPLICATIONS" section below.
Normally, a CPU remains in adaptive-ticks mode as long as possible.
In particular, transitioning to kernel mode does not automatically change
the mode. Instead, the CPU will exit adaptive-ticks mode only if needed,
for example, if that CPU enqueues an RCU callback.
Just as with dyntick-idle mode, the benefits of adaptive-tick mode do
not come for free:
1. CONFIG_NO_HZ_FULL selects CONFIG_NO_HZ_COMMON, so you cannot run
adaptive ticks without also running dyntick idle. This dependency
extends down into the implementation, so that all of the costs
of CONFIG_NO_HZ_IDLE are also incurred by CONFIG_NO_HZ_FULL.
2. The user/kernel transitions are slightly more expensive due
to the need to inform kernel subsystems (such as RCU) about
the change in mode.
3. POSIX CPU timers prevent CPUs from entering adaptive-tick mode.
Real-time applications needing to take actions based on CPU time
consumption need to use other means of doing so.
4. If there are more perf events pending than the hardware can
accommodate, they are normally round-robined so as to collect
all of them over time. Adaptive-tick mode may prevent this
round-robining from happening. This will likely be fixed by
preventing CPUs with large numbers of perf events pending from
entering adaptive-tick mode.
5. Scheduler statistics for adaptive-tick CPUs may be computed
slightly differently than those for non-adaptive-tick CPUs.
This might in turn perturb load-balancing of real-time tasks.
Although improvements are expected over time, adaptive ticks is quite
useful for many types of real-time and compute-intensive applications.
However, the drawbacks listed above mean that adaptive ticks should not
(yet) be enabled by default.
RCU Implications
================
There are situations in which idle CPUs cannot be permitted to
enter either dyntick-idle mode or adaptive-tick mode, the most
common being when that CPU has RCU callbacks pending.
Avoid this by offloading RCU callback processing to "rcuo" kthreads
using the CONFIG_RCU_NOCB_CPU=y Kconfig option. The specific CPUs to
offload may be selected using The "rcu_nocbs=" kernel boot parameter,
which takes a comma-separated list of CPUs and CPU ranges, for example,
"1,3-5" selects CPUs 1, 3, 4, and 5. Note that CPUs specified by
the "nohz_full" kernel boot parameter are also offloaded.
The offloaded CPUs will never queue RCU callbacks, and therefore RCU
never prevents offloaded CPUs from entering either dyntick-idle mode
or adaptive-tick mode. That said, note that it is up to userspace to
pin the "rcuo" kthreads to specific CPUs if desired. Otherwise, the
scheduler will decide where to run them, which might or might not be
where you want them to run.
Testing
=======
So you enable all the OS-jitter features described in this document,
but do not see any change in your workload's behavior. Is this because
your workload isn't affected that much by OS jitter, or is it because
something else is in the way? This section helps answer this question
by providing a simple OS-jitter test suite, which is available on branch
master of the following git archive:
git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git
Clone this archive and follow the instructions in the README file.
This test procedure will produce a trace that will allow you to evaluate
whether or not you have succeeded in removing OS jitter from your system.
If this trace shows that you have removed OS jitter as much as is
possible, then you can conclude that your workload is not all that
sensitive to OS jitter.
Note: this test requires that your system have at least two CPUs.
We do not currently have a good way to remove OS jitter from single-CPU
systems.
Known Issues
============
* Dyntick-idle slows transitions to and from idle slightly.
In practice, this has not been a problem except for the most
aggressive real-time workloads, which have the option of disabling
dyntick-idle mode, an option that most of them take. However,
some workloads will no doubt want to use adaptive ticks to
eliminate scheduling-clock interrupt latencies. Here are some
options for these workloads:
a. Use PMQOS from userspace to inform the kernel of your
latency requirements (preferred).
b. On x86 systems, use the "idle=mwait" boot parameter.
c. On x86 systems, use the "intel_idle.max_cstate=" to limit
` the maximum C-state depth.
d. On x86 systems, use the "idle=poll" boot parameter.
However, please note that use of this parameter can cause
your CPU to overheat, which may cause thermal throttling
to degrade your latencies -- and that this degradation can
be even worse than that of dyntick-idle. Furthermore,
this parameter effectively disables Turbo Mode on Intel
CPUs, which can significantly reduce maximum performance.
* Adaptive-ticks slows user/kernel transitions slightly.
This is not expected to be a problem for computationally intensive
workloads, which have few such transitions. Careful benchmarking
will be required to determine whether or not other workloads
are significantly affected by this effect.
* Adaptive-ticks does not do anything unless there is only one
runnable task for a given CPU, even though there are a number
of other situations where the scheduling-clock tick is not
needed. To give but one example, consider a CPU that has one
runnable high-priority SCHED_FIFO task and an arbitrary number
of low-priority SCHED_OTHER tasks. In this case, the CPU is
required to run the SCHED_FIFO task until it either blocks or
some other higher-priority task awakens on (or is assigned to)
this CPU, so there is no point in sending a scheduling-clock
interrupt to this CPU. However, the current implementation
nevertheless sends scheduling-clock interrupts to CPUs having a
single runnable SCHED_FIFO task and multiple runnable SCHED_OTHER
tasks, even though these interrupts are unnecessary.
And even when there are multiple runnable tasks on a given CPU,
there is little point in interrupting that CPU until the current
running task's timeslice expires, which is almost always way
longer than the time of the next scheduling-clock interrupt.
Better handling of these sorts of situations is future work.
* A reboot is required to reconfigure both adaptive idle and RCU
callback offloading. Runtime reconfiguration could be provided
if needed, however, due to the complexity of reconfiguring RCU at
runtime, there would need to be an earthshakingly good reason.
Especially given that you have the straightforward option of
simply offloading RCU callbacks from all CPUs and pinning them
where you want them whenever you want them pinned.
* Additional configuration is required to deal with other sources
of OS jitter, including interrupts and system-utility tasks
and processes. This configuration normally involves binding
interrupts and tasks to particular CPUs.
* Some sources of OS jitter can currently be eliminated only by
constraining the workload. For example, the only way to eliminate
OS jitter due to global TLB shootdowns is to avoid the unmapping
operations (such as kernel module unload operations) that
result in these shootdowns. For another example, page faults
and TLB misses can be reduced (and in some cases eliminated) by
using huge pages and by constraining the amount of memory used
by the application. Pre-faulting the working set can also be
helpful, especially when combined with the mlock() and mlockall()
system calls.
* Unless all CPUs are idle, at least one CPU must keep the
scheduling-clock interrupt going in order to support accurate
timekeeping.
* If there might potentially be some adaptive-ticks CPUs, there
will be at least one CPU keeping the scheduling-clock interrupt
going, even if all CPUs are otherwise idle.
Better handling of this situation is ongoing work.
* Some process-handling operations still require the occasional
scheduling-clock tick. These operations include calculating CPU
load, maintaining sched average, computing CFS entity vruntime,
computing avenrun, and carrying out load balancing. They are
currently accommodated by scheduling-clock tick every second
or so. On-going work will eliminate the need even for these
infrequent scheduling-clock ticks.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Scheduling-clock tick을 줄이는 세 방식
1-30이 문서는 scheduling-clock interrupt 수를 줄이는 Kconfig option과 boot parameter를 설명한다. Tick 수를 줄이면 energy efficiency를 높이고 OS jitter를 낮출 수 있다. OS jitter 감소는 계산량이 큰 일부 HPC application과 real-time application에서 중요하다.
Scheduling-clock interrupt는 scheduling-clock tick 또는 간단히 tick이라고도 한다. 이를 관리하는 주된 방식은 세 가지다.
| 방식 | 설정 | 용도 |
|---|---|---|
| Tick을 전혀 생략하지 않음 | CONFIG_HZ_PERIODIC=y, 오래된 kernel은 CONFIG_NO_HZ=n | 일반적으로 선택하지 않는다. |
| Idle CPU의 tick 생략 | CONFIG_NO_HZ_IDLE=y, 오래된 kernel은 CONFIG_NO_HZ=y | 가장 일반적인 방식이며 기본 선택이 되어야 한다. |
| Idle이거나 runnable task가 하나뿐인 CPU의 tick 생략 | CONFIG_NO_HZ_FULL=y | Real-time application 또는 특정 HPC workload가 아니라면 일반적으로 선택하지 않는다. |
뒤의 절은 이 세 경우와 RCU에 미치는 영향, 시험 방법, 알려진 문제를 차례로 설명한다.
Scheduling-clock tick을 항상 유지하는 mode
33-621990년대와 2000년대 초의 매우 오래된 Linux는 scheduling-clock tick을 생략할 수 없었다. 그러나 짧은 CPU burst를 쓰는 task가 많고 idle period가 매우 자주 나타나지만 각각 수십 또는 수백 microsecond로 짧은 무거운 workload에서는 이 방식이 여전히 적합할 수 있다.
이런 workload에서는 CPU마다 runnable task가 여러 개일 때가 많아 scheduling-clock interrupt가 어차피 전달된다. Interrupt를 끄려는 시도는 효과 없이 idle 진입·이탈과 user/kernel 전환 overhead만 늘릴 수 있다. 이 mode는 CONFIG_HZ_PERIODIC=y, 오래된 kernel에서는 CONFIG_NO_HZ=n으로 선택한다.
반대로 긴 idle period가 있는 가벼운 workload에서는 tick을 생략하지 않으면 전력을 지나치게 소비한다. Battery device에서는 battery lifetime이 매우 짧아진다. 또한 짧은 iteration을 수행하는 real-time 또는 HPC workload에서는 scheduling-clock interrupt가 application 성능을 낮출 수 있다. 이런 경우 뒤의 두 mode를 검토해야 한다.
Idle CPU에서 tick 생략: CONFIG_NO_HZ_IDLE
65-101Idle CPU에는 scheduling-clock interrupt를 보낼 이유가 거의 없다. 이 interrupt의 주된 목적은 바쁜 CPU가 여러 작업 사이에서 실행 대상을 바꾸게 하는 것인데 idle CPU에는 바꿀 작업이 없기 때문이다.
Scheduling-clock interrupt를 받지 않는 idle CPU는 dyntick-idle, dyntick-idle mode, nohz mode 또는 tickless라고 한다. 이 문서는 dyntick-idle mode라는 표현을 사용한다.
CONFIG_NO_HZ_IDLE=y는 idle CPU에 scheduling-clock interrupt를 보내지 않게 한다. Battery device와 많은 virtual machine을 실행하는 mainframe에서 특히 중요하다. CONFIG_HZ_PERIODIC=y kernel을 쓰는 battery device는 CONFIG_NO_HZ_IDLE=y를 쓸 때보다 battery를 2~3배 빠르게 소모할 수 있다. OS instance 1,500개를 실행하는 mainframe에서는 불필요한 tick이 CPU 시간의 절반을 사용할 수도 있다.
하지만 dyntick-idle mode에도 비용이 있다. Idle loop 진입과 이탈 path에서 실행하는 instruction 수가 늘고, 많은 architecture에서는 비싼 clock reprogramming operation도 증가한다. 매우 엄격한 real-time response constraint가 있는 system은 idle에서 빠져나오는 latency 증가를 피하려고 CONFIG_HZ_PERIODIC=y를 사용하기도 한다.
CONFIG_NO_HZ_IDLE=y kernel의 dyntick-idle mode는 boot parameter nohz=off로 비활성화할 수 있다. 기본값은 nohz=on이므로 활성화된 상태로 boot한다.
Runnable task가 하나인 CPU의 tick 생략: CONFIG_NO_HZ_FULL
104-143CPU에 runnable task가 하나뿐이면 전환할 다른 task가 없으므로 scheduling-clock interrupt를 보낼 이유가 거의 없다. 이 경우 tick을 생략하는 기능은 idle CPU의 tick 생략도 포함한다.
CONFIG_NO_HZ_FULL=y는 runnable task가 하나인 CPU에 scheduling-clock interrupt를 보내지 않으며 이런 CPU를 adaptive-ticks CPU라고 한다. 엄격한 real-time response constraint가 있는 application은 scheduling-clock interrupt의 최대 실행 시간만큼 worst-case response time을 줄일 수 있다.
계산량이 많고 iteration이 짧은 workload에도 중요하다. 어떤 iteration에서 CPU 하나가 지연되면 다른 모든 CPU는 그 CPU가 끝날 때까지 idle로 기다린다. 따라서 지연 비용은 CPU 수보다 하나 작은 배수만큼 확대된다.
기본 상태에서는 adaptive-ticks CPU가 없다. nohz_full= boot parameter로 CPU를 지정한다. 예를 들어 nohz_full=1,6-8은 CPU 1, 6, 7, 8을 adaptive-ticks CPU로 지정한다.
모든 CPU를 adaptive-ticks로 지정할 수는 없다. Adaptive CPU의 gettimeofday() 같은 system call이 정확한 값을 돌려주도록 timekeeping task를 처리할 non-adaptive CPU가 최소 하나 online이어야 한다. CONFIG_NO_HZ_IDLE=y에서는 실행 중인 user process가 없어 작은 clock drift를 관찰할 대상이 없으므로 이 문제가 없다. CONFIG_NO_HZ_FULL=y가 실제 효과를 내려면 system에 CPU가 최소 두 개 있어야 한다.
Adaptive-ticks CPU의 RCU callback은 반드시 다른 CPU로 offload해야 한다. 자세한 내용은 뒤의 RCU 절에서 설명한다.
CPU는 가능한 한 오래 adaptive-ticks mode에 머문다. Kernel mode로 전환한다고 자동으로 mode를 벗어나지는 않는다. 예를 들어 해당 CPU가 RCU callback을 enqueue하여 tick이 실제로 필요한 경우에만 adaptive-ticks mode에서 빠져나온다.
Adaptive tick의 비용과 제약
144-174- CONFIG_NO_HZ_FULL은 CONFIG_NO_HZ_COMMON을 select하므로 dyntick idle 없이 adaptive tick만 사용할 수 없다. 구현 의존성도 이어져 CONFIG_NO_HZ_IDLE의 모든 비용을 함께 부담한다.
- Mode 변경을 RCU 같은 kernel subsystem에 알려야 하므로 user/kernel 전환이 약간 더 비싸진다.
- POSIX CPU timer가 있으면 CPU가 adaptive-tick mode에 들어갈 수 없다. CPU time 소비량을 기준으로 동작해야 하는 real-time application은 다른 방법을 써야 한다.
- Hardware가 수용할 수 있는 수보다 perf event가 많으면 보통 event를 round-robin하여 시간에 걸쳐 모두 수집한다. Adaptive-tick mode가 이 round-robin을 막을 수 있다. 많은 perf event가 pending인 CPU의 mode 진입을 막는 방식으로 수정될 가능성이 있다.
- Adaptive-tick CPU의 scheduler statistic은 non-adaptive CPU와 약간 다르게 계산될 수 있으며, 그 결과 real-time task load balancing이 흔들릴 수 있다.
계속 개선될 것으로 예상되지만 adaptive tick은 이미 여러 real-time 및 compute-intensive application에 유용하다. 다만 위 단점 때문에 아직 기본으로 enable해서는 안 된다.
RCU callback offload
177-196CPU에 RCU callback이 pending인 경우처럼 idle CPU가 dyntick-idle 또는 adaptive-tick mode에 들어가면 안 되는 상황이 있다.
CONFIG_RCU_NOCB_CPU=y를 사용하면 RCU callback 처리를 rcuo kthread로 offload하여 이를 피할 수 있다. rcu_nocbs= boot parameter에 쉼표로 구분한 CPU와 CPU range를 지정한다. 예를 들어 rcu_nocbs=1,3-5는 CPU 1, 3, 4, 5를 선택한다. nohz_full=에 지정한 CPU도 자동으로 offload된다.
Offload된 CPU는 RCU callback을 queue하지 않으므로 RCU 때문에 dyntick-idle 또는 adaptive-tick mode 진입이 막히지 않는다. rcuo kthread를 특정 CPU에 고정하고 싶다면 userspace가 직접 pin해야 한다. 그렇지 않으면 scheduler가 실행 CPU를 결정하므로 원하는 위치와 다를 수 있다.
OS jitter 제거 효과 시험
199-220이 문서의 OS jitter 감소 기능을 모두 enable했는데 workload 동작이 바뀌지 않았다면, workload가 jitter에 민감하지 않은 것인지 다른 요인이 방해하는 것인지 구분해야 한다. 간단한 시험 suite가 다음 git archive의 master branch에 있다.
git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git
Archive를 clone하고 README의 지시를 따르면 OS jitter가 system에서 제거되었는지 평가할 trace를 생성한다. 가능한 만큼 jitter가 제거되었다고 trace가 보여 준다면 해당 workload가 OS jitter에 크게 민감하지 않다고 결론 내릴 수 있다.
이 test에는 CPU가 최소 두 개 필요하다. 현재 single-CPU system에서 OS jitter를 제거하는 좋은 방법은 없다.
알려진 문제: idle 전환 latency
223-249Dyntick-idle은 idle 진입과 이탈을 약간 느리게 한다. 실제로는 가장 엄격한 real-time workload를 제외하면 문제가 되지 않았으며, 그런 workload 대부분은 dyntick-idle을 끈다. 그러나 scheduling-clock interrupt latency를 없애려고 adaptive tick을 사용해야 하는 workload도 있다.
- 권장 방식: userspace의 PMQOS로 kernel에 latency 요구 사항을 전달한다.
- x86에서는 idle=mwait boot parameter를 사용한다.
- x86에서는 intel_idle.max_cstate=로 최대 C-state 깊이를 제한한다.
- x86에서는 idle=poll을 사용할 수 있다. 그러나 CPU 과열과 thermal throttling으로 latency가 dyntick-idle보다 더 나빠질 수 있다. Intel CPU의 Turbo Mode도 사실상 꺼져 최대 성능이 크게 낮아질 수 있다.
알려진 문제: adaptive tick 적용 범위와 runtime 재구성
250-283Adaptive tick은 user/kernel 전환을 약간 느리게 한다. 전환 횟수가 적은 compute-intensive workload에는 문제가 되지 않을 것으로 예상하지만 다른 workload의 영향은 세밀하게 benchmark해야 한다.
현재 adaptive tick은 CPU에 runnable task가 정확히 하나일 때만 동작한다. Tick이 필요 없는 다른 상황은 처리하지 못한다. 예를 들어 높은 priority의 runnable SCHED_FIFO task 하나와 낮은 priority의 SCHED_OTHER task 여러 개가 있는 CPU는 SCHED_FIFO task가 block되거나 더 높은 priority task가 깨어날 때까지 계속 그 task를 실행해야 한다. 이때 tick은 필요 없지만 현재 구현은 불필요한 scheduling-clock interrupt를 보낸다.
Runnable task가 여러 개여도 현재 task의 timeslice가 만료되기 전에는 CPU를 interrupt할 이유가 거의 없다. Timeslice는 대개 다음 scheduling-clock interrupt보다 훨씬 뒤에 끝난다. 이런 경우를 더 잘 처리하는 일은 향후 과제다.
Adaptive idle과 RCU callback offload 구성을 바꾸려면 reboot해야 한다. Runtime 재구성을 구현할 수는 있지만 RCU를 실행 중에 재구성하는 복잡성을 감수할 만큼 매우 강한 이유가 필요하다. 모든 CPU에서 RCU callback을 offload한 뒤 필요할 때 원하는 CPU에 pin하는 단순한 선택지가 있기 때문이다.
알려진 문제: 다른 OS jitter source
285-299Interrupt, system utility task, process 같은 다른 OS jitter source에는 추가 구성이 필요하며 보통 interrupt와 task를 특정 CPU에 binding한다.
일부 jitter는 workload를 제한해야만 없앨 수 있다. Global TLB shootdown으로 생기는 jitter를 없애려면 kernel module unload처럼 shootdown을 발생시키는 unmap operation을 피해야 한다. Huge page를 사용하고 application memory 사용량을 제한하면 page fault와 TLB miss를 줄이거나 경우에 따라 없앨 수 있다. Working set을 미리 fault하는 방법도 도움이 되며 mlock() 또는 mlockall()과 함께 쓰면 특히 효과적이다.
알려진 문제: timekeeping과 주기적 scheduler 작업
301-317모든 CPU가 idle이 아니라면 정확한 timekeeping을 위해 최소 CPU 하나는 scheduling-clock interrupt를 계속 발생시켜야 한다. Adaptive-ticks CPU가 존재할 가능성이 있으면 다른 모든 CPU가 idle이어도 최소 CPU 하나가 tick을 유지한다. 이 상황을 더 잘 처리하는 작업이 진행 중이다.
일부 process 처리에는 아직 간헐적인 scheduling-clock tick이 필요하다. CPU load 계산, sched average 유지, CFS entity vruntime 계산, avenrun 계산, load balancing이 포함된다. 현재는 약 1초마다 tick을 발생시켜 처리한다. 진행 중인 작업은 이런 드문 tick의 필요성까지 없애는 것을 목표로 한다.
세 가지 scheduling tick mode
no_hz.rst:1-32