一、说明
运行环境:虚拟机 gentoo4.4.6 ,3核心cpu
gcc 4.9.3
参考资料:文中部分代码和内容参照以下网络资料,如有侵权,请及时联系。
Linux CPU affinity: http://blog.csdn.net/yfkiss/article/details/7464968
top指令:http://developer.51cto.com/art/201509/492641.htm
http://www.cnblogs.com/yjf512/p/3383915.html
Linux进程或线程绑定到CPU:
http://www.linuxidc.com/Linux/2015-04/116867.htm
http://0987654321.blog.51cto.com/6934559/1409979
《unix环境高级编程》第11章:线程
二、中断绑定cpu
以网卡中断为例:对于网卡中断来说,有时会因为大量的网络中断导致cpu繁忙,可以通过将网卡中断绑定到特定的cpu,这样即使网络再繁忙,也不会使cpu响应其它请求变得太慢。
图中说明网卡中断为19,其smp_affinity 0x07,注意,这个值是以16进制表示,换成二进制就是0111, 也就说明3个cpu核心都可以相应网卡中断(虚拟机中设定了该系统使用3个cpu),
如果只让网卡中断绑定一个cpu,例如cpu0 , 可以使用下面的方法:
Echo ‘1’ > /proc/irq/19/smp_affinity
具体细节可以参看内核源码文档: 内核源码:Documentation/IRQ-affinity
三、进程(线程)运行中绑定cpu
3.1单线程进程消耗cpu情况
3.1.1指定cpu
将某个正在运行,或是开始运行时就可以指定cpu
taskset(需安装schedutils)
// 代码出出Linux CPU affinity: http://blog.csdn.net/yfkiss/article/details/7464968
//test.c
#include<stdio.h>
void main(int argc, char** argv)
{
int i=0;
for(i=0;i<100000000;i++)
{
if(i==10000)
{
i=0;
printf("program is running!\n");
}
}
}
两种设置方法
taskset -c 0 ./test test为程序名
Tastset -cp 0 pid pid为进程号
从图片中的数据看,虚拟机(程序运行在虚拟机中的linux系统中)中的cpu0确实
最繁忙 ,但cpu1 cpu2 的sys(内核态占用的cpu)仍然较高,并且从宿主机的cpu占用情况看,虚拟机中的3个cpu感觉都快满了。这一结果与网友的一篇博客不符合:
Linux CPU affinity http://blog.csdn.net/yfkiss/article/details/7464968
现在我们换一种程序的写法:
//test.c
#include<stdio.h>
void main(int argc, char** argv)
{
int i=0;
for(i=0;i<100000000;i++)
{
if(i==10000)
{
i=0;
//printf("program is running!\n");将打印信息注注释掉,
}
}
}
我们再来看cpu占用情况:
这个结果才是我们想要的,对吧。我猜想是不是taskset不能控制内核进程的占用cpu情况,对于有打印的那个test.c,会引起内核线程的调用,导致三个cpu都有较高的使用率。
我以目前的知识做出猜测:Printf最终会产生80h中断,系统调用,就是内核态,所以在消耗的cpu中,usr,sys各占一部分,而内核态对cpu的占用,我们使用taskset是无法控制的。反之,没有printf的就没有sys消耗了,我们就能控制只占用一个cpu的usr部分
此外,我也做过小实验,用test去调用另外的进程(自己写的,会占用3个cpu的usr 100%),当我控制test只在一个cpu上运行时,所调用的能跑满3个cpu的进程,也就只在一个cpu上运行。
3.1.2不指定cpu
对与没有打印语句的test.c
./test 结果: 与指定cpu的情况一致,也是占用一个cpu 100 usr 0 sys
对有打印语句的test.c
./test 结果: 与指定cpu的情况一致,也是占用一个cpu 75 usr 25 sys
6.1usr 45sys 4usr 61 sys
3.2多线程进程消耗cpu情况
#include<stdio.h>
#include<pthread.h>
void thr_fn1(void *arg)
{
int j=0;
for(j=0;j<100000000;j++)
{
if(j==10000)
{
j=0;
printf("program is running %d!\n",j);
}
}
}
void thr_fn2(void *arg)
{
int k=0;
for(k=0;k<100000000;k++)
{
if(k==10000)
{
k=0;
printf("program is running %d!\n",k);
}
}
}
void main(int argc, char** argv)
{
int i=0;
err=pthread_create(&ntid,NULL,thr_fn1,NULL);
if(err!=0)
{
printf("cannot create thread");
exit(1);
}
err=pthread_create(&ntid,NULL,thr_fn2,NULL);
if(err!=0)
{
printf("cannot create thread");
exit(1);
}
for(i=0;i<100000000;i++)
{
if(i==10000)
{
i=0;
printf("program is running!\n");
}
}
}
3.2.1指定cpu
不打印语句:如果指定cpu ,则只有一个cpu满负载,其它两个cpu比较悠闲,且其它两个cpu的sys占用也很低
打印语句: 如果指定cpu, 一个全部满载,另外两个的usr会比较空闲,但是sys占用率仍然高。
3.2.2不指定cpu
不打印语句:如果不指定cpu,则三个cpu usr都会满负载。
打印语句:如果不指定cpu,则三个都会满载,与单线程不同的是,每个cpu核的sys占用都较高
Ps: 具体的占用情况需呀读者自己去尝试,分析
要让top输出某个特定进程<pid>并检查该进程内运行的线程状况:
$ top -H -p <pid>
四、在函数中显示的对线程绑定cpu
//代码出处: http://0987654321.blog.51cto.com/6934559/1409979
void *MyfunWithMultiThread(void *arg)
{
cpu_set_t mask;
cpu_set_t get;
int i = 0;
int num = 0;
int cpuID = *(int *)arg;
CPU_ZERO(&mask);
CPU_SET(2, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) { //对线程的cpu addinity值进行调整,绑定到cpu2
fprintf(stderr, "set thread affinity failed\n");
}
CPU_ZERO(&get);
if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0) {
fprintf(stderr, "get thread affinity failed\n");
}
num = sysconf(_SC_NPROCESSORS_CONF);
for (i = 0; i < num; i++) {
if (CPU_ISSET(i, &get)) {
printf("thread %d is running in processor %d\n", (int)pthread_self(), i);
printf("Original setting is in processor %d\n\n", cpuID);
}
}
sleep(10);
}
对于进程的绑定:
int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);