(转)Linux下将进程/线程绑定到指定CPU核运行

作者:神秘网友 发布时间:2022-05-13 07:13:08

(转)Linux下将进程/线程绑定到指定CPU核运行


转自:Linux下将进程/线程绑定到指定CPU核运行

如何查看Linux核数
$ 总核数 = 物理CPU个数 X 每颗物理CPU的核数
$ 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

$ 查看物理CPU个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

$ 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep "cpu cores"| uniq

$ 查看逻辑CPU的个数
cat /proc/cpuinfo| grep "processor"| wc -l

processor:指明每个物理CPU中逻辑处理器信息(序号:0~5表示有6个逻辑CPU)

cpu cores:指明每颗物理CPU中总核数

以I5-8400 6核/6线程为例:

WINDOWS查看方式:

C:\Users\Administratorwmic

wmic:root\clicpu get

NumberOfCores NumberOfEnabledCore NumberOfLogicalProcessors

(CPU核心数)=6 (可用的CPU核心数)=6 (CPU线程数)=6

LINUX虚拟机:

$ cat /proc/cpuinfo | grep "physical id" | uniq
physical id : 0

$ cat /proc/cpuinfo | grep "cpu cores" | uniq
cpu cores : 6

$ cat /proc/cpuinfo | grep "processor" | uniq
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5

在程序中使用系统调用sysconf获取cpu核心数:

#include unistd.h

int sysconf(_SC_NPROCESSORS_CONF);/* 返回系统可以使用的核数,但是其值会包括系统中禁用的核的数目,因 此该值并不代表当前系统中可用的核数 */
int sysconf(_SC_NPROCESSORS_ONLN);/* 返回值真正的代表了系统当前可用的核数 */

/* 以下两个函数与上述类似 */
#include sys/sysinfo.h

int get_nprocs_conf (void);/* 可用核数 */
int get_nprocs (void);/* 真正的反映了当前可用核数 */

C语言代码如下:

#include stdio.h
#include unistd.h
#include sys/sysinfo.h

int main(int argc, char *argv[])
{
int sc_nprocessor_conf = sysconf(_SC_NPROCESSORS_CONF);
int sc_nprocessor_onln = sysconf(_SC_NPROCESSORS_ONLN);
printf("sc_nprocessor_conf[%d]\n", sc_nprocessor_conf);
printf("sc_nprocessor_onln[%d]\n", sc_nprocessor_onln);

int nprocs_conf = get_nprocs_conf();
int nprocs_onln = get_nprocs();
printf("nprocs_conf[%d]\n", nprocs_conf);
printf("nprocs_onln[%d]\n", nprocs_onln);
return 0;
}

执行结果:

sc_nprocessor_conf[6]
sc_nprocessor_onln[6]
nprocs_conf[6]
nprocs_onln[6]

确定调用线程正在运行的CPU和NUMA节点
#include linux/getcpu.h
int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
成功时返回0。 出错时,返回-1,并适当地设置errno
注意:这个系统调用没有glibc包装。 见注意事项。
测试程序:

#include stdio.h
#include sys/types.h
#include unistd.h
#include sys/syscall.h
#include time.h
#include sys/types.h

struct getcpu_cache
{
unsigned long blob[128/sizeof(long)];
};

int getcpu(unsigned *cpu, unsigned *node,struct getcpu_cache *tcache)
{
return syscall(SYS_getcpu, cpu, node, tcache);
}

int main(int argc, char *argv[])
{
unsigned cpu = 0;
unsigned node = 0;
if(getcpu(cpu,node,NULL)==-1)
{
printf("getcpu bad \n");
return 1;
}
printf("cpu = %u node = %u\n",cpu,node);
return 0;
}

getcpu()系统调用标识调用线程或进程当前正在运行的处理器和节点,并将它们写入由cpu和node参数指向的整数。处理器是识别CPU的唯一小整数。该节点是标识NUMA节点的唯一小标识符。当cpu或节点为NULL时,没有任何内容写入相应的指针。
这个系统调用的第三个参数现在是未使用的,应该指定为NULL,除非需要可移植到Linux 2.6.23或更早版本(请参阅NOTES)。

保存在cpu中的信息仅在调用时保持为当前状态:除非使用sched_setaffinity(2)修复了CPU关联性,否则内核可能随时更改CPU。
(通常情况下不会发生这种情况,因为调度器会尽量减少CPU之间的移动来保持缓存热度,但这是可能的。)调用者必须允许在调用返回时,在cpu和node中返回的信息不再是当前的

什么是绑核
所谓绑核,其实就是设定某个进程/线程与某个CPU核的亲和力(affinity)。设定以后,Linux调度器就会让这个进程/线程只在所绑定的核上面去运行。但并不是说该进程/线程就独占这个CPU的核,其他的进程/线程还是可以在这个核上面运行的。

掩码形式绑核
将掩码转换为二进制形式,从最低位到最高位代表物理CPU的#0、#1、……、#n号核。某位的值为0表示不绑该核,1表示绑。比如:0x00000001的二进制为0000...0001,只有第0号核的位置是1,所以表示只绑0号核;0x00000003的二进制为0000...0011,第0和1号核的位置是1,所以表示绑CPU的0号和1号核;再比如0xFFFFFFFF的二进制为1111...1111,所有32个核的位置都为1,所以表示绑CPU的0~31核。

掩码形式的绑核命令为:

taskset -p mask pid

列表形式
列表形式指直接指定要绑的CPU核的列表,列表中可以有一个或多个核。具体语法如下:

taskset -cp cpu-list pid

其中cpu-list是数字化的cpu列表,从0开始。多个不连续的cpu可用逗号连接,连续的可用短现连接,比如0,1,3-6等。

比如taskset -cp 0,1,3-6 2677 命令表示将进程2677 绑定到#0、#1、#3~#6号核上面。

多进程和多线程在cpu核上运行分析:

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

举例如下:

1, 使用taskset指令绑定进程到特定CPU步骤

测试程序:cpu_processor_test.c

#include stdio.h
#include time.h
#include sys/types.h
#include unistd.h

int main(int argc, char *argv[])
{
pid_t pid = getpid();
pid_t ppid = getppid();
printf("ppid %d pid %d\n", ppid, pid);
while(1)
{
sleep(10);
}
return 0;
}

gcc cpu_processor_test.c -o cpu_processor_test

(1)获取进程pid

$ ps -aux | grep "cpu_processor_test"
myroot 1582 0.0 0.0 4352 628 pts/8 S+ 22:04 0:00 ./cpu_processor_test

(2) 查看进程当前运行在哪些cpu上

$ taskset -p 1582
pid 1582's current affinity mask: 3f

显示的十进制数字3转换为2进制为最低6个是1,每个1对应一个cpu,所以进程运行在6个cpu上。

(3)指定进程运行在cpu2上

$ taskset -pc 2 1582
pid 1582's current affinity list: 0-5
pid 1582's new affinity list: 2

注意,cpu的标号是从0开始的,所以cpu1表示第二个cpu(第一个cpu的标号是0)。

至此,就把应用程序绑定到了cpu1上运行

(4)确认绑定命令

$ taskset -p 1582
pid 1582's current affinity mask: 4

2,启动程序时绑定cpu

(1)启动时绑定到第3个cpu

$ taskset -c 2 ./cpu_processor_test
[1] 1615
ppid 1439 pid 1615

(2)查看确认绑定情况

$ taskset -p 1615
pid 1615's current affinity mask: 4

使用sched_setaffinity系统调用

sched_setaffinity可以将某个进程绑定到一个特定的CPU。

#define _GNU_SOURCE /* See feature_test_macros(7) */
#include sched.h

/* 设置进程号为pid的进程运行在mask所设定的CPU上
* 第二个参数cpusetsize是mask所指定的数的长度
* 通常设定为sizeof(cpu_set_t)

* 如果pid的值为0,则表示指定的是当前进程
*/
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所指示的进程的CPU位掩码,并将该掩码返回到mask所指向的结构中 */

实例

#includestdlib.h
#includestdio.h
#includesys/types.h
#includesys/sysinfo.h
#includeunistd.h

#define __USE_GNU
#includesched.h
#includectype.h
#includestring.h
#includepthread.h

#define MAX_THREAD_NUM 200 //1个CPU内的最多进程数

int cpu_cores_num = 0; //cpu中核数
void *thread_test(void *arg) //arg 传递线程标号(自己定义)
{
cpu_set_t mask; //CPU核的集合
cpu_set_t get; //获取在集合中的CPU
int *cpu_index = (int *)arg;
int i;

printf("the thread is:%d\n",*cpu_index); //显示是第几个线程
CPU_ZERO(mask); //置空
CPU_SET(*cpu_index,mask); //设置亲和力值
if (sched_setaffinity(0, sizeof(mask), mask) == -1)//设置线程CPU亲和力
{
printf("warning: could not set CPU affinity, continuing...\n");
}

CPU_ZERO(get);
if (sched_getaffinity(0, sizeof(get), get) == -1)//获取线程CPU亲和力
{
printf("warning: cound not get thread affinity, continuing...\n");
}
for (int cpu_core_index = 0; cpu_core_index cpu_cores_num; cpu_core_index++)
{
if (CPU_ISSET(cpu_core_index, get))//判断线程与哪个CPU有亲和力
{
printf("this thread %d is running processor : %d\n", cpu_core_index, cpu_core_index);
}
}

return NULL;
}

int main(int argc, char *argv[])
{
int tid[MAX_THREAD_NUM] = {0};
int cpu_core_index = 0;
pthread_t thread[MAX_THREAD_NUM];

cpu_cores_num = sysconf(_SC_NPROCESSORS_CONF); //获取核数
if (cpu_cores_num MAX_THREAD_NUM)
{
printf("cpu_cores_num of cores[%d] is bigger than MAX_THREAD_NUM[%d]!\n", cpu_cores_num, MAX_THREAD_NUM);
return -1;
}
printf("system has %i processor(s). \n", cpu_cores_num);

for(cpu_core_index = 0; cpu_core_index cpu_cores_num;cpu_core_index++)
{
tid[cpu_core_index] = cpu_core_index; //每个线程必须有个tid[i]
pthread_create(thread[cpu_core_index],NULL,thread_test,(void*)tid[cpu_core_index]);
}
for(cpu_core_index = 0; cpu_core_index cpu_cores_num; cpu_core_index++)
{
pthread_join(thread[cpu_core_index],NULL);//等待所有的线程结束,线程为死循环所以CTRL+C结束
}
return 0;
}

运行结果

$ gcc cpu_processor_test.c -o cpu_processor_test -pthread

$./cpu_processor_test
system has 6 processor(s).
the thread is:0
the thread is:2
the thread is:5
the thread is:3
this thread 5 is running processor : 5
this thread 2 is running processor : 2
this thread 3 is running processor : 3
the thread is:1
the thread is:4
this thread 4 is running processor : 4
this thread 0 is running processor : 0
this thread 1 is running processor : 1

绑定线程到cpu核上运行

绑定线程到cpu核上使用pthread_setaffinity_np函数,其原型定义如下:

#define _GNU_SOURCE /* See feature_test_macros(7) */
#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);

Compile and link with -pthread.

各参数的意义与sched_setaffinity相似。

实例

#define _GNU_SOURCE
#include pthread.h
#include stdio.h
#include stdlib.h
#include errno.h

#define handle_error_en(en, msg) \
do { \
errno = en; \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)

int main(int argc, char *argv[])
{
int s, j;
cpu_set_t cpuset;

pthread_t thread = pthread_self();
/* Set affinity mask to include CPUs 0 to 7 */

CPU_ZERO(cpuset);
for (j = 0; j 8; j++)
{
CPU_SET(j, cpuset);
}

s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpuset);
if (s != 0) handle_error_en(s, "pthread_setaffinity_np");

/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), cpuset);
if (s != 0) handle_error_en(s, "pthread_getaffinity_np");
printf("Set returned by pthread_getaffinity_np() contained:\n");
for (j = 0; j CPU_SETSIZE; j++)
{
if (CPU_ISSET(j, cpuset)) printf(" CPU %d\n", j);
}

exit(EXIT_SUCCESS);

return 0;
}

运行结果

$ gcc cpu_processor_test.c -o cpu_processor_test -pthread
$ ./cpu_processor_test
Set returned by pthread_getaffinity_np() contained:
CPU 0
CPU 1
CPU 2
CPU 3
CPU 4
CPU 5

总结

可以使用多种方法把进程/线程指定到特定的cpu核上运行。

在具体使用中,要根据使用场景和需求决定使用何种方式。
————————————————
版权声明:本文为CSDN博主「IT笔记」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013416923/article/details/120317841

(转)Linux下将进程/线程绑定到指定CPU核运行 相关文章

  1. 多核优化使用linux affinity 将进程线程中断指定到对应的cpu运行

    多核优化,使用linux affinity 将进程,线程,中断指定到对应的cpu运行,用ftrace查看消耗时间 cpu的affinity简介 使用cpu的affinity机制可以将对应的进程,线程,以及中断指定代对应的cpu上运行,如果合理配置,减少某个cpu负担,提高...

  2. centos下查看指定进程中的每个线程运行在哪个CPU中

    centos下查看指定进程中的每个线程运行在哪个CPU中 top 以上图中的numatest1进程为例,可以在top中看到PID为11295 top -H -p PID (ps:在这里我的PID为11295) 按下 f ,通过上下键移动到nTH和p这两个参数上,分别按下 空格 按 esc ,即可切回...

  3. Linux 线程或者进程在固定的CPU上运行方法

    Linux 线程或者进程在固定的CPU上运行方法 https://blog.csdn.net/wanxuexiang/article/details/108590490 文章目录 Linux 线程或者进程在固定的CPU上运行方法 1 如何查看进程或者线程运行在哪个CPU上? 1.1 利用PS命令进行查看 1.2 利用top命令进行查...

  4. cpustat在 Linux 下根据运行的进程监控 CPU 使用率

    cpustat 是 Linux 下一个强大的系统性能测量程序,它用 Go 编程语言 编写。它通过使用 用于分析任意系统的性能的方法(USE),以有效的方式显示 CPU 利用率和饱和度。 它高频率对系统中运行的每个进程进行取样,然后以较低的频...

  5. Linux 有问必答如何知道进程运行在哪个 CPU 内核上

    问题:我有个 Linux 进程运行在多核处理器系统上。怎样才能找出哪个 CPU 内核正在运行该进程? 当你在 多核 NUMA 处理器上运行需要较高性能的 HPC(高性能计算)程序或非常消耗网络资源的程序时,CPU/memory 的亲和力是限度其发...

  6. 查看JAVA进程中哪个线程CPU消耗最高_JAVA本地远程连接linux程序

    查看JAVA进程中哪个线程CPU消耗最高_JAVA本地远程连接linux程序监控状态 转载:http://www.cnblogs.com/tankaixiong/p/5995759.html 转载: http://www.cnblogs.com/tankaixiong/p/5984023.html 查看JAVA进程中哪个线程CPU消耗最高 一,在centos linux 上查看

  7. Linux 网络编程概述 进程线程到套接字

    Linux 网络编程概述 进程线程到套接字 回顾之前的进程间通信 管道 消息队列 共享内存 信号 信号量 这些通信方式,全部都是依赖于 linux 内核,同一个linux 系统。 而这样,势必导致此类方式无法进行 跨设备 通信。 地址 : { ...

  8. 在Ubuntu中怎么绑定CPU进程

    Linux进程包括核心进程和普通进程,把普通进程绑定到Linux系统CPU核中运行,那么普通进程就成了核心进程。本文就以Ubuntu为例子来介绍一下,在Ubuntu中怎么绑定CPU进程。 taskset -cp 《CPU ID | CPU IDs》 《Process ID》 下面用一个简单的...

  9. linux下将移动硬盘挂载到服务器上

    linux下将移动硬盘挂载到服务器上 (切换到管理员账户,管理员运行以下命令) 1. sudo fdisk -l #查看当前磁盘状态; 我的移动磁盘显示为:/ dev/sdc1 sudo mkdir disk/usb disk/usb ): sudo mount /dev/sdc1 /home/ran.chen/disk/usb 问题1:权限不足 问题2

  10. linux下将一个目录下的所有文件拷贝到另一个大文件中并把大文件

    linux下将一个目录下的所有文件拷贝到另一个大文件中,并把大文件拆分成原来的小文件,大小,内容,名字不变 经过四五天的编写与调试,初步完成了文件操作工具的内容,以下是代码说明: 首先,我测试用的文件在 /home/xudo...

  11. linux 终止指定进程_如何在Linux中通过等待来等待指定的进程终止

    linux 终止指定进程_如何在Linux中通过等待来等待指定的进程终止,而在睡眠中如何等待差异?... linux 终止指定进程 Linux provides simple and useful tools and commands. wait is one of them. We can use wait command to wait for specified process id

  12. 分析占用了大量 CPU 处理时间的是Java 进程中哪个线程

    分析占用了大量 CPU 处理时间的是Java 进程中哪个线程 本文的目的是在 Java进程中确定哪个线程正在占用CPU的时间。 当您的系统 CPU 负载居高不下时,这是一种有用的故障排除技术。 本文的目的是在 Java进程中确定哪个线程正在...

  13. 石杉笔记(5) 进程间通信方式线程间切换BIO/NIO/AIO 线上cpu 100

    石杉笔记(5) 进程间通信方式、线程间切换、BIO/NIO/AIO 、线上cpu 100%、32位java虚拟机中的long和double变量写操作为何不是原子的 1、进程间的通信 通信方式:管道(pipe)、命名管道(fifo)、消息队列、共享内存(System V) 线程之间...

  14. 进程和线程 java程序运行的原理 线程创建的方式

    进程和线程 java程序运行的原理 线程创建的方式 / * 进程和线程: 1 . 一个进程对应一个应用程序 eg.windows 启动 word. windows 启动 jvm . 就是启动了一个进程。现代的计算机都支持多进程。 就是同一个操作系统中,同时启动多个进程...

  15. Linux查找占用指定端口的进程

    在Linux有多种方案。 lsof lsof-itcp:80 列出使用tcp连接80端口的进程 不指定协议 lsof-i:80 netstat sudonetstat-nlp 列出所有打开的网络连接

  16. Linux 性能优化笔记:CPU 异常处理(不可中断进程、僵尸进程)

    Linux 性能优化笔记:CPU 异常处理(不可中断进程、僵尸进程) 当你发现系统的 CPU 使用率很高的时候,不一定能找到相对应的高 CPU 使用率的进程 。 当碰到无法解释的 CPU 使用率问题时,先要检查一下是不是短时应用在捣鬼。 ...

  17. linux查看进程占CPU过高

    linux查看进程占CPU过高 问题: linux使用top命令查看服务器资源,发现有两个进程占CPU值大于60%,通过PID无法查看到具体进程服务 解决: 使用ps -aux命令查看服务器所有正在运行的进程,查看是否有某一个进程占CPU过高,进行处理

  18. linux查看指定用户的所有进程

    linux查看指定用户的所有进程 简言 1. top命令如果不加限制,默认是查看所有用户的进程情况 2. top -u [用户名] 可以查看该用户名的所有进程 实验如下 1. ubuntu用户状态下,我们运行命令 top -u ubuntu 可以查看用户 ubuntu 的所有进程 2...

  19. Linux下通过grep查找指定的进程是否存在

    Linux下通过grep查找指定的进程是否存在 [var1] Linux通过命令查找指定的进程是否存在,并返回该进程的PID号。 在程序中可以使用该方法监控指定的程序是否在运行,如果异常退出,可以重新启动指定程序或者系统。 [var1] 2.1 shell...

  20. linux系统cpu进程与内存相关查杀操作

    linux系统cpu进程与内存相关查杀操作 系统监视和进程控制工具 查看内存的使用信息 free -m 以M为单位 free -h 以G为单位 process search ps aux,查看所有进程 查询到的结果里包含了查询命令本身,可以取消掉 -v 表款取反。本例取不包含...

每天更新java,php,javaScript,go,python,nodejs,vue,android,mysql等相关技术教程,教程由网友分享而来,欢迎大家分享IT技术教程到本站,帮助自己同时也帮助他人!

Copyright 2021, All Rights Reserved. Powered by 跳墙网(www.tqwba.com)|网站地图|关键词