针对CPU密集型的任务,CPU负载较高,推荐设置CPU Affinity,以提升任务执行效率,避免CPU进行上下文切换,提升CPU Cache命中率。
默认状况下,Linux内核调度器可使用任意CPU核心,若是特定任务(进程/线程)须要独占一个CPU核心而且不想让其它任务(进程/线程)使用时,能够把指定CPU孤立出来,不让其它进程使用。python
孤立CPU能够有效地提升孤立CPU上任务运行的实时性,在保证孤立CPU上任务运行的同时会减小了其它任务能够运行的CPU资源,所以须要对计算机CPU资源进行规划。linux
Linux Kernel中isolcpus启动参数用于在SMP均衡调度算法中将一个或多个CPU孤立出来,经过CPU Affinity设置将指定进程置于孤立CPU运行。isolcpus= cpu_number [, cpu_number ,...]
(1)修改grub配置文件
默认grub配置为/etc/default/grub,GRUB_CMDLINE_LINUX值中加入isolcpus=11,12,13,14,15,全部CPU核心必须用逗号进行分隔,不支持区域范围。GRUB_CMDLINE_LINUX="isolcpus=1,2 crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet"
(2)更新grub
从新生成grub引导文件/boot/grub/grub.cfg,重启系统生效。算法
update-grub update-grub2 grub-mkconfig -o /boot/grub/grub.cfg
一旦Linux Kernel使用isolcpus参数启动,Linux Kernel任务均衡调度器不会再将进程调度给指定CPU核心,用户一般须要使用taskset或cset命令将进程绑定到CPU核心。编程
超线程技术(Hyper-Threading)是利用特殊的硬件指令,把两个逻辑内核(CPU core)模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,进而兼容多线程操做系统和软件,减小了CPU的闲置时间,提升CPU的运行效率。
物理CPU是计算机主板上安装的CPU。
逻辑CPU是一颗物理CPU上的物理CPU核心,一般一颗物理CPU有多颗物理内核,即有多个逻辑CPU。若是支持Intel超线程技术(HT),能够在逻辑CPU上再分一倍数量的CPU Core。cat /proc/cpuinfo|grep "physical id"|sort -u|wc -l
查看物理CPU个数cat /proc/cpuinfo|grep "cpu cores"|uniq
查看每一个物理CPU中core的个数(即核数)cat /proc/cpuinfo|grep "processor"|wc -l
查看逻辑CPU的个数cat /proc/cpuinfo|grep "name"|cut -f2 -d:|uniq
查看CPU的名称型号ps -eo pid,args,psr
查看进程运行的逻辑CPU缓存
CPU绑定是对进程或线程设置相应的CPU Affinity,确保进程或线程只会在设置有相应标志位的CPU上运行,进而提升应用程序对CPU的使用效率。若是应用能够在多个CPU上运行,操做系统会在CPU之间频繁切换应用,引发CPU缓存失效,下降缓存的命中率,致使CPU使用效率降低。使用CPU绑定技术能够在必定程度上会避免CPU Cache失效,提高系统性能。
CPU affinity是一种调度属性(scheduler property),能够将一个进程绑定到一个或一组CPU上。
在SMP(Symmetric Multi-Processing对称多处理)架构下,Linux调度器(scheduler)会根据CPU affinity设置让指定的进程运行在绑定的CPU上,而不会在其它CPU上运行.,
Linux调度器一样支持天然CPU亲和性(natural CPU affinity): 调度器会试图保持进程在相同的CPU上运行, 这意味着进程一般不会在处理器之间频繁迁移,进程迁移的频率小就意味着产生的负载小。
由于程序的做者比调度器更了解程序,因此咱们能够手动地为其分配CPU核,而不会过多地占用CPU0,或是让咱们关键进程和一堆别的进程挤在一块儿,全部设置CPU亲和性可使某些程序提升性能。
Linux内核进程调度器天生具备软CPU亲和性(affinity)特性,进程一般不会在处理器之间频繁迁移。
查看全部进程CPU分配状况ps -eo pid,cmd,psr
查看进程的全部线程的CPU分配状况ps -To 'pid,lwp,psr,cmd' -p [PID]
多线程
将进程/线程与CPU绑定,能够显著提升CPU Cache命中率,从而减小内存访问损耗,提升应用性能。我以为在NUMA架构下,这个操做对系统运行速度的提高有较大的意义,而在SMP架构下,这个提高可能就比较小。这主要是由于二者对于cache、总线这些资源的分配使用方式不一样形成的,NUMA架构下,每一个CPU有本身的一套资源体系;SMP架构下,每一个核心仍是须要共享这些资源的。
每一个CPU核运行一个进程的时候,因为每一个进程的资源都独立,因此CPU核心之间切换的时候无需考虑上下文;每一个CPU核运行一个线程的时候,有时线程之间须要共享资源,因此共享资源必须从CPU的一个核心被复制到另一个核心,形成额外开销。架构
yum install util-linux
安装taskset工具taskset [options] [mask] -p pid
查看进程的CPU Affinity,使用-p选项指定PID,默认打印十六进制数,若是指定-cp选项打印CPU核列表。3的二进制形式是0011,对应-cp打印0和1,表示进程只能运行在CPU的第0个核和第1个核。taskset -c -p pid
查看指定进程的CPU Affinityide
taskset -p mask pid taskset -c [CPU NUMBER] -p PID
设置指定进程的CPU Affinity,对于孤立CPU,只有第一个CPU有效。
使用11,12,13,14,15号CPU运行进程工具
taskset -c 11,12,13,14,15 python xx.py taskset -c 11-15 python xx.py
Docker容器中,孤立CPU仍然能够被使用;建立Docker容器时能够经过参数--cpuset-cpus指定容器只能使用哪些CPU,实现Docker容器内孤立CPU。性能
cset set --cpu CPU CPUSET NAME
定义CPU核心集合,对于独立CPU,只有第一个CPU核心有效。cset proc --move --pid=PID,...,PID --toset=CPUSET NAME
移动多个进程到指定CPU集合
#define _GNU_SOURCE #include <sched.h> int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
参数:
pid:进程号,若是pid值为0,则表示指定当前进程。
cpusetsize:mask参数所指定数的长度,一般设定为sizeof(cpu_set_t)。
mask:CPU掩码
#include<stdlib.h> #include<stdio.h> #include<sys/types.h> #include<sys/sysinfo.h> #include<unistd.h> #define __USE_GNU #include<sched.h> #include<ctype.h> #include<string.h> #include<pthread.h> #define THREAD_MAX_NUM 10 //1个CPU内的最多进程数 int CPU_NUM = 0; //cpu中核数 int CPU = 3; // CPU编号 void* threadFun(void* arg) { cpu_set_t mask; //CPU核的集合 CPU_ZERO(&mask); // set CPU MASK CPU_SET(CPU, &mask); //设置当前进程的CPU Affinity if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("warning: could not set CPU affinity, continuing...\n"); } cpu_set_t affinity; //获取在集合中的CPU CPU_ZERO(&affinity); // 获取当前进程的CPU Affinity if (sched_getaffinity(0, sizeof(affinity), &affinity) == -1) { printf("warning: cound not get Process affinity, continuing...\n"); } int i = 0; for (i = 0; i < CPU_NUM; i++) { if (CPU_ISSET(i, &affinity))//判断线程与哪一个CPU有亲和力 { printf("this thread %d is running processor : %d\n", *((int*)arg), i); } } return NULL; } int main(int argc, char* argv[]) { int tid[THREAD_MAX_NUM]; pthread_t thread[THREAD_MAX_NUM]; // 获取核数 CPU_NUM = sysconf(_SC_NPROCESSORS_CONF); printf("System has %i processor(s). \n", CPU_NUM); int i = 0; for(i=0;i<THREAD_MAX_NUM;i++) { tid[i] = i; pthread_create(&thread[i],NULL,threadFun, &tid[i]); } for(i=0; i< THREAD_MAX_NUM; i++) { pthread_join(thread[i],NULL); } return 0; }
编译:gcc -o test test.c -pthread
运行结果:
System has 4 processor(s). this thread 1 is running processor : 3 this thread 0 is running processor : 3 this thread 4 is running processor : 3 this thread 9 is running processor : 3 this thread 7 is running processor : 3 this thread 5 is running processor : 3 this thread 6 is running processor : 3 this thread 8 is running processor : 3 this thread 3 is running processor : 3 this thread 2 is running processor : 3
(1)绑定进程至指定CPU
taskset -pc CPU_NUMBER PID taskset -p PID
查看进程的CPU Affinity
(2)进程启动时绑定至CPUtaskset -c CPU_NUMBER PROGRAM&
启动PROGRAM程序后台运行,绑定进程至CPU_NUMBER核心,taskset -p PID
查看进程的CPU Affinity
#define _GNU_SOURCE #include <pthread.h> int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset); int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset)
参数:
pthead:线程对象
cpusetsize:mask参数所指定数的长度,一般设定为sizeof(cpu_set_t)。
mask:CPU掩码
#include<stdlib.h> #include<stdio.h> #include<sys/types.h> #include<sys/sysinfo.h> #include<unistd.h> #define __USE_GNU #include<sched.h> #include<ctype.h> #include<string.h> #include<pthread.h> #define THREAD_MAX_NUM 10 //1个CPU内的最多进程数 int CPU_NUM = 0; //cpu中核数 int CPU = 3; // CPU编号 void* threadFun(void* arg) { cpu_set_t affinity; //获取在集合中的CPU CPU_ZERO(&affinity); pthread_t thread = pthread_self(); // 获取当前进程的CPU Affinity if (pthread_getaffinity_np(thread, sizeof(affinity), &affinity) == -1) { printf("warning: cound not get Process affinity, continuing...\n"); } int i = 0; for (i = 0; i < CPU_NUM; i++) { if (CPU_ISSET(i, &affinity))//判断线程与哪一个CPU有亲和力 { printf("this thread %d is running processor : %d\n", *((int*)arg), i); } } return NULL; } int main(int argc, char* argv[]) { int tid[THREAD_MAX_NUM]; pthread_t thread[THREAD_MAX_NUM]; // 获取核数 CPU_NUM = sysconf(_SC_NPROCESSORS_CONF); printf("System has %i processor(s). \n", CPU_NUM); cpu_set_t mask; //CPU核的集合 CPU_ZERO(&mask); // set CPU MASK CPU_SET(CPU, &mask); int i = 0; for(i=0;i<THREAD_MAX_NUM;i++) { tid[i] = i; pthread_create(&thread[i],NULL,threadFun, &tid[i]); //设置当前进程的CPU Affinity if (pthread_setaffinity_np(thread[i], sizeof(mask), &mask) != 0) { printf("warning: could not set CPU affinity, continuing...\n"); } } for(i=0; i< THREAD_MAX_NUM; i++) { pthread_join(thread[i],NULL); } return 0; }
编译:gcc -o test test.c -pthread
运行结果:
System has 4 processor(s). this thread 0 is running processor : 3 this thread 1 is running processor : 3 this thread 2 is running processor : 3 this thread 3 is running processor : 3 this thread 5 is running processor : 3 this thread 4 is running processor : 3 this thread 6 is running processor : 3 this thread 9 is running processor : 3 this thread 7 is running processor : 3 this thread 8 is running processor : 3