linux cpu核绑定命令,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,重启系统生效。

update-grub

update-grub2

grub-mkconfig -o /boot/grub/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

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

#include

#include

#include

#include

#define __USE_GNU

#include

#include

#include

#include

#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

{

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

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

#include

#include

#include

#include

#define __USE_GNU

#include

#include

#include

#include

#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

{

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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本书介绍了Linux下图形用户接口(GUI)编程技术。全书共18章,分五个部分。第一部分介绍Linux GUI编程架构以及编程基础知识,第二部分介绍Linux 编程常用C语言函数库glibc、构件库Gtk+、Gnome,第三部分介绍Linux下的GUI生成器Glade,第四部分介绍Linux编程调试工具gdb及xxgdb。第五部分包括三个附录,附录A是书中使用的示例GnomeHello的源代码,附录B介绍了一些与Gtk+/Gnome编程相关的在线资源,附录C是Gtk+/Gnome对象的简要介绍。本书中的Gtk+构件示例都来自于GTK 1.2.3软件包的示例。如果下载并安装了GTK 1.2.3软件包,则能够在展开的源代码目录下找到这些示例代码。本书适用于有Linux使用经验及C语言编程基础的读者阅读。 目 录 前言 第一部分 Linux GUI编程框架及编程基础 第1章 Linux软件开发概述 1 1.1 关于Linux 1 1.2 关于Linux的桌面环境 2 1.3 Linux系统中的软件开发 3 1.3.1 开发所使用的库 3 1.3.2 Gnome的开发结构 4 1.4 开发Linux应用程序的编程语言 和编程工具 6 1.5 本书的结构 7 第2章 Gtk+/Gnome开发简介 8 2.1 安装Gtk+/Gnome库 8 2.2 第一个Gtk+应用程序 9 2.2.1 一个什么也不能做的窗口 9 2.2.2 示例代码的含义 9 2.2.3 GTK的Hello World 10 2.2.4 Gtk+的信号和回调函数原理 12 2.2.5 Hello World代码解释 14 2.2.6 运行helloworld 17 2.3 Gnome应用程序 17 2.4 GNU C 编译器 18 2.4.1 使用 gcc 18 2.4.2 gcc 选项 18 2.5 初始化库 19 2.6 用popt分析参数 20 2.6.1 参数分析方法 20 2.6.2 GnomeHello程序的参数分析 22 2.7 国际化 25 2.8 保存配置信息 27 2.8.1 读出存储的配置数据 28 2.8.2 在配置文件中存储数据 30 2.8.3 配置文件迭代器 30 2.8.4 节迭代器 33 2.8.5 其他的配置文件操作 33 2.9 会话管理 34 2.10 Gtk+的主循环 36 2.10.1 主循环基本知识 36 2.10.2 退出函数 36 2.10.3 Timeout函数 37 2.10.4 idle函数 37 2.10.5 输入函数 38 2.11 编译应用程序 39 2.11.1 生成源代码树 39 2.11.2 configure.in文件 41 2.11.3 Makefile.am文件 43 2.11.4 安装支持文件 44 第二部分 Linux 编程常用C 语言 函数库及构件库 第3章 glib库简介 49 3.1 类型定义 49 3.2 glib的宏 49 3.2.1 常用宏 49 3.2.2 调试宏 50 3.3 内存管理 52 3.4 字符串处理 53 3.5 数据结构 55 3.5.1 链表 55 3.5.2 树 59 3.5.3 哈希表 63 3.6 GString 65 3.7 计时器函数 66 3.8 错误处理函数 67 3.9 其他实用函数 67 第4章 构件定位 69 4.1 构件的显现、映射和显示 69 4.2 其他的构件概念 70 4.3 构件的类型转换 72 4.4 组装构件 72 4.4.1 尺寸分配 73 4.4.2 GtkWindow构件 74 4.4.3 GtkBox 76 4.4.4 表格构件GtkTable 79 4.4.5 固定容器构件GtkFixed 83 4.4.6 布局容器构件GtkLayout 85 第5章 按钮构件 87 5.1 普通按钮GtkButton 87 5.2 开关按钮GtkToggleButton 90 5.3 检查按钮GtkCheckButton 91 5.4 无线按钮GtkRadioButton 91 第6章 调整对象 95 6.1 创建一个调整对象 95 6.2 使用调整对象 95 6.3 调整对象内部机制 96 第7章 文本构件GtkText 98 7.1 创建、配置文本构件 98 7.2 操作文本 99 7.3 键盘快捷键 100 7.4 GtkText示例 100 第8章 范围构件GtkRange 105 8.1 滚动条构件GtkScrollBar 105 8.2 比例构件GtkScale 105 8.2.1 函数和信号 105 8.2.2 常用的范围函数 106 8.2.3 键盘和鼠标绑定 107 8.2.4 示例 107 第9章 杂项构件 114 9.1 标签构件GtkLabel 114 9.2 箭头构件GtkArrow 117 9.3 工具提示对象GtkTooltips 119 9.4 进度条构件GtkProgressBar 120 9.5 对话框构件 126 9.6 pixmap 127 9.7 标尺构件GtkRuler 134 9.8 文本输入构件GtkEntry 137 9.9 微调按钮构件GtkSpinButton 140 9.10 组合框GtkCombo 146 9.11 日历构件GtkCalendar 148 9.12 颜色选择构件GtkColorSelect 158 9.13 文件选择构件GtkFileSelect 162 第10章 容器构件GtkContainer 165 10.1 事件盒构件GtkEventBox 165 10.2 对齐构件GtkAlignment 166 10.3 框架构件GtkFrame 167 10.4 比例框架构件GtkAspectFrame 169 10.5 分栏窗口构件GtkPanedWindow 170 10.6 视角构件GtkViewport 174 10.7 滚动窗口构件GtkScrolled Window 175 10.8 按钮盒构件GtkButtonBox 177 10.9 工具条构件GtkToolbar 181 10.10 笔记本构件GtkNotebook 187 第11章 分栏列表构件GtkCList 193 11.1 创建分栏列表构件GtkCList 193 11.2 操作模式 193 11.3 操作分栏列表构件列标题 194 11.4 操纵列表 194 11.5 向列表中添加行 196 11.6 在单元格中设置文本和pixmap 图片 197 11.7 存储数据指针 198 11.8 处理选择 198 11.9 信号 199 11.10 GtkCList示例 199 第12章 树构件 204 12.1 创建新树构件 204 12.1.1 添加一个子树 204 12.1.2 处理选中的列表 205 12.1.3 树构件内部机制 205 12.1.4 信号 206 12.1.5 函数和宏 206 12.2 树项构件GtkTreeItem 208 12.2.1 信号 209 12.2.2 函数和宏 210 12.3 树构件示例 210 第13章 GnomeApp构件和GnomeUIInfo 215 13.1 主窗口GnomeApp 215 13.2 GnomeUIInfo 216 13.2.1 创建GnomeUIInfo 216 13.2.2 将GnomeUIInfo转换为构件 218 第14章 状态条构件 221 14.1 状态条构件简介 221 14.2 GnomeAppBar构件 221 14.3 状态条构件GtkStatusbar 222 第15章 对话框 225 15.1 GnomeDialog构件 225 15.1.1 创建对话框 225 15.1.2 填充对话框 226 15.1.3 处理GnomeDialog的信号 226 15.1.4 最后的修饰 227 15.2 模态对话框 229 15.3 一个对话框示例 230 15.4 特殊对话框 231 15.4.1 GnomeAbout 231 15.4.2 GnomePropertyBox—属性框 233 15.4.3 GnomeMessageBox—消息框 234 第16章 GDK 基础 236 16.1 GDK和Xlib 236 16.2 GdkWindow 237 16.2.1 GdkWindow和GtkWidget 237 16.2.2 GdkWindow属性 238 16.3 视件和颜色表 240 16.3.1 GdkVisual 240 16.3.2 视件的类型 241 16.3.3 颜色和GdkColormap 242 16.3.4 获得颜色表 244 16.4 可绘区和pixmap 244 16.5 事件 245 16.5.1 事件类型 245 16.5.2 事件屏蔽 247 16.5.3 在Gtk+中接收Gdk事件 248 16.5.4 鼠标按键事件 250 16.5.5 键盘事件 252 16.5.6 鼠标移动事件 254 16.5.7 焦点变更事件 257 16.6 鼠标指针 257 16.6.1 指针定位 257 16.6.2 独占指针 258 16.6.3 改变光标 259 16.7 字体 259 16.8 图形上下文 263 16.9 绘图 267 16.9.1 画点 267 16.9.2 画线 268 16.9.3 矩形 268 16.9.4 画弧 269 16.9.5 多边形 269 16.9.6 文本 270 16.9.7 pixmap像素映射图形 270 16.9.8 RGB缓冲 271 第三部分 Linux GUI 生成器Glade 第17章 Glade:GUI生成器 273 17.1 安装Glade 273 17.1.1 Glade简介 273 17.1.2 安装Glade 273 17.1.3 在Gnome主菜单下为Glade 创建菜单项 274 17.1.4 在Gnome面板上创建快捷 按钮 275 17.2 用Glade生成图形用户接口 275 17.2.1 Glade的界面简介 275 17.2.2 用Glade创建应用程序界面 277 第四部分 调试工具 第18章 程序调试 283 18.1 用gdb调试应用程序 283 18.1.1 为调试程序做准备 283 18.1.2 获得gdb帮助 284 18.1.3 gdb常用命令 284 18.1.4 gdb 应用举例 286 18.2 用xxgdb调试应用程序 289 第五部分 附 录 附录A GnomeHello源代码 293 附录B 在线资源 304 附录C Gtk+/Gnome对象总览 306

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值