[转帖]Linux性能优化(十五)——CPU绑定

linux,性能,优化,十五,cpu,绑定 · 浏览次数 : 0

小编点评

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 4 is running processor : 3 this thread 5 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 this thread 5 is running processor : 3

正文

一、孤立CPU

1、孤立CPU简介

针对CPU密集型的任务,CPU负载较高,推荐设置CPU Affinity,以提高任务执行效率,避免CPU进行上下文切换,提高CPU Cache命中率

默认情况下,Linux内核调度器可以使用任意CPU核心,如果特定任务(进程/线程)需要独占一个CPU核心并且不想让其它任务(进程/线程)使用时,可以把指定CPU孤立出来,不让其它进程使用。

2、孤立CPU的特点

孤立CPU可以有效地提高孤立CPU上任务运行的实时性,在保证孤立CPU上任务运行的同时会减少了其它任务可以运行的CPU资源,因此需要对计算机CPU资源进行规划。

3、孤立CPU设置

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,重启系统生效。

  1. // Ubuntu
  2. update-grub
  3. update-grub2
  4. // CentOS 7
  5. grub-mkconfig -o /boot/grub2/grub.cfg
复制

一旦Linux Kernel使用isolcpus参数启动,Linux Kernel任务均衡调度器不会再将进程调度给指定CPU核心,用户通常需要使用taskset或cset命令将进程绑定到CPU核心。

二、CPU绑定简介

1、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

2、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]
复制

3、CPU绑定的特点

将进程/线程与CPU绑定,可以显著提高CPU Cache命中率,从而减少内存访问损耗,提高应用性能。我觉得在NUMA架构下,这个操作对系统运行速度的提升有较大的意义,而在SMP架构下,这个提升可能就比较小。这主要是因为两者对于cache、总线这些资源的分配使用方式不同造成的,NUMA架构下,每个CPU有自己的一套资源体系;SMP架构下,每个核心还是需要共享这些资源的。

每个CPU核运行一个进程的时候,由于每个进程的资源都独立,所以CPU核心之间切换的时候无需考虑上下文;每个CPU核运行一个线程的时候,有时线程之间需要共享资源,所以共享资源必须从CPU的一个核心被复制到另外一个核心,造成额外开销。

4、taskset绑定进程

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 Affinity

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。

5、cset绑定进程

cset set --cpu CPU CPUSET NAME
复制

定义CPU核心集合,对于独立CPU,只有第一个CPU核心有效。

cset proc --move --pid=PID,...,PID --toset=CPUSET NAME
复制

移动多个进程到指定CPU集合

三、进程绑定CPU

1、系统调用API

#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掩码

2、编程实现

#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
复制

运行结果:

  1. System has 4 processor(s).
  2. this thread 1 is running processor : 3
  3. this thread 0 is running processor : 3
  4. this thread 4 is running processor : 3
  5. this thread 9 is running processor : 3
  6. this thread 7 is running processor : 3
  7. this thread 5 is running processor : 3
  8. this thread 6 is running processor : 3
  9. this thread 8 is running processor : 3
  10. this thread 3 is running processor : 3
  11. this thread 2 is running processor : 3
复制

3、taskset绑定进程至CPU

(1)绑定进程至指定CPU

taskset -pc CPU_NUMBER  PID taskset -p PID
复制

查看进程的CPU Affinity

(2)进程启动时绑定至CPU

taskset -c CPU_NUMBER PROGRAM&
复制

启动PROGRAM程序后台运行,绑定进程至CPU_NUMBER核心,

taskset -p PID
复制

查看进程的CPU Affinity

四、线程绑定CPU

1、系统调用API

#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掩码

2、编程实现

#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
复制

运行结果:

  1. System has 4 processor(s).
  2. this thread 0 is running processor : 3
  3. this thread 1 is running processor : 3
  4. this thread 2 is running processor : 3
  5. this thread 3 is running processor : 3
  6. this thread 5 is running processor : 3
  7. this thread 4 is running processor : 3
  8. this thread 6 is running processor : 3
  9. this thread 9 is running processor : 3
  10. this thread 7 is running processor : 3
  11. this thread 8 is running processor : 3
复制

文章知识点与官方知识档案匹配,可进一步学习相关知识
CS入门技能树Linux入门初识Linux30020 人正在系统学习中
量化IT技术交流群
QQ群名片

与[转帖]Linux性能优化(十五)——CPU绑定相似的内容:

[转帖]Linux性能优化(十五)——CPU绑定

一、孤立CPU 1、孤立CPU简介 针对CPU密集型的任务,CPU负载较高,推荐设置CPU Affinity,以提高任务执行效率,避免CPU进行上下文切换,提高CPU Cache命中率。 默认情况下,Linux内核调度器可以使用任意CPU核心,如果特定任务(进程/线程)需要独占一个CPU核心并且不想

【转帖】Linux性能优化(十六)——中断绑定

一、中断绑定简介 1、中断简介 计算机中,中断是一种电信号,由硬件产生并直接送到中断控制器上,再由中断控制器向CPU发送中断信号,CPU检测到信号后,中断当前工作转而处理中断信号。CPU会通知操作系统已经产生中断,操作系统就会对中断进行处理。常见的中断控制器有两种:可编程中断控制器8259A和高级可

[转帖]Linux性能优化(十)——CPU性能分析工具

Linux性能优化(十)——CPU性能分析工具 https://blog.51cto.com/u_9291927/2594169 一、CPU性能指标 1、CPU使用率 CPU使用率是最常见的一个性能指标,描述了非空闲时间占总CPU 时间的百分比,根据CPU上运行任务的不同,分为用户CPU、系统CPU

[转帖]Linux性能优化(十一)——CPU性能优化原理

Linux性能优化(十一)——CPU性能优化原理 https://blog.51cto.com/u_9291927/2594259 一、CPU上下文切换 1、CPU上下文 Linux是多任务操作系统,支持远大于CPU数量的任务同时运行。在每个任务运行前,CPU需要知道任务从哪里加载、从哪里开始运行,

[转帖]Linux性能优化(十二)——CPU性能调优

Linux性能优化(十二)——CPU性能调优 https://blog.51cto.com/u_9291927/2594259 一、应用程序优化 (1)编译器优化。适当开启编译器优化选项,在编译阶段提升性能。gcc提供优化选项-On会自动对应用程序的代码进行优化。(2)算法优化。使用复杂度更低的算法

【转帖】Linux性能优化(十四)——CPU Cache

一、CPU Cache 1、CPU Cache简介 CPU Cache是位于CPU与内存之间的临时存储器,容量比内存小但交换速度却比内存要快得多。Cache的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,会使CPU花费很长时间等待数据到来或把数

【转帖】Linux性能优化(十三)——CPU性能测试

一、CPU上下文切换测试场景 使用sysbench模拟多线程调度: sysbench --threads=10 --time=300 threads run 使用vmstat查看CPU上下文切换: cs列上下文切换次数超过150万次。 r列就绪队列长度最大达到8,超过系统CPU的个数4,存在大量的C

[转帖]《Linux性能优化实战》笔记(十五)—— 磁盘IO的工作原理

前一篇介绍了文件系统的工作原理,这一篇来看看磁盘IO的工作原理 一、 磁盘 1. 按存储介质分类 磁盘是可以持久化存储的设备,根据存储介质的不同,常见磁盘可以分为两类:机械磁盘和固态磁盘。 机械磁盘,也称为硬盘驱动器(Hard Disk Driver,HDD),主要由盘片和读写磁头组成,数据存储在盘

[转帖]《Linux性能优化实战》笔记(十九)—— DNS 解析原理与故障案例分析

一、 域名与 DNS 解析 域名主要是为了方便让人记住,而 IP 地址是机器间的通信的真正机制。以 time.geekbang.org 为例,最后面的 org 是顶级域名,中间的 geekbang 是二级域名,而最左边的 time 则是三级域名。点(.)是所有域名的根,所有域名都以点作为后缀。 把域

[转帖]《Linux性能优化实战》笔记(十七)—— Linux网络基础与性能指标

一、 网络模型 1. OSI 网络模型(七层) 为了解决网络互联中异构设备的兼容性问题,并解耦复杂的网络包处理流程,OSI 模型把网络互联的框架分为七层,每个层负责不同的功能。其中, 应用层,负责为应用程序提供统一的接口。表示层,负责把数据转换成兼容接收系统的格式。会话层,负责维护计算机之间的通信连