目录
Linux、AIX等操作系统支持CPU亲和性(affinity)调度,即可以将进程/线程与CPU进行绑定,提高CPU cache的命中率,减少内存访问损耗,从而提升应用程序的运行性能。要实现CPU亲和性绑定,我们可以通过系统工具手动分配进程到不同的 CPU 上,也可以通过LSF将作业进程绑定到指定的CPU上。本文将以实例说明LSF如何实现对CPU亲和性绑定的控制。
如何启用LSF的CPU亲和性调度?
先介绍LSF中设置CPU亲和性调度的两个配置文件。
1. 通过lsb.hosts中的AFFINITY关键字来配置是否启用这台host的CPU亲和性调度功能:
HOST_NAME MXJ r1m AFFINITY
hostA ! () (Y)
2. 在lsb.modules中设置是否启用CPU亲和性调度插件schmod_affinity:
Begin PluginModule
SCH_PLUGIN RB_PLUGIN SCH_DISABLE_PHASES
schmod_default () ()
...
schmod_affinity () ()
End PluginModule
LSF也支持在Linux Cgroup的cpuset子系统上强制执行CPU绑定。当启用Linux Cgroup的CPU affinity绑定时,如果作业有亲和性资源需求,LSF将创建一个包含作业进程的Cgroup,并确保作业进程无法从该Cgroup中脱离。每个affinity作业的Cgroup只包括LSF分配的CPU和内存节点。
LSF会自动采集计算节点的CPU拓扑结构,包括NUMA、CPU socket、CPU core和硬件超线程HT等信息。用户提交作业时可以指定作业进程如何绑定到这些计算单元。
要启用Linux Cgroup的CPU和内存绑定,除了需要设置之前提到的lsb.hosts和lsb.modules外,还需要在 lsf.conf中配置以下3个参数:
LSF_PROCESS_TRACKING=Y
LSF_LINUX_CGROUP_ACCT=Y
LSB_RESOURCE_ENFORCE="cpu"
注释:
1)前两个参数用于在LSF中使能Cgroup,第三个参数用于使能CPU强制执行;
2)以上配置设置后,需要重启LSF集群来生效。
如何提交CPU/内存绑定作业?
LSF中通过bsub -R选项的affinity[]关键字来指定CPU亲和性资源需求,也可以在lsb.queues或lsb.applications中通过RES_REQ参数进行指定。
affinity[]资源需求字符串的详细语法如下:
affinity[pu_type[*count] | [pu_type(pu_num[,pu_options])[*count]] [:cpubind=numa | socket | core | thread] [:membind=localonly | localprefer] [:distribute=task_distribution]]
关于affinity关键字的详细说明可以参考下面的官方文档:
下面举几个例子说明一下:
示例1:
bsub -n 6 -R "span[hosts=1] affinity[core(1):distribute=pack]" myjob
该作业请求提供6个slots,以启动6个tasks在一个节点上运行。每个slot/task都映射到一个CPU core上。LSF会尽可能在单个NUMA或CPU socket上分配6个core。如果无法满足任务分配,则作业无法启动。
示例2:
bsub -n 6 -R "span[hosts=1] affinity[core(1):distribute=pack(socket=1)]" myjob
该作业请求6个slots,以启动6个tasks在一个节点上运行。每个slot/task映射到一个CPU core上,并且所有CPU core必须来自同一个CPU socket,否则作业无法启动。
示例3:
bsub -n 2 -R "span[hosts=1] affinity[core(2, same=socket, exclusive=(socket, injob))]" myjob
该作业请求分配一个计算节点上的两个slots,以启动两个tasks,每个slot映射到两个CPU core上。第一个slot/task的两个CPU core必须来自同一个CPU socket,第二个slot/task的两个CPU core必须位于另外一个CPU socket上。
示例4:
bsub -n 2 -R "affinity[core(2,same=socket,exclusive=(socket,injob|alljobs)): cpubind=socket]" myjob
该作业请求两个slots,以启动两个task,每个slot/task分配到不同的CPU socket上。每个task需要来自相同CPU socket的两个CPU core,并且在socket级别绑定每个task。分配的CPU socket是独占的,也就是说task之间不能共用相同的CPU socket。其它作业也不允许使用该作业占用的CPU socket。
如何查看LSF的亲和性资源及作业?
1. 查看具有affinity资源需求的作业信息
bjobs、bhist和bacct命令的-l选项再加上-aff选项可以显示作业的affinity资源信息,例如这是某个指定了affinity资源需求作业的bjobs -l -aff的输出:
AFFINITY:
CPU BINDING MEMORY BINDING
------------------------ --------------------
HOST TYPE LEVEL EXCL IDS POL NUMA SIZE
hostA core socket socket /0/0/0 local 0 16.7MB
hostA core socket socket /0/1/0 local 0 16.7MB
hostA core socket socket /0/2/0 local 0 16.7MB
hostA core socket socket /0/3/0 local 0 16.7MB
hostA core socket socket /0/4/0 local 0 16.7MB
hostA core socket socket /0/5/0 local 0 16.7MB
...
2. 查看计算节点的affinity信息
lshosts命令的-T选项可以显示计算节点的CPU拓扑信息。
bhosts命令的-aff选项可以显示计算节点的CPU拓扑信息和作业占用情况。
对于不支持CPU亲和性调度的计算节点,bhosts -aff输出中的内存信息会显示为破折号(-),且不显示CPU拓扑信息。
CPU亲和性调度举例
我们以下面的作业为例说明LSF的CPU亲和性调度。
bsub -n 2 -R "affinity[core(3,same=numa):cpubind=numa:membind=localonly]" myjob
上面的作业请求两个slots以启动两个tasks,每个task都需要使用同一个NUMA节点上的3个CPU core,并进行CPU和内存绑定。
1. 配置参数使能亲和性绑定,重启LSF集群使其生效
2. 提交作业
$ bsub -n 2 -R "affinity[core(3,same=numa):cpubind=numa:membind=localonly]" sleep 1h
Job <22045> is submitted to default queue <normal>.
3. 使用bjobs -l -aff和bhist -l -aff查看作业绑定的CPU信息
$ bjobs -l -aff
Job <22045>, User <usr1>, Project <default>, Status <RUN>, Queue <normal>,
Command <sleep 1h>, Share group charged </usr1>
Tue Nov 30 14:44:41: Submitted from host <host1>, CWD <$HOME>, 2 Task(s), Requ
ested Resources <affinity[core(3,same=numa):cpubind=numa:m
embind=localonly]>;
Tue Nov 30 14:44:42: Started 2 Task(s) on Host(s) <2*host1>, Allocated 6 Slot(
s) on Host(s) <6*host1>, Execution Home </home/usr1>,
Execution CWD </home/usr1>;
Tue Nov 30 14:44:49: Resource usage collected.
MEM: 2 Mbytes; SWAP: 0 Mbytes; NTHREAD: 4
PGID: 16606; PIDs: 16606 16607 16609
MEMORY USAGE:
MAX MEM: 2 Mbytes; AVG MEM: 2 Mbytes
SCHEDULING PARAMETERS:
r15s r1m r15m ut pg io ls it tmp swp mem
loadSched - - - - - - - - - - -
loadStop - - - - - - - - - - -
RESOURCE REQUIREMENT DETAILS:
Combined: select[type == local] order[r15s:pg] affinity[core(3,same=numa)*1:cp
ubind=numa:membind=localonly]
Effective: select[type == local] order[r15s:pg] affinity[core(3,same=numa)*1:c
pubind=numa:membind=localonly]
AFFINITY:
CPU BINDING MEMORY BINDING
------------------------ --------------------
HOST TYPE LEVEL EXCL IDS POL NUMA SIZE
host1 core numa - /0/0/0 local 0 0.0MB
/0/0/1
/0/0/2
host1 core numa - /0/0/3 local 0 0.0MB
/0/0/4
/0/0/5
$ bhist -l -aff
Job <22045>, User <usr1>, Project <default>, Command <sleep 1h>
Tue Nov 30 14:44:41: Submitted from host <host1>, to Queue <normal>, CWD <$HOM
E>, 2 Task(s), Requested Resources <affinity[core(3,same=n
uma):cpubind=numa:membind=localonly]>;
Tue Nov 30 14:44:42: Dispatched 2 Task(s) on Host(s) <2*host1>, Allocated 6 Sl
ot(s) on Host(s) <6*host1>, Effective RES_REQ <select[typ
e == local] order[r15s:pg] affinity[core(3,same=numa)*1:cp
ubind=numa:membind=localonly] >;
AFFINITY:
CPU BINDING MEMORY BINDING
------------------------ --------------------
HOST TYPE LEVEL EXCL IDS POL NUMA SIZE
host1 core numa - /0/0/0 local 0 0.0MB
/0/0/1
/0/0/2
host1 core numa - /0/0/3 local 0 0.0MB
/0/0/4
/0/0/5
Tue Nov 30 14:44:42: Starting (Pid 16606);
Tue Nov 30 14:44:42: Running with execution home </home/usr1>, Execution CW
D </home/usr1>, Execution Pid <16606>;
Summary of time in seconds spent in various states by Tue Nov 30 14:45:36
PEND PSUSP RUN USUSP SSUSP UNKWN TOTAL
1 0 54 0 0 0 55
作业完成后可以使用bacct -l -aff查看作业CPU和内存绑定信息。
4. 使用bhosts -aff查看作业绑定的CPU信息
$ bhosts -aff
Host[125.7G] host1
NUMA[0: 0M / 62.7G]
Socket0
core0(*0 16)
core1(*1 17)
core2(*2 18)
core3(*3 19)
core4(*4 20)
core5(*5 21)
core6(6 22)
core7(7 23)
NUMA[1: 0M / 62.9G]
Socket1
core0(8 24)
core1(9 25)
core2(10 26)
core3(11 27)
core4(12 28)
core5(13 29)
core6(14 30)
core7(15 31)
bhosts -aff输出中的*号表示有作业绑定了这个CPU core。
lshosts -T也可以查看节点的CPU拓扑信息。lshosts -T与bhosts -aff的区别在于前者不显示CPU是否有作业绑定,后者显示绑定信息。
$ lshosts -T
Host[125.7G] host1
NUMA[0: 62.7G]
Socket
core(0 16)
core(1 17)
core(2 18)
core(3 19)
core(4 20)
core(5 21)
core(6 22)
core(7 23)
NUMA[1: 62.9G]
Socket
core(8 24)
core(9 25)
core(10 26)
core(11 27)
core(12 28)
core(13 29)
core(14 30)
core(15 31)
由于篇幅有限,更多关于CPU亲和性调度的使用示例请参阅IBM官方文档,也欢迎给我们留言。
欢迎关注下方微信公众号【HPC常青园】,共同交流HPC集群管理经验和最佳实践。如果您有关于HPC集群的具体需求,欢迎邮件沟通交流:hpc@ivyent.cn。