[转帖]Linux性能优化(十五)——CPU绑定
一、孤立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,重启系统生效。
-
// Ubuntu
-
update-grub
-
update-grub2
-
// CentOS 7
-
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
运行结果:
-
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
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
运行结果:
-
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

QQ群名片
[转帖]Linux性能优化(十五)——CPU绑定的更多相关文章
- Linux性能优化 第五章 性能工具:特定进程内存
5.1 Linux内存子系统 在诊断内存性能问题的时候,也许有必要观察应用程序在内存子系统的不同层次上是怎样执行的.在顶层,操作系统决定如何利用交换内存和物理内存.它决定应用程序的哪一块地址空间将被放 ...
- 深挖计算机基础:Linux性能优化学习笔记
参考极客时间专栏<Linux性能优化实战>学习笔记 一.CPU性能:13讲 Linux性能优化实战学习笔记:第二讲 Linux性能优化实战学习笔记:第三讲 Linux性能优化实战学习笔记: ...
- Linux 性能优化之 IO 子系统 系列 图
http://blog.sina.com.cn/s/articlelist_1029388674_11_1.html Linux 性能优化之 IO 子系统(一) 本文介绍了对 Linux IO 子系统 ...
- Linux 性能优化解析
前情概述 进程调度 老板 cpu 任劳任怨的打工仔 线程 工作在做什么 可运行队列 拥有的工作清单 上下文切换 和老板沟通以便得到老板的想法并及时调整自己的工作 中断 部分工作做完以后还需要及时向老板 ...
- Linux 性能优化排查工具
下图1为 Linux 性能优化排查工具的总结 图1 诊断 CPU 工具 查看 CPU 核数 总核数 = 物理CPU个数 X 每颗物理CPU的核数 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU ...
- Linux性能优化从入门到实战:01 Linux性能优化学习路线
我通过阅读各种相关书籍,从操作系统原理.到 Linux内核,再到硬件驱动程序等等. 把观察到的性能问题跟系统原理关联起来,特别是把系统从应用程序.库函数.系统调用.再到内核和硬件等不同的层级贯 ...
- Linux性能优化-平均负载
Linux性能优化-平均负载 目录 Linux性能优化-平均负载 平均负载的含义 平均负载为多少时合理 平均负载与 CPU 使用率 平均负载案例分析 场景一:CPU 密集型进程 场景二:I/O 密集型 ...
- 如何学习Linux性能优化?
如何学习Linux性能优化? 你是否也曾跟我一样,看了很多书.学了很多 Linux 性能工具,但在面对 Linux 性能问题时,还是束手无策?实际上,性能分析和优化始终是大多数软件工程师的一个痛点.但 ...
- Linux性能优化实战学习笔记:第五十讲
一.上节回顾 上一节,我以 ksoftirqd CPU 使用率高的问题为例,带你一起学习了内核线程 CPU 使用率高时的分析方法.先简单回顾一下. 当碰到内核线程的资源使用异常时,很多常用的进程级性能 ...
- Linux性能优化实战学习笔记:第五十二讲
一.上节回顾 上一节,我们一起学习了怎么使用动态追踪来观察应用程序和内核的行为.先简单来回顾一下.所谓动态追踪,就是在系统或者应用程序还在正常运行的时候,通过内核中提供的探针,来动态追踪它们的行为,从 ...
随机推荐
- 大模型高效开发的秘密武器:大模型低参微调套件MindSpore PET
摘要:本文介绍大模型低参微调套件--MindSpore PET. 本文分享自华为云社区<大模型高效开发的秘密武器--大模型低参微调套件MindSpore PET篇>,作者:yd_28087 ...
- 连Python都不熟也能跑通AI人脸识别?“隐藏Boss”竟是它!
摘要:先把AI人脸识别跑起来,然后研究它是如何实现的,整个过程中确实收获不少.所谓先跟着做,再跟着学,实践与理论结合,自己感觉有理解了一些基础概念入个门,在此分享一下自己的捣鼓经验. 1.买台小&qu ...
- 带你认识大模型训练关键算法:分布式训练Allreduce算法
摘要:现在的模型以及其参数愈加复杂,仅仅一两张的卡已经无法满足现如今训练规模的要求,分布式训练应运而生. 本文分享自华为云社区<分布式训练Allreduce算法>,原文作者:我抽签必中. ...
- 分析内部运行机制,教你解决Redis性能问题
摘要:聚焦Redis的性能分析,思考Redis 可以通过哪些机制来提高性能,当性能瓶颈发生的时候,我们又能做出哪些优化策略,最终确保业务系统的稳定运行. 本文分享自华为云社区<分析内部运行机制, ...
- Git hooks与自动化部署
好的 commit message 是至关重要的,如果随意编写 log,带来的后果可小可大,但是无论大小都影响了开发的效率和回朔的难度,所以有必要进行 log 规范化检查. 通过自定义的commit ...
- DarkMode(2):深色模式解决方案——css颜色变量实现Dark Mode
暗黑模式实现,最初的设计,就是参考之前的主题模式.所谓多套主题/配色/皮肤,就是我们很常见的换肤功能.换肤简单的实现就是更换 css实现不同样式呈现不同肤色. 之前做不同颜色的皮肤,暗黑模式可以单做其 ...
- 火山引擎在行为分析场景下的ClickHouse JOIN优化
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 背景 火山引擎增长分析DataFinder基于ClickHouse来进行行为日志的分析,ClickHouse的主要 ...
- MongoDB 内存占用过大
不同的版本配置项可能不同:本文使用的 mongodb-win32-x86_64-2012plus-4.2.11-signed.msi mongod.cfg 默认占用内存为 0.5*(物理内存-1)如 ...
- WebService rwsp:NoRunningCommunicationPointAvailable
SoapUI 调WebService 报 No running communication point is configured to process this request. 错误 检查入参是否 ...
- forms组件渲染标签 form表单展示信息 forms组件校验方式 form组件源码 modelform组件 django自定义中间件
目录 forms组件渲染标签 方式一:全自动渲染表单 as_p as_ul as_table 表单类的label标签 方式二:手动渲染 方式三:for循环表单对象(推荐) 查看源码 渲染标签的注意事项 ...
