如何保护cpu不受linux调度程序的影响(防止它将线程调度到该cpu上)?

可以使用sched_setaffinity将线程固定到cpu,从而提高性能(在某些情况下)

从linux手册页:

将进程限制在单个CPU上运行也可以避免
由于缓存失效而导致的性能损失
进程停止在一个CPU上执行,然后在另一个CPU上重新开始执行
不同的CPU

此外,如果我需要更实时的响应,我可以将该线程的调度程序策略更改为SCHED_FIFO,并将优先级提高到某个较高的值(高达SCHED_get_priority_max),这意味着当该线程准备就绪时,该线程应该始终抢占其cpu上运行的任何其他线程

然而,此时,实时线程刚刚抢占的cpu上运行的线程可能已经退出了实时线程的大部分1级缓存项

我的问题如下:

  1. 是否可以阻止调度程序将任何线程调度到给定的cpu上?(例如:要么对调度程序完全隐藏cpu,要么以其他方式)
  2. 是否有一些线程必须能够在该cpu上运行?(例如:内核线程/中断线程)
  3. 如果我需要在该cpu上运行内核线程,那么要使用什么合理的最大优先级值,这样我就不会耗尽内核线程

答案是使用cpusets。pythoncpuset实用程序使配置它们变得容易

基本概念

3个cpusets

  • 根目录:存在于所有配置中并包含所有CPU(非屏蔽
  • 系统:包含用于系统任务的CPU-需要运行但不“重要”的CPU(非屏蔽
  • 用户:包含用于“重要”任务的CPU—我们希望在“实时”模式下运行的CPU(屏蔽

shield命令管理这3个cpusets

在设置期间,它将所有可移动任务移动到非屏蔽cpuset(系统)中,在拆卸期间,它将所有可移动任务移动到cpuset中。
设置后,子命令允许您将任务移动到屏蔽用户)cpuset中,此外,还允许您将特殊任务(内核线程)从根目录移动到系统(从而从用户cpuset中移出)

命令:

首先我们制造一个盾牌。屏蔽的布局自然取决于机器/任务。例如,假设我们有一台4核非NUMA机器:我们想将3核专用于盾牌,并将1核留给不重要的任务;因为它是非NUMA的,所以我们不需要指定任何内存节点参数,我们让内核线程在rootcpuset中运行(即:跨所有CPU)

$cset屏蔽——cpu 1-3

一些内核线程(那些没有绑定到特定CPU的线程)可以移动到系统中cpuset。(一般来说,移动绑定到特定cpu的内核线程不是一个好主意)

$cset-shield--kthread打开

现在,让我们列出屏蔽(用户)或非屏蔽(系统)cpusets:(-v详细,将列出进程名称)(添加第二个-v以显示80多个字符)

$cset-shield--shield-v
$cset盾牌-非场-v-v

如果我们想停止防护罩(拆卸)

$cset屏蔽-重置

现在,让我们在shield中执行一个进程(将'-'后面的命令传递给要执行的命令,而不是传递给cset

$cset-shield--exec mycommand--arg1-arg2

如果我们已经有一个正在运行的进程,我们希望将其移动到屏蔽中(注意,我们可以通过传递逗号分隔的列表或范围来移动多个进程(该范围内的任何进程都将被移动,即使存在间隙))

$cset-shield--shield--pid 1234
$cset shield——屏蔽——pid 12341236
$cset屏蔽——屏蔽——pid 123412371238-1240

先进概念

cset set/proc-这些可以让您更好地控制cpusets

设置

创建、调整、重命名、移动和销毁cpusets

命令

使用CPU 1-3创建一个cpuset,使用NUMA节点1并将其称为“my_cpuset1”

$cset set--cpu=1-3--mem=1--set=my\u cpuset1

将“my_cpuset1”更改为仅使用CPU 1和3

$cset set--cpu=1,3--mem=1--set=my\u cpuset1

摧毁一个cpuset

$cset set--destroy--set=my\u cpuset1

重命名现有的cpuset

$cset set--set=my\u cpuset1--newname=your\u cpuset1

创建一个层次化的cpuset

$cset set--cpu=3--mem=1--set=my\u cpuset1/my\u subset1

列出现有cpusets(1级深度)

$cset集--列表

列出现有的cpuset及其子项

$cset set--list--set=my\u cpuset1

列出所有现有的cpusets

$cset集--列表--递归

Proc

管理线程和进程

命令

列出在cpuset中运行的任务

$cset proc--list--set=my\u cpuset1--verbose

在cpuset中执行任务

$cset proc--set=my\u cpuset1--exec myApp--arg1--arg2

移动任务

$cset proc--toset=my\u cpuset1--move--pid 1234
$cset proc--toset=my_cpuset1--move--pid 12341236
$cset proc--toset=my_cpuset1--move--pid 1238-1340

移动任务及其所有同级

$cset proc--move--toset=my_cpuset1--pid 1234--threads

将所有任务从一个cpuset移动到另一个cpuset

$cset proc--move--fromset=my\u cpuset1--toset=system

将未固定的内核线程移动到cpuset中

$cset proc--kthread--fromset=root--toset=system

强制将内核线程(包括固定到特定cpu的线程)移动到cpuset中(注意:这可能会对系统造成严重后果-确保您知道自己在做什么)

$cset proc--kthread--fromset=root--toset=system--force

层次结构示例

我们可以使用分层cpusets来创建优先级分组

  1. 创建一个带有1个cpu(0)的系统cpuset
  2. 创建一个带有1个cpu(1)的prio_lowcpuset
  3. 使用2个CPU(1-2)创建一个prio_metcpuset
  4. 创建一个带有3个CPU(1-3)的prio_highcpuset
  5. 使用所有4个CPU(0-3)创建一个prio_allcpuset(注意这与root相同;与root保持分离被认为是良好的做法)

要实现上述目标,您需要创建prio_all,然后在prio_all下创建prio_high子集,以此类推

$cset set--cpu=0--set=system
$cset set--cpu=0-3--set=prio\u all
$cset set--cpu=1-3--set=/prio\u all/prio\u high
$cset set--cpu=1-2--set=/prio\u all/prio\u high/prio\u med
$cset set--cpu=1--set=/prio_all/prio_high/prio_med/prio_low

发表评论