多核环境下绑定进程运行在指定的CPU核上

      最近做相关算法性能测试的时候,要测试单核的性能,故需要事先绑定指定的CPU核号。

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

该进程/线程就独占这个CPU的核,其他的进程/线程还是可以在这个核上面运行的。如果想要实现某个进程/线程独占某个核,就要使用cpuset命令去实现。

      其实,很多情况下,为了提高性能,Linux调度器会自动的实现尽量让某个进程/线程在同样的CPU上去运行。所以,除非必须,我们没有必要显式的去进程绑核操作。


下文介绍两种绑定的方法:

一、taskset


     1.简单介绍: taskset用来查看和设定“CPU亲和力”,说白了就是查看或者配置进程和cpu的绑定关系,让某进程在指定的CPU核上运行,即是“绑核”。

     2.taskset的用法

          (1)显示进程运行的CPU

            taskset -p pid

            注意,此命令返回的是十六进制的,转换成二进制后,每一位对应一个逻辑CPU,低位是0号CPU,依次类推。如果每个位置上是1,表示该进程绑定了该CPU。例如,0101就表示进程绑定在了0号和3号逻辑CPU上了

          (2)绑核设定

            a.掩码形式绑核
            按照二进制形式,从最低位到最高位代表物理CPU的#1、#2、……、#n号核。
            比如:0x00000001代表CPU的0号核,0x00000003代表CPU的0号和3号核。
            需要注意的是,并非掩码中给出的CPU核就一定会存在,比如0x00000400理论上代表CPU的第10号核,但是该核在真正的计算机上面并不一定是存在的。而且,如果            我们试图将物理上并不存的核绑定给某个进程时,会返回错误。掩码形式的绑核命令为:
            taskset -p mask pid
            b.按CPU数直接绑核
            taskset -cp cpu-list pid 或者 taskset -c cpu-list command
            其中cpu-list是数字化的cpu列表,从1开始。多个不连续的cpu可用逗号连接,连续的可用短现连接,比如1,2,5-11等。
            比如“taskset -c 1,3,5-9 9860”命令表示将进程9860绑定到#1、#3、#5~#9号核上面。


二、sched_setaffinity系统调用


     一个CPU的亲合力掩码用一个cpu_set_t结构体来表示一个CPU集合,下面的几个宏分别对这个掩码集进行操作:
    ·CPU_ZERO() 清空一个集合
    ·CPU_SET()与CPU_CLR()分别对将一个给定的CPU号加到一个集合或者从一个集合中去掉.
    ·CPU_ISSET()检查一个CPU号是否在这个集合中.

    下面两个函数就是用来设置获取线程CPU亲和力状态: 
    ·sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask) 

      该函数设置进程为pid的这个进程,让它运行在mask所设定的CPU上.如果pid的值为0,则表示指定的是当前进程,使当前进程运行在mask所设定的那些CPU上.第二个参数cpusetsize是mask所指定的数的长度.通常设定为sizeof(cpu_set_t).如果当前pid所指定的进程此时没有运行在mask所指定的任意一个CPU上,则该指定的进程会从其它CPU上迁移到mask的指定的一个CPU上运行. 

    ·sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask) 

      该函数获得pid所指示的进程的CPU位掩码,并将该掩码返回到mask所指向的结构中.即获得指定pid当前可以运行在哪些CPU上.同样,如果pid的值为0.也表示的是当前进程

      给出测试代码:

#include
   
   
    
      
#include
    
    
     
       
#include
     
     
      
        
#include
      
      
       
         
#include
       
       
         #define __USE_GNU #include 
        
          #include 
         
           #include 
          
            #include 
           
             #define THREAD_MAX_NUM 100 //1个CPU内的最多进程数 int num=0; //cpu中核数 void* threadFun(void* arg) //arg 传递线程标号 { cpu_set_t mask; //CPU核的集合 cpu_set_t get; //获取在集合中的CPU int *a = (int *)arg; printf("the a is:%d\n",*a); //显示是第几个线程 CPU_ZERO(&mask); //置空 CPU_SET(*a,&mask); //设置亲和力值 if (sched_setaffinity(0, sizeof(mask), &mask) == -1)//设置线程CPU亲和力 { printf("warning: could not set CPU affinity, continuing...\n"); } while (1) { CPU_ZERO(&get); if (sched_getaffinity(0, sizeof(get), &get) == -1)//获取线程CPU亲和力 { printf("warning: cound not get thread affinity, continuing...\n"); } int i; for (i = 0; i < num; i++) { if (CPU_ISSET(i, &get))//判断线程与哪个CPU有亲和力 { printf("this thread %d is running processor : %d\n", i,i); } } } return NULL; } int main(int argc, char* argv[]) { num = sysconf(_SC_NPROCESSORS_CONF); //获取核数 pthread_t thread[THREAD_MAX_NUM]; printf("system has %i processor(s). \n", num); int tid[THREAD_MAX_NUM]; int i; for(i=0;i 
             
            
           
          
         
       
      
      
     
     
    
    
   
   

      编译:gcc bind.c -o bind -lpthread

      执行:./bind


      特别注意:

      #define __USE_GNU不要写成#define _USE_GNU

      #include<pthread.h>必须写在#define __USE_GNU之后,否则编译会报错

      查看你的线程情况可以在执行时在另一个窗口使用top -H来查看线程的情况,查看各个核上的情况请使用top命令然后按数字“1”来查看。

      如图:




  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值