减少每个 CPU 的 kthread 引起的操作系统抖动¶
本文列出了 Linux 内核中每个 CPU 的 kthread,并提出了控制其操作系统抖动的方法。请注意,非每个 CPU 的 kthread 不在此列。为了减少非每个 CPU 的 kthread 产生的操作系统抖动,请将它们绑定到专门用于此类工作的“日常维护 (housekeeping)”CPU 上。
参考资料¶
SMP IRQ 亲和性:将中断绑定到一组 CPU。
Documentation/admin-guide/cgroup-v1:使用 cgroups 将任务绑定到一组 CPU。
man taskset:使用 taskset 命令将任务绑定到一组 CPU。
man sched_setaffinity:使用
sched_setaffinity()系统调用将任务绑定到一组 CPU。/sys/devices/system/cpu/cpuN/online:控制 CPU N 的热插拔状态,写入“0”表示下线,写入“1”表示上线。
为了定位 CPU N 上由内核产生的操作系统抖动
cd /sys/kernel/tracing echo 1 > max_graph_depth # 增加“1”的值以获取更多详细信息 echo function_graph > current_tracer # 运行工作负载 cat per_cpu/cpuN/trace
kthreads¶
- 名称
ehca_comp/%u
- 用途
定期处理 InfiniBand 相关的工作。
为了减少其操作系统抖动,请执行以下任意操作:
不要使用 eHCA InfiniBand 硬件,而是选择不需要每个 CPU 的 kthread 的硬件。这可以从一开始就防止创建这些 kthread。(这对大多数人有效,因为这种硬件虽然重要,但相对较旧且产量相对较低。)
在其他 CPU 上完成所有与 eHCA InfiniBand 相关的工作,包括中断。
改造 eHCA 驱动程序,使其每个 CPU 的 kthread 仅在选定的 CPU 上配置。
- 名称
irq/%d-%s
- 用途
处理线程化中断。
为了减少其操作系统抖动,请执行以下操作:
使用中断亲和性(irq affinity)强制 irq 线程在其他 CPU 上执行。
- 名称
kcmtpd_ctr_%d
- 用途
处理蓝牙工作。
为了减少其操作系统抖动,请执行以下操作之一:
不要使用蓝牙,在这种情况下,这些 kthread 从一开始就不会被创建。
使用中断亲和性强制蓝牙相关的中断在其他 CPU 上发生,并且在其他 CPU 上发起所有蓝牙活动。
- 名称
ksoftirqd/%u
- 用途
在线程化或高负载情况下执行软中断(softirq)处理程序。
为了减少其操作系统抖动,必须分别对每个软中断向量进行如下处理:
TIMER_SOFTIRQ¶
执行以下所有操作:
尽最大可能在 CPU 非空闲时使其远离内核,例如,通过避免系统调用,并强制内核线程和中断在别处执行。
使用 CONFIG_HOTPLUG_CPU=y 构建内核。引导完成后,强制 CPU 下线,然后再将其上线。这会迫使周期性定时器迁移到别处。如果您关心多个 CPU,请在将第一个 CPU 重新上线之前,将它们全部强制下线。一旦您将相关 CPU 上线,切勿将任何其他 CPU 下线,因为这样做可能会迫使定时器重新回到相关 CPU 上。
NET_TX_SOFTIRQ 和 NET_RX_SOFTIRQ¶
执行以下所有操作:
强制网络中断到其他 CPU 上。
在其他 CPU 上发起任何网络 I/O。
一旦您的应用程序启动,请防止从可能在要消除抖动的 CPU 上运行的任务中发起 CPU 热插拔操作。(在启动应用程序之前,强制此 CPU 下线然后再将其上线是可以的。)
BLOCK_SOFTIRQ¶
执行以下所有操作:
强制块设备中断到其他 CPU 上。
在其他 CPU 上发起任何块 I/O。
一旦您的应用程序启动,请防止从可能在要消除抖动的 CPU 上运行的任务中发起 CPU 热插拔操作。(在启动应用程序之前,强制此 CPU 下线然后再将其上线是可以的。)
IRQ_POLL_SOFTIRQ¶
执行以下所有操作:
强制块设备中断到其他 CPU 上。
在其他 CPU 上发起任何块 I/O 和块 I/O 轮询。
一旦您的应用程序启动,请防止从可能在要消除抖动的 CPU 上运行的任务中发起 CPU 热插拔操作。(在启动应用程序之前,强制此 CPU 下线然后再将其上线是可以的。)
TASKLET_SOFTIRQ¶
执行以下一项或多项操作:
避免使用使用 tasklet 的驱动程序。(此类驱动程序将包含对诸如
tasklet_schedule()之类函数的调用。)将必须使用的所有驱动程序从 tasklet 转换为工作队列 (workqueues)。
强制使用 tasklet 的驱动程序的中断到其他 CPU 上,并且在其他 CPU 上执行涉及这些驱动程序的 I/O。
SCHED_SOFTIRQ¶
执行以下所有操作:
避免向要消除抖动的 CPU 发送调度程序 IPI,例如,确保该 CPU 上最多只有一个可运行的 kthread。如果期望在消除抖动的 CPU 上运行的线程被唤醒,调度程序将发送一个 IPI,这可能导致随后的 SCHED_SOFTIRQ。
CONFIG_NO_HZ_FULL=y,并使用“nohz_full=”引导参数确保要消除抖动的 CPU 被标记为自适应时钟滴答 (adaptive-ticks) CPU。这减少了消除抖动的 CPU 接收到的调度程序时钟中断次数,从而最大限度地降低其被选中去执行在 SCHED_SOFTIRQ 上下文中运行的负载均衡工作的几率。
尽最大可能在 CPU 非空闲时使其远离内核,例如,通过避免系统调用,并强制内核线程和中断在别处执行。这进一步减少了消除抖动的 CPU 接收到的调度程序时钟中断次数。
HRTIMER_SOFTIRQ¶
执行以下所有操作:
尽最大可能在 CPU 非空闲时使其远离内核。例如,避免系统调用,并强制内核线程和中断在别处执行。
使用 CONFIG_HOTPLUG_CPU=y 构建内核。引导完成后,强制 CPU 下线,然后再将其上线。这会迫使周期性定时器迁移到别处。如果您关心多个 CPU,请在将第一个 CPU 重新上线之前,将它们全部强制下线。一旦您将相关 CPU 上线,切勿将任何其他 CPU 下线,因为这样做可能会迫使定时器重新回到相关 CPU 上。
RCU_SOFTIRQ¶
执行以下至少一项操作:
通过执行以下所有操作,卸载回调 (callbacks) 并使 CPU 保持在动态时钟滴答空闲 (dyntick-idle) 或自适应时钟滴答 (adaptive-ticks) 状态:
CONFIG_NO_HZ_FULL=y,并使用“nohz_full=”引导参数确保要消除抖动的 CPU 被标记为自适应时钟滴答 CPU。将 rcuo kthreads 绑定到能够容忍操作系统抖动的日常维护 (housekeeping) CPU 上。
尽最大可能在 CPU 非空闲时使其远离内核,例如,通过避免系统调用,并强制内核线程和中断在别处执行。
通过执行以下所有操作,使 RCU 能够通过动态时钟滴答空闲 (dyntick-idle) 远程执行其处理:
使用 CONFIG_NO_HZ=y 构建内核。
确保 CPU 频繁进入空闲状态,从而允许其他 CPU 检测到它已经通过了 RCU 静止状态 (quiescent state)。如果内核构建时带有 CONFIG_NO_HZ_FULL=y,则用户空间执行也允许其他 CPU 检测到相关 CPU 已经通过了静止状态。
尽最大可能在 CPU 非空闲时使其远离内核,例如,通过避免系统调用,并强制内核线程和中断在别处执行。
- 名称
kworker/%u:%d%s (cpu, id, priority)
- 用途
执行工作队列请求
为了减少其操作系统抖动,请执行以下任意操作:
以实时优先级运行您的工作负载,这将允许抢占 kworker 守护进程。
通过将 WQ_SYSFS 传递给该工作队列的
alloc_workqueue(),可以使特定工作队列在 sysfs 文件系统中可见。可以使用/sys/devices/virtual/workqueue/*/cpumasksysfs 文件将此类工作队列限制在给定的 CPU 子集中。可以使用“ls /sys/devices/virtual/workqueue”显示 WQ_SYSFS 工作队列的集合。话虽如此,工作队列维护人员希望提醒大家不要在所有工作队列中盲目滥用 WQ_SYSFS。需要谨慎的原因是,添加 WQ_SYSFS 很简单,但由于 sysfs 是正式的用户/内核 API 的一部分,因此几乎不可能将其删除,即使当初添加它是一个错误。执行以下任何必要的操作,以避免您的应用程序无法容忍的抖动:
避免使用 oprofile,从而避免来自
wq_sync_buffer()的操作系统抖动。限制您的 CPU 频率,以便不需要 CPU 频率调节器 (governor),可能需要借助特殊的散热片或其他冷却技术。如果操作正确,且您的 CPU 架构允许,您应该能够通过 CONFIG_CPU_FREQ=n 构建内核,以避免 CPU 频率调节器定期在每个 CPU 上运行,包括
cs_dbs_timer()和od_dbs_timer()。警告:请检查您的 CPU 规格,以确保这在您的特定系统上是安全的。
从 v3.18 开始,Christoph Lameter 的按需 vmstat 工作线程提交防止了在 CONFIG_SMP=y 系统上由
vmstat_update()引起的操作系统抖动。在 v3.18 之前,无法完全消除操作系统抖动,但您可以通过向 /proc/sys/vm/stat_interval 写入一个较大的值来降低其频率。默认值为 HZ,时间间隔为一秒。当然,较大的值会使您的虚拟内存统计信息更新更慢。当然,您也可以以实时优先级运行您的工作负载,从而抢占vmstat_update(),但如果您的工作负载是 CPU 密集型的,这不是一个好主意。不过,Christoph Lameter 有一个 RFC 补丁(基于 Gilad Ben-Yossef 早期的补丁),可以减少甚至消除某些工作负载的 vmstat 开销,详见 https://lore.kernel.org/r/00000140e9dfd6bd-40db3d4f-c1be-434f-8132-7820f81bb586-000000@email.amazonses.com。如果在高端 powerpc 服务器上运行,请使用 CONFIG_PPC_RTAS_DAEMON=n 构建内核。这可以防止 RTAS 守护进程每隔一秒左右在每个 CPU 上运行。(这需要编辑 Kconfig 文件,并且会破坏该平台的 RAS 功能。)这避免了由
rtas_event_scan()函数引起的抖动。警告:请检查您的 CPU 规格,以确保这在您的特定系统上是安全的。如果在 PowerMAC 上运行,请使用 CONFIG_PMAC_RACKMETER=n 构建内核以禁用 CPU 仪表 (CPU-meter),从而避免来自
rackmeter_do_timer()的操作系统抖动。
- 名称
rcuc/%u
- 用途
在 CONFIG_RCU_BOOST=y 内核中执行 RCU 回调。
为了减少其操作系统抖动,请执行以下至少一项操作:
使用 CONFIG_PREEMPT=n 构建内核。这从一开始就防止创建这些 kthread,并且还免去了对 RCU 优先级提升 (priority boosting) 的需求。这种方法对于不需要高响应度的工作负载是可行的。
使用 CONFIG_RCU_BOOST=n 构建内核。这从一开始就防止创建这些 kthread。这种方法仅在您的工作负载绝不需要 RCU 优先级提升时才可行,例如,如果您确保可能在内核中执行的所有 CPU 上都有频繁的空闲时间。
使用 CONFIG_RCU_NOCB_CPU=y 构建内核,并使用 rcu_nocbs= 引导参数启动,从所有易受操作系统抖动影响的 CPU 中卸载 RCU 回调。这种方法可防止 rcuc/%u kthreads 有任何工作要做,从而使它们永远不会被唤醒。
确保 CPU 从不进入内核,特别是避免在该 CPU 上发起任何 CPU 热插拔操作。这是防止在 CPU 上排队任何回调的另一种方法,再次防止了 rcuc/%u kthreads 有任何工作要做。
- 名称
rcuop/%d, rcuos/%d, 和 rcuog/%d
- 用途
从相应的 CPU 卸载 RCU 回调。
为了减少其操作系统抖动,请执行以下至少一项操作:
使用亲和性 (affinity)、cgroups 或其他机制强制这些 kthread 在其他 CPU 上执行。
使用 CONFIG_RCU_NOCB_CPU=n 构建内核,这将从一开始就防止创建这些 kthread。但是,请注意,这不会消除操作系统抖动,而是将其转移到 RCU_SOFTIRQ。