有可能使用sched_setaffinity
将一个线程固定到一个cpu,提高性能(在某些情况下)
从Linux手册页:
限制进程在单个CPU上运行也可以避免由于某个进程在一个CPU上停止执行而发生高速caching失效而导致的性能开销,然后重新开始在不同的CPU上执行
此外,如果我希望获得更实时的响应,我可以将该线程的调度策略更改为SCHED_FIFO
,并将优先级更改为某个较高的值(最高为sched_get_priority_max
),这意味着所讨论的线程应始终sched_get_priority_max
其他线程线程运行在它的CPU上,当它准备好了。
但是,此时,实时线程刚刚被抢占的cpu上运行的线程可能已经驱逐了实时线程的一级caching条目。
我的问题如下:
答案是使用cpusets 。 python cpuset实用程序可以很容易地配置它们。
基本概念
3 cpusets
root
:存在于所有配置中,并包含所有cpus(未屏蔽 ) system
:包含用于系统任务的cpus – 需要运行但不“重要”(未屏蔽 ) user
:包含用于“重要”任务的cpus – 我们希望以“实时”模式运行( 屏蔽 ) shield
命令管理这3个cpusets。
在安装过程中,它将所有可移动任务移动到未屏蔽的cpuset( system
)中,在拆卸过程中,它将所有可移动任务移动到root
cpuset中。 在设置之后,子命令可以让你将任务移动到shield ( user
)cpuset中,另外还可以将特殊任务(内核线程)从root
到system
(因此移出user
cpuset)。
命令:
首先我们创造一个盾牌。 当然盾的布局将依赖于机器/任务。 例如,假设我们有一个4核非NUMA机器,我们要把3个核心专门用于屏蔽 ,而把1个核心留给不重要的任务 ; 因为它不是NUMA,所以我们不需要指定任何内存节点参数,并且让内核线程在root
cpuset中运行(即:跨所有cpu)
$ cset shield --cpu 1-3
一些内核线程(不绑定到特定cpus的线程)可以移入system
cpuset。 (一般来说,移动绑定到特定cpu的内核线程并不是一个好主意)
$ cset shield --kthread on
现在让我们列出在屏蔽( user
)或非屏蔽( system
)cpusets中运行的内容:(- -v
for verbose,它将列出进程名称)(添加第二个-v
显示超过80个字符)
$ cset shield --shield -v $ cset shield --unshield -v -v
如果我们想要阻止盾牌(拆除)
$ cset shield --reset
现在让我们在盾中执行一个进程( '--'
后面'--'
命令被传递给要执行的命令,而不是cset
)
$ cset shield --exec mycommand -- -arg1 -arg2
如果我们已经有了一个正在运行的进程(我们可以通过传入一个以逗号分隔的列表或范围来移动多个进程)(即使有间隙,范围内的任何进程也会被移动)
$ cset shield --shield --pid 1234 $ cset shield --shield --pid 1234,1236 $ cset shield --shield --pid 1234,1237,1238-1240
先进的概念
cset set/proc
– 这些可以让你更好地控制cpusets
组
创建,调整,重命名,移动和销毁cpusets
命令
创建一个cpuset,使用cpu 1-3,使用NUMA节点1,并将其称为“my_cpuset1”
$ cset set --cpu=1-3 --mem=1 --set=my_cpuset1
将“my_cpuset1”更改为仅使用cpus 1和3
$ cset set --cpu=1,3 --mem=1 --set=my_cpuset1
销毁一个cpuset
$ cset set --destroy --set=my_cpuset1
重命名现有的cpuset
$ cset set --set=my_cpuset1 --newname=your_cpuset1
创建一个分层的cpuset
$ cset set --cpu=3 --mem=1 --set=my_cpuset1/my_subset1
列出现有的cpusets(级别1的深度)
$ cset set --list
列出现有的cpuset及其子项
$ cset set --list --set=my_cpuset1
列出所有现有的cpusets
$ cset set --list --recurse
PROC
管理线程和进程
命令
列出在cpuset中运行的任务
$ cset proc --list --set=my_cpuset1 --verbose
在cpuset中执行任务
$ cset proc --set=my_cpuset1 --exec myApp -- --arg1 --arg2
移动任务
$ cset proc --toset=my_cpuset1 --move --pid 1234 $ cset proc --toset=my_cpuset1 --move --pid 1234,1236 $ cset proc --toset=my_cpuset1 --move --pid 1238-1340
移动一个任务和所有的兄弟姐妹
$ cset proc --move --toset=my_cpuset1 --pid 1234 --threads
将所有任务从一个cpuset移到另一个
$ cset proc --move --fromset=my_cpuset1 --toset=system
将未固定的内核线程移入cpuset
$ cset proc --kthread --fromset=root --toset=system
强制将内核线程(包括固定到特定cpu的内核线程)移动到cpuset(注意:这可能会对系统造成严重后果 – 请确保知道自己在做什么)
$ cset proc --kthread --fromset=root --toset=system --force
层次结构的例子
我们可以使用分层的cpusets来创建优先分组
system
cpuset prio_low
cpuset(1) prio_met
cpuset prio_high
cpuset prio_all
cpuset(注意这和root是一样的;保持与root的分离被认为是一个好习惯) 为了实现上述你创建prio_all,然后在prio_all等创建子集prio_high
$ cset set --cpu=0 --set=system $ cset set --cpu=0-3 --set=prio_all $ cset set --cpu=1-3 --set=/prio_all/prio_high $ cset set --cpu=1-2 --set=/prio_all/prio_high/prio_med $ cset set --cpu=1 --set=/prio_all/prio_high/prio_med/prio_low
还有两种方法可以考虑这样做(虽然不像cset那样优雅,但它似乎并没有得到Redhat的高度支持):
1)任务包括PID 1 – 很好很容易(但是,alledgly – 我从来没有见过任何问题 – 可能会导致调度器效率低下)。 下面的脚本(必须以root身份运行)在所有正在运行的进程上运行taskset,包括init(pid 1); 这将把所有正在运行的进程固定到一个或多个“垃圾核心”上,并通过固定init来确保未来的进程也在“垃圾核心”列表中启动:
#!/bin/bash if [[ -z $1 ]]; then printf "Usage: %s '<csv list of cores to set as junk in double quotes>'", $0 exit -1; fi for i in `ps -eLfad |awk '{ print $4 } '|grep -v PID | xargs echo `; do taskset -pc $1 $i; done
2)使用isolcpus内核参数(这里是来自https://www.kernel.org/doc/Documentation/kernel-parameters.txt的文档):
isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler. Format: <cpu number>,...,<cpu number> or <cpu number>-<cpu number> (must be a positive range in ascending order) or a mixture <cpu number>,...,<cpu number>-<cpu number> This option can be used to specify one or more CPUs to isolate from the general SMP balancing and scheduling algorithms. You can move a process onto or off an "isolated" CPU via the CPU affinity syscalls or cpuset. <cpu number> begins at 0 and the maximum value is "number of CPUs in system - 1". This option is the preferred way to isolate CPUs. The alternative -- manually setting the CPU mask of all tasks in the system -- can cause problems and suboptimal load balancer performance.
我已经使用了这两个加上几个项目的cset机制(顺便说一句,请原谅公然的自我提升:-)),我刚刚提交了一个名为Pontus Vision ThreadManager的工具的专利,提出了任何给定x86平台给任何给定的软件工作负载; 在客户现场进行测试后,我得到了非常好的结果(峰值延迟减少了270%),因此非常值得进行固定和CPU隔离。