CPU Isolation

CPU隔离

Posted by icecube on December 18, 2023

简介

cpu隔离是个很有用的特性。目的是最小化指定cpu上的内核活动,这些内核活动可能导致延迟,降低性能。
有些高带宽网络应用或者实时系统,对延迟和性能有特殊要求,必须独占cpu,不能受到任何其它系统活动的干扰。
比如DPDK超高的网络带宽不允许发生丢包或者抖动。

系统活动比如,中断、timer、内核线程(比如workqueues),页面回收等,
这些异步的事件处理对于维护系统正常运行是必须的,因此称之为housekeeping任务。
有些任务是绑定到cpu,有些没有绑定,没有绑定的可以在任一cpu上运行。
这些任务有可能打断cpu上当前正在执行的业务进程,偷走业务进程的cpu cycle并且污染cache,导致进程cache miss 严重影响业务正常运行。

housekeeping

大致有以下几种系统活动

  • timer
  • irq/softirq
  • scheduler tick
  • rcu callback
  • workqueues
  • kthreads

对应内核中定义的这些TYPE

enum hk_type {
	HK_TYPE_TIMER,         //  0 定时器
	HK_TYPE_RCU,           //  1 RCU callback
	HK_TYPE_MISC,          //  2 idle rebalancing work
	HK_TYPE_SCHED,         //  3 内核未明确使用该类型
	HK_TYPE_TICK,          //  4 HZ心跳
	HK_TYPE_DOMAIN,        //  5 域调度
	HK_TYPE_WQ,            //  6 工作队列
	HK_TYPE_MANAGED_IRQ,   //  7 如果有中断的affnity cpu包含了isolcpus指定的cpu,那么这个type可以让cpu避免受到这类中断的干扰
	HK_TYPE_KTHREAD,       //  8 内核线程
	HK_TYPE_MAX
};

这里的每一种housekeeping事件类型都代表一个干扰因素,到来时会打断cpu当前任务,影响到关键业务

隔离指定cpu,给关键业务进程提供一个干净的cpu环境,可以通过给内核传递 isolcpusnohz_full 两个参数达到目的

  • 0、1、2、4、6、8 由nohz_full参数负责
  • 3 未起用
  • 4、5、7 由isolcpus参数负责(默认5, 4和7可选)

本质上是把参数指定范围内的cpu上的绝大部分任务迁移到 housekeeping cpus 上。
是绝大部分,而不是全部,因为有些per-cpu kthreads 不允许调整cpu affinity.

干扰只能转移,不能消除。

内核定义了一个全局变量 housekeeping 用于跟踪哪些cpu处理负责哪种每种类型的事件

struct housekeeping {
	cpumask_var_t cpumasks[HK_TYPE_MAX];
	unsigned long flags;   //  跟踪记录所有需要处理的TYPE
};

static struct housekeeping housekeeping;

每一个HK_TYPE事件都有自己的cpumask,置位的cpu需要负责处理这些类型事件
没有置位的cpu则无需处理,除非用户配置有变化,比如绑定至少两个进程到某个cpu

rcu_nobcs

我们知道RCU适用于多个读者和一个写者的场景。
当所有读者都退出了临界区,RCU移除阶段的回调就会释放内存。
这些回调可能会降低实时性能,特别是如果它们在中断上下文中运行,可能引入不可忽视的调度延迟。

内核中实现了CONFIG_RCU_NOCB_CPU 配置项和 rcu_nocbs 参数
可以将RCU回调移动到可在其它non time-critical CPUs上的 kthreads 中。

如果已经指定了nohz_full,就无需再提供 rcu_nocbs

参数定制

同时提供参数 nohz_fullisolcpus才有意义
没有isolcpus,调度器可能会选择在nohz_full指定的核心上运行新的任务
这会导致内核禁用nohz_full模式并回到默认的无滴答(tickless)模式(HZ滴答/秒)

nohz_full=4-7 isolcpus=4-7

隔离cpu 4-7,既不会参与域调度,也没有timer中断上来,构造出干净的运行环境

只绑定一个进程到某个cpu上, 进程就会独占该cpu,不会被调度出去,也没有timer、tick等中断干扰

如果在cpu上绑定至少两个进程的话,中断还是会上来,因为至少还需要利用tick中断在两个进程之间调度
就失去了 nohz_full 应有的意义。

参考索引

cpu isolation