可以使用sched_setaffinity将线程固定到cpu,从而提高性能(在某些情况下)
从linux手册页:
将进程限制在单个CPU上运行也可以避免
由于缓存失效而导致的性能损失
进程停止在一个CPU上执行,然后在另一个CPU上重新开始执行
不同的CPU
此外,如果我需要更实时的响应,我可以将该线程的调度程序策略更改为SCHED_FIFO,并将优先级提高到某个较高的值(高达SCHED_get_priority_max),这意味着当该线程准备就绪时,该线程应该始终抢占其cpu上运行的任何其他线程
然而,此时,实时线程刚刚抢占的cpu上运行的线程可能已经退出了实时线程的大部分1级缓存项
我的问题如下:
- 是否可以阻止调度程序将任何线程调度到给定的cpu上?(例如:要么对调度程序完全隐藏cpu,要么以其他方式)
- 是否有一些线程必须能够在该cpu上运行?(例如:内核线程/中断线程)
- 如果我需要在该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个cpu(0)的
系统cpuset - 创建一个带有1个cpu(1)的
prio_lowcpuset - 使用2个CPU(1-2)创建一个
prio_metcpuset - 创建一个带有3个CPU(1-3)的
prio_highcpuset - 使用所有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