减少由于每个 CPU 的 kthread 导致的操作系统抖动

本文档列出了 Linux 内核中每个 CPU 的 kthread,并提供了控制其操作系统抖动的选项。请注意,此处未列出非每个 CPU 的 kthread。要减少非每个 CPU 的 kthread 导致的操作系统抖动,请将它们绑定到专用于此类工作的“内务处理”CPU。

参考

  • SMP IRQ 亲和性:将中断绑定到 CPU 集。

  • Documentation/admin-guide/cgroup-v1:使用 cgroup 将任务绑定到 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

kthread

名称

ehca_comp/%u

目的

定期处理与 Infiniband 相关的工作。

要减少其操作系统抖动,请执行以下任一操作

  1. 不要使用 eHCA Infiniband 硬件,而是选择不需要每个 CPU kthread 的硬件。这将防止首先创建这些 kthread。(这对大多数人来说都可行,因为这种硬件虽然重要,但相对较旧,并且产量相对较低。)

  2. 在其他 CPU 上完成所有与 eHCA-Infiniband 相关的工作,包括中断。

  3. 重做 eHCA 驱动程序,使其每个 CPU 的 kthread 仅在选定的 CPU 上配置。

名称

irq/%d-%s

目的

处理线程中断。

要减少其操作系统抖动,请执行以下操作

  1. 使用 irq 亲和性强制 irq 线程在其他 CPU 上执行。

名称

kcmtpd_ctr_%d

目的

处理蓝牙工作。

要减少其操作系统抖动,请执行以下操作之一

  1. 不要使用蓝牙,在这种情况下,这些 kthread 首先不会被创建。

  2. 使用 irq 亲和性强制与蓝牙相关的中断发生在其他 CPU 上,并且在其他 CPU 上启动所有蓝牙活动。

名称

ksoftirqd/%u

目的

在线程化或高负载下执行 softirq 处理程序。

要减少其操作系统抖动,每个 softirq 向量必须单独处理,如下所示

TIMER_SOFTIRQ

执行以下所有操作

  1. 在可能的情况下,当 CPU 非空闲时,使其远离内核,例如,通过避免系统调用并强制内核线程和中断在其他地方执行。

  2. 使用 CONFIG_HOTPLUG_CPU=y 构建。引导完成后,强制 CPU 离线,然后使其重新联机。这会强制重复计时器迁移到其他地方。如果您担心多个 CPU,请在使第一个 CPU 重新联机之前强制它们全部离线。一旦您使有问题的 CPU 联机,请不要使任何其他 CPU 离线,因为这样做可能会强制计时器回到有问题的 CPU 之一上。

NET_TX_SOFTIRQ 和 NET_RX_SOFTIRQ

执行以下所有操作

  1. 强制网络中断到其他 CPU 上。

  2. 在其他 CPU 上启动任何网络 I/O。

  3. 一旦您的应用程序启动,请阻止可能在要取消抖动的 CPU 上运行的任务启动 CPU 热插拔操作。(可以在启动应用程序之前强制此 CPU 离线,然后使其重新联机。)

BLOCK_SOFTIRQ

执行以下所有操作

  1. 强制块设备中断到其他 CPU 上。

  2. 在其他 CPU 上启动任何块 I/O。

  3. 一旦您的应用程序启动,请阻止可能在要取消抖动的 CPU 上运行的任务启动 CPU 热插拔操作。(可以在启动应用程序之前强制此 CPU 离线,然后使其重新联机。)

IRQ_POLL_SOFTIRQ

执行以下所有操作

  1. 强制块设备中断到其他 CPU 上。

  2. 在其他 CPU 上启动任何块 I/O 和块 I/O 轮询。

  3. 一旦您的应用程序启动,请阻止可能在要取消抖动的 CPU 上运行的任务启动 CPU 热插拔操作。(可以在启动应用程序之前强制此 CPU 离线,然后使其重新联机。)

TASKLET_SOFTIRQ

执行以下一个或多个操作

  1. 避免使用使用 tasklet 的驱动程序。(此类驱动程序将包含对 tasklet_schedule() 之类的调用。)

  2. 将所有必须使用的驱动程序从 tasklet 转换为工作队列。

  3. 强制使用 tasklet 的驱动程序的中断到其他 CPU 上,并在其他 CPU 上执行涉及这些驱动程序的 I/O。

SCHED_SOFTIRQ

执行以下所有操作

  1. 避免向要取消抖动的 CPU 发送调度程序 IPI,例如,确保该 CPU 上最多存在一个可运行的 kthread。如果预期在取消抖动的 CPU 上运行的线程被唤醒,调度程序将发送一个 IPI,这可能导致后续的 SCHED_SOFTIRQ。

  2. CONFIG_NO_HZ_FULL=y 并确保要取消抖动的 CPU 使用“nohz_full=”引导参数标记为自适应滴答 CPU。这减少了取消抖动的 CPU 收到的调度程序时钟中断的数量,从而最大限度地减少了它被选择来执行在 SCHED_SOFTIRQ 上下文中运行的负载平衡工作的机会。

  3. 在可能的情况下,当 CPU 非空闲时,使其远离内核,例如,通过避免系统调用并强制内核线程和中断在其他地方执行。这进一步减少了取消抖动的 CPU 收到的调度程序时钟中断的数量。

HRTIMER_SOFTIRQ

执行以下所有操作

  1. 在可能的情况下,当 CPU 非空闲时,使其远离内核。例如,避免系统调用并强制内核线程和中断在其他地方执行。

  2. 使用 CONFIG_HOTPLUG_CPU=y 构建。引导完成后,强制 CPU 离线,然后使其重新联机。这会强制重复计时器迁移到其他地方。如果您担心多个 CPU,请在使第一个 CPU 重新联机之前强制它们全部离线。一旦您使有问题的 CPU 联机,请不要使任何其他 CPU 离线,因为这样做可能会强制计时器回到有问题的 CPU 之一上。

RCU_SOFTIRQ

至少执行以下一项操作

  1. 卸载回调,并通过执行以下所有操作使 CPU 处于 dyntick 空闲或自适应滴答状态

    1. CONFIG_NO_HZ_FULL=y 并确保要取消抖动的 CPU 使用“nohz_full=”引导参数标记为自适应滴答 CPU。将 rcuo kthread 绑定到可以容忍操作系统抖动的内务处理 CPU。

    2. 在可能的情况下,当 CPU 非空闲时,使其远离内核,例如,通过避免系统调用并强制内核线程和中断在其他地方执行。

  2. 通过执行以下所有操作,启用 RCU 通过 dyntick 空闲远程执行其处理

    1. 使用 CONFIG_NO_HZ=y 构建。

    2. 确保 CPU 频繁进入空闲状态,允许其他 CPU 检测到它已通过 RCU 静止状态。如果内核使用 CONFIG_NO_HZ_FULL=y 构建,则用户空间执行也允许其他 CPU 检测到有问题的 CPU 已通过静止状态。

    3. 在可能的情况下,当 CPU 非空闲时,使其远离内核,例如,通过避免系统调用并强制内核线程和中断在其他地方执行。

名称

kworker/%u:%d%s (cpu, id, 优先级)

目的

执行工作队列请求

要减少其操作系统抖动,请执行以下任一操作

  1. 以实时优先级运行您的工作负载,这将允许抢占 kworker 守护程序。

  2. 通过将 WQ_SYSFS 传递给该工作队列的 alloc_workqueue(),可以在 sysfs 文件系统中显示给定的工作队列。可以使用 /sys/devices/virtual/workqueue/*/cpumask sysfs 文件将此类工作队列限制在给定的 CPU 子集内。可以使用“ls /sys/devices/virtual/workqueue”显示 WQ_SYSFS 工作队列集。也就是说,工作队列维护者希望告诫人们不要不加区分地在所有工作队列中撒 WQ_SYSFS。需要谨慎的原因是,添加 WQ_SYSFS 很容易,但是因为 sysfs 是正式用户/内核 API 的一部分,所以即使添加是错误的,也几乎不可能将其删除。

  3. 执行以下任何必要的操作以避免您的应用程序无法容忍的抖动

    1. 避免使用 oprofile,从而避免 wq_sync_buffer() 造成的操作系统抖动。

    2. 限制您的 CPU 频率,以便不需要 CPU 频率调速器,可能会利用特殊散热器或其他冷却技术的帮助。如果操作正确,并且您的 CPU 架构允许,您应该能够使用 CONFIG_CPU_FREQ=n 构建您的内核,以避免 CPU 频率调速器定期在每个 CPU 上运行,包括 cs_dbs_timer() 和 od_dbs_timer()。

      警告:请检查您的 CPU 规格,以确保这在您的特定系统上是安全的。

    3. 从 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

    4. 如果在高端 powerpc 服务器上运行,请使用 CONFIG_PPC_RTAS_DAEMON=n 构建。这可以防止 RTAS 守护进程每秒左右在每个 CPU 上运行。(这需要编辑 Kconfig 文件,并且会破坏此平台的 RAS 功能。)这可以避免由于 rtas_event_scan() 函数引起的抖动。警告:请检查您的 CPU 规格,以确保这在您的特定系统上是安全的。

    5. 如果在 Cell 处理器上运行,请使用 CBE_CPUFREQ_SPU_GOVERNOR=n 构建您的内核,以避免 spu_gov_work() 引起的操作系统抖动。警告:请检查您的 CPU 规格,以确保这在您的特定系统上是安全的。

    6. 如果在 PowerMAC 上运行,请使用 CONFIG_PMAC_RACKMETER=n 构建您的内核,以禁用 CPU 仪表,避免 rackmeter_do_timer() 引起的操作系统抖动。

名称

rcuc/%u

目的

在 CONFIG_RCU_BOOST=y 内核中执行 RCU 回调。

要减少其操作系统抖动,请至少执行以下一项

  1. 使用 CONFIG_PREEMPT=n 构建内核。这可以防止首先创建这些 kthread,并且还避免了 RCU 优先级提升的需要。对于不需要高响应度的工作负载,此方法是可行的。

  2. 使用 CONFIG_RCU_BOOST=n 构建内核。这可以防止首先创建这些 kthread。只有当您的工作负载永远不需要 RCU 优先级提升时,此方法才可行,例如,如果您确保在可能在内核中执行的所有 CPU 上都有频繁的空闲时间。

  3. 使用 CONFIG_RCU_NOCB_CPU=y 构建,并使用 rcu_nocbs= 启动参数从所有容易发生操作系统抖动的 CPU 上卸载 RCU 回调。此方法可防止 rcuc/%u kthread 有任何工作要做,从而使它们永远不会被唤醒。

  4. 确保 CPU 永远不会进入内核,特别是避免在此 CPU 上启动任何 CPU 热插拔操作。这是防止任何回调在 CPU 上排队的另一种方法,再次防止 rcuc/%u kthread 有任何工作要做。

名称

rcuop/%d、rcuos/%d 和 rcuog/%d

目的

从相应的 CPU 卸载 RCU 回调。

要减少其操作系统抖动,请至少执行以下一项

  1. 使用亲和性、cgroup 或其他机制强制这些 kthread 在其他 CPU 上执行。

  2. 使用 CONFIG_RCU_NOCB_CPU=n 构建,这将阻止首先创建这些 kthread。但是,请注意,这不会消除操作系统抖动,而是会将其转移到 RCU_SOFTIRQ。