一、孤立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


  1. taskset -p mask pid
  2. taskset -c [CPU NUMBER] -p PID

设置指定进程的CPU Affinity,对于孤立CPU,只有第一个CPU有效。

使用11,12,13,14,15号CPU运行进程


  1. taskset -c 11,12,13,14,15 python xx.py
  2. 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


  1. #define _GNU_SOURCE        
  2. #include <sched.h>
  3. int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
  4. 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、编程实现


  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. #include<sys/types.h>
  4. #include<sys/sysinfo.h>
  5. #include<unistd.h>
  6. #define __USE_GNU
  7. #include<sched.h>
  8. #include<ctype.h>
  9. #include<string.h>
  10. #include<pthread.h>
  11. #define THREAD_MAX_NUM 10  //1个CPU内的最多进程数
  12. int CPU_NUM = 0;  //cpu中核数
  13. int CPU = 3; // CPU编号
  14. void* threadFun(void* arg)
  15. {
  16.     cpu_set_t mask;  //CPU核的集合
  17.     CPU_ZERO(&mask);
  18.     // set CPU MASK
  19.     CPU_SET(CPU, &mask);
  20.     //设置当前进程的CPU Affinity
  21.     if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
  22.     {
  23.         printf("warning: could not set CPU affinity, continuing...\n");
  24.     }
  25.     cpu_set_t affinity;   //获取在集合中的CPU
  26.     CPU_ZERO(&affinity);
  27.     // 获取当前进程的CPU Affinity
  28.     if (sched_getaffinity(0, sizeof(affinity), &affinity) == -1)
  29.     {
  30.         printf("warning: cound not get Process affinity, continuing...\n");
  31.     }
  32.     int i = 0;
  33.     for (i = 0; i < CPU_NUM; i++)
  34.     {
  35.         if (CPU_ISSET(i, &affinity))//判断线程与哪个CPU有亲和力
  36.         {
  37.             printf("this thread %d is running processor : %d\n", *((int*)arg), i);
  38.         }
  39.     }
  40.     return NULL;
  41. }
  42. int main(int argc, char* argv[])
  43. {
  44.     int tid[THREAD_MAX_NUM];
  45.     pthread_t thread[THREAD_MAX_NUM];
  46.     // 获取核数
  47.     CPU_NUM = sysconf(_SC_NPROCESSORS_CONF);
  48.     printf("System has %i processor(s). \n", CPU_NUM);
  49.     int i = 0;
  50.     for(i=0;i<THREAD_MAX_NUM;i++)
  51.     {
  52.         tid[i] = i;
  53.         pthread_create(&thread[i],NULL,threadFun, &tid[i]);
  54.     }
  55.     for(i=0; i< THREAD_MAX_NUM; i++)
  56.     {
  57.         pthread_join(thread[i],NULL);
  58.     }
  59.     return 0;
  60. }

编译:

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


  1. taskset -pc CPU_NUMBER  PID
  2. taskset -p PID

查看进程的CPU Affinity

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

taskset -c CPU_NUMBER PROGRAM&

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

taskset -p PID

查看进程的CPU Affinity

四、线程绑定CPU

1、系统调用API


  1. #define _GNU_SOURCE            
  2. #include <pthread.h>
  3. int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
  4. int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset)

参数:

pthead:线程对象

cpusetsize:mask参数所指定数的长度,通常设定为sizeof(cpu_set_t)。

mask:CPU掩码

2、编程实现


  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. #include<sys/types.h>
  4. #include<sys/sysinfo.h>
  5. #include<unistd.h>
  6. #define __USE_GNU
  7. #include<sched.h>
  8. #include<ctype.h>
  9. #include<string.h>
  10. #include<pthread.h>
  11. #define THREAD_MAX_NUM 10  //1个CPU内的最多进程数
  12. int CPU_NUM = 0;  //cpu中核数
  13. int CPU = 3; // CPU编号
  14. void* threadFun(void* arg)
  15. {
  16.     cpu_set_t affinity;   //获取在集合中的CPU
  17.     CPU_ZERO(&affinity);
  18.     pthread_t thread = pthread_self();
  19.     // 获取当前进程的CPU Affinity
  20.     if (pthread_getaffinity_np(thread, sizeof(affinity), &affinity) == -1)
  21.     {
  22.         printf("warning: cound not get Process affinity, continuing...\n");
  23.     }
  24.     int i = 0;
  25.     for (i = 0; i < CPU_NUM; i++)
  26.     {
  27.         if (CPU_ISSET(i, &affinity))//判断线程与哪个CPU有亲和力
  28.         {
  29.             printf("this thread %d is running processor : %d\n", *((int*)arg), i);
  30.         }
  31.     }
  32.     return NULL;
  33. }
  34. int main(int argc, char* argv[])
  35. {
  36.     int tid[THREAD_MAX_NUM];
  37.     pthread_t thread[THREAD_MAX_NUM];
  38.     // 获取核数
  39.     CPU_NUM = sysconf(_SC_NPROCESSORS_CONF);
  40.     printf("System has %i processor(s). \n", CPU_NUM);
  41.     cpu_set_t mask;  //CPU核的集合
  42.     CPU_ZERO(&mask);
  43.     // set CPU MASK
  44.     CPU_SET(CPU, &mask);
  45.     int i = 0;
  46.     for(i=0;i<THREAD_MAX_NUM;i++)
  47.     {
  48.         tid[i] = i;
  49.         pthread_create(&thread[i],NULL,threadFun, &tid[i]);
  50.         //设置当前进程的CPU Affinity
  51.         if (pthread_setaffinity_np(thread[i], sizeof(mask), &mask) != 0)
  52.         {
  53.             printf("warning: could not set CPU affinity, continuing...\n");
  54.         }
  55.     }
  56.     for(i=0; i< THREAD_MAX_NUM; i++)
  57.     {
  58.         pthread_join(thread[i],NULL);
  59.     }
  60.     return 0;
  61. }

编译:

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绑定的更多相关文章

  1. Linux性能优化 第五章 性能工具:特定进程内存

    5.1 Linux内存子系统 在诊断内存性能问题的时候,也许有必要观察应用程序在内存子系统的不同层次上是怎样执行的.在顶层,操作系统决定如何利用交换内存和物理内存.它决定应用程序的哪一块地址空间将被放 ...

  2. 深挖计算机基础:Linux性能优化学习笔记

    参考极客时间专栏<Linux性能优化实战>学习笔记 一.CPU性能:13讲 Linux性能优化实战学习笔记:第二讲 Linux性能优化实战学习笔记:第三讲 Linux性能优化实战学习笔记: ...

  3. Linux 性能优化之 IO 子系统 系列 图

    http://blog.sina.com.cn/s/articlelist_1029388674_11_1.html Linux 性能优化之 IO 子系统(一) 本文介绍了对 Linux IO 子系统 ...

  4. Linux 性能优化解析

    前情概述 进程调度 老板 cpu 任劳任怨的打工仔 线程 工作在做什么 可运行队列 拥有的工作清单 上下文切换 和老板沟通以便得到老板的想法并及时调整自己的工作 中断 部分工作做完以后还需要及时向老板 ...

  5. Linux 性能优化排查工具

    下图1为 Linux 性能优化排查工具的总结 图1 诊断 CPU 工具 查看 CPU 核数 总核数 = 物理CPU个数 X 每颗物理CPU的核数 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU ...

  6. Linux性能优化从入门到实战:01 Linux性能优化学习路线

      我通过阅读各种相关书籍,从操作系统原理.到 Linux内核,再到硬件驱动程序等等.   把观察到的性能问题跟系统原理关联起来,特别是把系统从应用程序.库函数.系统调用.再到内核和硬件等不同的层级贯 ...

  7. Linux性能优化-平均负载

    Linux性能优化-平均负载 目录 Linux性能优化-平均负载 平均负载的含义 平均负载为多少时合理 平均负载与 CPU 使用率 平均负载案例分析 场景一:CPU 密集型进程 场景二:I/O 密集型 ...

  8. 如何学习Linux性能优化?

    如何学习Linux性能优化? 你是否也曾跟我一样,看了很多书.学了很多 Linux 性能工具,但在面对 Linux 性能问题时,还是束手无策?实际上,性能分析和优化始终是大多数软件工程师的一个痛点.但 ...

  9. Linux性能优化实战学习笔记:第五十讲

    一.上节回顾 上一节,我以 ksoftirqd CPU 使用率高的问题为例,带你一起学习了内核线程 CPU 使用率高时的分析方法.先简单回顾一下. 当碰到内核线程的资源使用异常时,很多常用的进程级性能 ...

  10. Linux性能优化实战学习笔记:第五十二讲

    一.上节回顾 上一节,我们一起学习了怎么使用动态追踪来观察应用程序和内核的行为.先简单来回顾一下.所谓动态追踪,就是在系统或者应用程序还在正常运行的时候,通过内核中提供的探针,来动态追踪它们的行为,从 ...

随机推荐

  1. 《华为云DTSE》期刊2023年第二季—HDC.Cloud 2023专刊

    本文分享自华为云社区<<华为云DTSE>期刊2023年第二季-HDC.Cloud 2023专刊>,作者: HuaweiCloudDeveloper . AI技术风起云涌,百家争 ...

  2. 云图说|Git云上仓库哪家好?一张图了解华为云代码托管服务

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要: 云办公时代已然到 ...

  3. Sechunter移动应用隐私合规检测详解

    摘要:本文简要介绍Sechunter移动应用隐私合规检测的方法步骤,以及目标检测技术在其中的应用. 本文分享自华为云社区<移动应用隐私合规检测简介及目标检测技术的应用>,作者:wolfre ...

  4. 火山引擎DataLeap的Catalog系统搜索实践(三):Learning to rank与后续工作

    Learning to rank Learning to rank主要分为数据收集,离线训练和在线预测三个部分.搜索系统是一个Data-driven system,因此火山引擎DataLeap的Cat ...

  5. 剖析字节案例,火山引擎 A/B 测试 DataTester 如何“嵌入”技术研发流程

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 日前,在 WOT 全球创新技术大会上,火山引擎 DataTester 技术负责人韩云飞做了关于字节跳动 A/B 测 ...

  6. Solon Aop 特色开发(6)新鲜货提取器,提取Bean的函数进行定制开发

    Solon,更小.更快.更自由!本系列专门介绍Solon Aop方面的特色: <Solon Aop 特色开发(1)注入或手动获取配置> <Solon Aop 特色开发(2)注入或手动 ...

  7. Jenkins Pipeline 流水线 - 声明式 Demo

    Jenkins Pipeline 流水线 流水线既能作为任务的本身,也能作为 Jenkinsfile 使用流水线可以让我们的任务从UI手动操作,转换为代码化,像dockerfile 一样.从shell ...

  8. 玩转Python:在Python中处理表格数据,几个非常流行且功能强大的库

    在Python中处理表格数据,有几个非常流行且功能强大的库.以下是一些最常用的库及其示例代码: 1. Pandas Pandas是一个开放源代码的.BSD许可的库,为Python编程语言提供高性能.易 ...

  9. ZOJ 3537 Cake (凸包 + 区间DP && 最优三角形剖分)

    题目链接:Here 题意: 给定 \(n\)​​ 个点的坐标,先问这些点能否组成一个凸包,如是凸包,问用不相交的线来切这个凸包使得凸包只由三角形组成,根据 \(cost_{i, j} = |x_i + ...

  10. 0x62 图论-最小生成树

    A题:走廊泼水节 链接:https://ac.nowcoder.com/acm/contest/1056/A 题目描述 给定一棵N个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小 ...