一、孤立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. 24、去除右上方的debug图标

    class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext ...

  2. Blog Statistics Dec 1, 2021 - Dec 1, 2022

    1. Overview Data Date: Dec 1, 2021 - Dec 1, 2022 Number of articles: 51 All Platform Total Visits: 3 ...

  3. GaussDB(for Redis)游戏实践:玩家下线行为上报

    本文分享自华为云社区<GaussDB(for Redis) 游戏实践:玩家下线行为上报>,作者:GaussDB 数据库 为保护未成年人的身心健康,2007年国家推出网络游戏防沉迷系统,对未 ...

  4. 从相识到相惜:Redis与计算存储分离四部曲

    摘要:协议兼容问题.性能问题.数据备份问题.数据容量问题--这些都是数据库在使用过程中必然会遇见的问题.就好比选择结婚对象,你需要去对比不同的方面,最后选出最好的.最合适的. 近期全国两会正在轰轰烈烈 ...

  5. Python图像处理丨图像缩放、旋转、翻转与图像平移

    摘要:本篇文章主要讲解Python调用OpenCV实现图像位移操作.旋转和翻转效果,包括四部分知识:图像缩放.图像旋转.图像翻转.图像平移. 本文分享自华为云社区<[Python图像处理] 六. ...

  6. 顶会CIKM'21论文解读:基于图神经网络的人类行为轨迹恢复模型

    摘要:本文是由华为云数据库创新Lab联合电子科技大学数据与智能实验室发表在顶会CIKM'21的文章,该文章提出首个克服人类移动轨迹数据中普遍存在的多层次周期性.周期偏移现象以及数据稀疏问题的轨迹恢复模 ...

  7. 第三方测评:GaussDB(for Redis)稳定性与扩容表现

    摘要:本文将通过采用Redis Labs推出的多线程压测工具memtier_benchmark对比测试下GaussDB(for Redis) 和原生Redis的特性差异 本文分享自华为云社区<墨 ...

  8. POJ:Dungeon Master(BFS模板题)

    原题链接 思路: 正常的思路,只不过是将二维BFS换成三维的,也算是个模板题吧(PS:DFS超容易超时) #include<iostream> #include<queue> ...

  9. Codeforces Round #674 (Div. 3) (A - F题题解)

    A. Floor Number https://codeforces.com/contest/1426/problem/A 题意: 一个楼房房间号由 \(1\) 递增,一楼仅2个房间.给定一位用户的房 ...

  10. java调用本机的命令 如ping、打开文本等

    最近接触到用java代码调用主机的命令部分感觉有点意思整理总结一下 环境jdk1.8  操作系统win10,不用引入其他的包jdk自带的api就可以 一.java调用ping命令 import jav ...