关于CPU affinity的几篇文章

cpu绑定和cpu亲和性

原文地址:http://blog.csdn.net/joker0910/article/details/7484371

将进程/线程与cpu绑定,最直观的好处就是提高了cpu cache的命中率,从而减少内存访问损耗,提高程序的速度。我觉得在NUMA架构下,这个操作对系统运行速度的提升有较大的意义,而在SMP架构下,这个提升可能就比较小。这主要是因为两者对于cache、总线这些资源的分配使用方式不同造成的,NUMA每个cpu有自己的一套资源体系, SMP中每个核心还是需要共享这些资源的,从这个角度来看,NUMA使用cpu绑定时,每个核心可以更专注地处理一件事情,资源体系被充分使用,减少了同步的损耗。SMP由于一部分资源的共享,在进行了绑定操作后,受到的影响还是很大的。

通过linux提供的几个api, 可以轻松地完成这个优化:


下面是一个实例。

[cpp]  view plain  copy
  1. /* 
  2.  * @FileName: simple_affinity.c 
  3.  * @Author: wzj 
  4.  * @Brief:  
  5.  * 1. cpu affinity.  case 
  6.  * 2.在子线程中,会继承绑定的cpu..., 不过在子线程中,可以重新分配。 
  7.  *   
  8.  * @History:  
  9.  *  
  10.  *  
  11.  *  
  12.  * @Date: 2012年04月21日星期六12:56:14 
  13.  *  
  14.  */   
  15.   
  16. #include <stdlib.h>  
  17. #include <stdio.h>  
  18. #include <unistd.h>  
  19.   
  20. #define __USE_GNU       //启用CPU_ZERO等相关的宏  
  21. //#define _GNU_SOURCE  
  22. #include <sched.h>  
  23. #include <pthread.h>            //这个东西原来放在__USE_GNU宏之前,结果被编译器报错说CPU_ZERO未定义  
  24.   
  25. void* new_test_thread(void* arg)  
  26. {  
  27.     cpu_set_t mask;  
  28.     int i = 0;  
  29.     int num = sysconf(_SC_NPROCESSORS_CONF);    //获取当前的cpu总数  
  30.     pthread_detach(pthread_self());  
  31.       
  32.     CPU_ZERO(&mask);      
  33.     CPU_SET(1, &mask);      //绑定cpu 1  
  34.     if(sched_setaffinity(0, sizeof(mask), &mask) == -1)      //0 代表对当前线程/进程进行设置。  
  35.     {  
  36.         printf("set affinity failed..");  
  37.     }  
  38.     while(1)  
  39.     {  
  40.         CPU_ZERO(&mask);  
  41.         if(sched_getaffinity(0, sizeof(mask), &mask) == -1)   
  42.         {  
  43.             printf("get failed..\n");  
  44.         }  
  45.   
  46.         for(i = 0; i < num; i++)  
  47.         {  
  48.             if(CPU_ISSET(i, &mask))  
  49.             printf("new thread %d run on processor %d\n", getpid(), i);  
  50.         }  
  51.         while(1);  
  52.         sleep (1);  
  53.     }  
  54. }      //while(1);      //如果觉得不明显,改成这个,  

[cpp]  view plain  copy
  1. void* child_test_thread(void* arg)  
  2. {  
  3.     cpu_set_t mask;  
  4.     int i = 0;  
  5.     int num = sysconf(_SC_NPROCESSORS_CONF);  
  6.     pthread_detach(pthread_self());  
  7.       
  8.     while(1)  
  9.     {  
  10.         CPU_ZERO(&mask);  
  11.         if(sched_getaffinity(0, sizeof(mask), &mask) == -1)   
  12.         {  
  13.             printf("get failed..\n");  
  14.         }  
  15.   
  16.         for(i = 0; i < num; i++)  
  17.         {  
  18.             if(CPU_ISSET(i, &mask))  
  19.             printf("child thread %d run on processor %d\n", getpid(), i);  
  20.         }  
  21.         sleep (1);  
  22.     }  
  23.   
  24. }  
  25.   
  26. int  
  27. main(int argc, char* argv[])  
  28. {  
  29.     int num = sysconf(_SC_NPROCESSORS_CONF);  
  30.     int created_thread = 0;  
  31.     int myid;  
  32.     int i;  
  33.     int j = 0;  
  34.     pthread_t ptid = 0;  
  35.   
  36.     cpu_set_t mask;  
  37.     cpu_set_t get;  
  38.   
  39.     if(argc != 2)  
  40.     {  
  41.         printf("usage: ./cpu num\n");  
  42.         return -1;  
  43.     }  
  44.     myid = atoi(argv[1]);  
  45.     printf("system has %i processor(s).\n", num);  
  46.   
  47.     CPU_ZERO(&mask);  
  48.     CPU_SET(myid, &mask);  
  49.     if(sched_setaffinity(0, sizeof(mask), &mask) == -1)  
  50.     {  
  51.         printf("warning: set CPU affinity failed...");  
  52.     }  
  53.   
  54.     int ret = pthread_create(&ptid, NULL, new_test_thread, NULL);  
  55.     if(ret)  
  56.     {  
  57.         return -1;  
  58.     }  
  59.     ret = pthread_create(&ptid, NULL, child_test_thread, NULL);  
  60.     if(ret)  
  61.     {  
  62.         return -1;  
  63.     }  
  64.   
  65.   
  66.     while(1)  
  67.     {  
  68.         CPU_ZERO(&get);  
  69.         if(sched_getaffinity(0, sizeof(get), &get) == -1)  
  70.         {  
  71.             printf("can't get cpu affinity...");  
  72.         }  
  73.   
  74.         for(i = 0; i < num; i++)  
  75.         {  
  76.             if(CPU_ISSET(i, &get))  
  77.             {  
  78.                 printf("this process %d is runing on procesor:%d\n", getpid(), i);  
  79.             }  
  80.         }  
  81.           
  82.         sleep(1);  
  83.     }  
  84.     //while(1); //使用这个更明显  
  85.     return 0;  
  86. }  

编译:

[cpp]  view plain  copy
  1. gcc -o cpu simple_affinity.c -lpthread  

执行./cpu [cpu num / masks] ,使用top观察cpu使用状况。 使用./cpu 0 时,可以发现,两颗核心使用率都比较高, 使用./cpu 1时,可以发现,1核的压力比较重。


当然还可以对线程进行cpu绑定。

[cpp]  view plain  copy
  1. #define _GNU_SOURCE  
  2. #include <pthread.h>  
  3.    
  4. int pthread_setaffinity_np(pthread_t threadsize_t cpusetsize,  
  5.                           const cpu_set_t *cpuset);  
  6. int pthread_getaffinity_np(pthread_t threadsize_t cpusetsize,  
  7.                           cpu_set_t *cpuset);  


这个介绍了使用的时机,比较经典:http://www.ibm.com/developerworks/cn/linux/l-affinity.html



Linux中线程与CPU核的绑定 

原文地址:http://blog.chinaunix.net/uid-26739406-id-3181199.html

   最近在对项目进行性能优化,由于在多核平台上,所以了解了些进程、线程绑定cpu核的问题,在这里将所学记录一下。

   不管是线程还是进程,都是通过设置亲和性(affinity)来达到目的。对于进程的情况,一般是使用sched_setaffinity这个函数来实现,网上讲的也比较多,这里主要讲一下线程的情况。
   与进程的情况相似,线程亲和性的设置和获取主要通过下面两个函数来实现:
int pthread_setaffinity_np(pthread_tthread, size_t cpusetsize,const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize,cpu_set_t *cpuset);
    从函数名以及参数名都很明了,唯一需要点解释下的可能就是cpu_set_t这个结构体了。这个结构体的理解类似于select中的fd_set,可以理解为cpu集,也是通过约定好的宏来进行清除、设置以及判断:
//初始化,设为空
      void CPU_ZERO (cpu_set_t *set); 
      //将某个cpu加入cpu集中 
       void CPU_SET (int cpu, cpu_set_t *set); 
       //将某个cpu从cpu集中移出 
       void CPU_CLR (int cpu, cpu_set_t *set); 
       //判断某个cpu是否已在cpu集中设置了 
       int CPU_ISSET (int cpu, const cpu_set_t *set); 
       cpu集可以认为是一个掩码,每个设置的位都对应一个可以合法调度的 cpu,而未设置的位对应一个不可调度的 CPU。换而言之,线程都被绑定了,只能在那些对应位被设置了的处理器上运行。通常,掩码中的所有位都被置位了,也就是可以在所有的cpu中调度。       
      以下为测试代码:

点击(此处)折叠或打开

  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <pthread.h>
  7. #include <sched.h>

  8. void *myfun(void *arg)
  9. {
  10.     cpu_set_t mask;
  11.     cpu_set_t get;
  12.     char buf[256];
  13.     int i;
  14.     int j;
  15.     int num = sysconf(_SC_NPROCESSORS_CONF);
  16.     printf("system has %d processor(s)\n", num);

  17.     for (= 0; i < num; i++) {
  18.         CPU_ZERO(&mask);
  19.         printf("mask=%x\n", mask);
  20.         CPU_SET(i, &mask);
  21.         printf("mask=%x\n", mask);
  22.         if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) {
  23.             fprintf(stderr, "set thread affinity failed\n");
  24.         }
  25.         CPU_ZERO(&get);
  26.         if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0) {
  27.             fprintf(stderr, "get thread affinity failed\n");
  28.         }
  29.         for (= 0; j < num; j++) {
  30.             if (CPU_ISSET(j, &get)) {
  31.                 printf("thread %d is running in processor %d\n", (int)pthread_self(), j);
  32.             }
  33.         }
  34.         j = 0;
  35.         while (j++ < 100000000) {
  36.             memset(buf, 0, sizeof(buf));
  37.         }
  38.     }
  39.     pthread_exit(NULL);
  40. }

  41. int main(int argc, char *argv[])
  42. {
  43.     pthread_t tid;
  44.     if (pthread_create(&tid, NULL, (void *)myfun, NULL) != 0) {
  45.         fprintf(stderr, "thread create failed\n");
  46.         return -1;
  47.     }
  48.     pthread_join(tid, NULL);
  49.     return 0;
  50. }
       这段代码将使myfun线程在所有cpu中依次执行一段时间,在我的四核cpu上,执行结果为  :
       system has 4 processor(s)        
       thread 1095604544 is running in processor 0        
       thread 1095604544 is running in processor 1        
       thread 1095604544 is running in processor 2        
       thread 1095604544 is running in processor 3 
       在一些嵌入式设备中,运行的进程线程比较单一,如果指定进程线程运行于特定的cpu核,减少进程、线程的核间切换,有可能可以获得更高的性能。

编译命令为:
gcc cpu_affinity.c -lpthread -o cpu_affinity

更直观地查看程序在CPU的affinity,top -d 1,然后再按下‘1’。
可以看到Cpu1处于100%占用率。


同时执行的log如下,从mask的值也可以看出当前附着在哪个CPU上面:

system has 4 processor(s)
mask=81a2ed00
mask=1
thread -2120026368 is running in processor 0
mask=81a2ed00
mask=2
thread -2120026368 is running in processor 1
mask=81a2ed00
mask=4
thread -2120026368 is running in processor 2
mask=81a2ed00
mask=8

thread -2120026368 is running in processor 3


Linux中CPU亲和性(affinity)

原文地址:http://www.cnblogs.com/LubinLew/p/cpu_affinity.html?utm_source=tuicool&utm_medium=referral

 0、准备知识

超线程技术(Hyper-Threading):就是利用特殊的硬件指令,把两个逻辑内核(CPU core)模拟成两个物理芯片,

    让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。

    我们常听到的双核四线程/四核八线程指的就是支持超线程技术的CPU.

物理CPU:机器上安装的实际CPU, 比如说你的主板上安装了一个8核CPU,那么物理CPU个数就是1个,所以物理CPU个数就是主板上安装的CPU个数。

逻辑CPU:一般情况,我们认为一颗CPU可以有多核,加上intel的超线程技术(HT), 可以在逻辑上再分一倍数量的CPU core出来;

逻辑CPU数量 = 物理CPU数量 x CPU cores x 2(如果支持并开启HT) //前提是CPU的型号一致,如果不一致只能一个一个的加起来,不用直接乘以物理CPU数量
//比如你的电脑安装了一块4核CPU,并且支持且开启了超线程(HT)技术,那么逻辑CPU数量 = 1 × 4 × 2 = 8

 Linux下查看CPU相关信息, CPU的信息主要都在/proc/cupinfo中,

复制代码
# 查看物理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

# 查看CPU的名称型号
cat /proc/cpuinfo|grep "name"|cut -f2 -d:|uniq
复制代码

 Linux查看某个进程运行在哪个逻辑CPU上

复制代码
ps -eo pid,args,psr
#参数的含义: pid - 进程ID args - 该进程执行时传入的命令行参数 psr - 分配给进程的逻辑CPU

例子:
[~]# ps -eo pid,args,psr | grep nginx
9073 nginx: master process /usr/   1
9074 nginx: worker process         0
9075 nginx: worker process         1
9076 nginx: worker process         2
9077 nginx: worker process         3
13857 grep nginx                   3
复制代码

 Linux查看线程的TID

TID就是Thread ID,他和POSIX中pthread_t表示的线程ID完全不是同一个东西.

Linux中的POSIX线程库实现的线程其实也是一个轻量级进程(LWP),这个TID就是这个线程的真实PID.

但是又不能通过getpid()函数获取,Linux中定义了gettid()这个接口,但是通常都是未实现的,所以需要使用下面的方式获取TID。

复制代码
//program
#include <sys/syscall.h>  
pid_t tid;
tid = syscall(__NR_gettid);// or syscall(SYS_gettid)  

//command-line
(1)ps -efL | grep prog_name
(2)ls /proc/pid/task            //文件夹名即TID
复制代码

 

 

1、CPU亲和性(亲和力)

1.1 基本概念

CPU affinity 是一种调度属性(scheduler property), 它可以将一个进程"绑定" 到一个或一组CPU上.

在SMP(Symmetric Multi-Processing对称多处理)架构下,Linux调度器(scheduler)会根据CPU affinity的设置让指定的进程运行在"绑定"的CPU上,而不会在别的CPU上运行. 

Linux调度器同样支持自然CPU亲和性(natural CPU affinity): 调度器会试图保持进程在相同的CPU上运行, 这意味着进程通常不会在处理器之间频繁迁移,进程迁移的频率小就意味着产生的负载小。

因为程序的作者比调度器更了解程序,所以我们可以手动地为其分配CPU核,而不会过多地占用CPU0,或是让我们关键进程和一堆别的进程挤在一起,所有设置CPU亲和性可以使某些程序提高性能。

1.2 表示方法

CPU affinity 使用位掩码(bitmask)表示, 每一位都表示一个CPU, 置1表示"绑定".

最低位表示第一个逻辑CPU, 最高位表示最后一个逻辑CPU.

CPU affinity典型的表示方法是使用16进制,具体如下.

复制代码
0x00000001
    is processor #0

0x00000003
    is processors #0 and #1

0xFFFFFFFF
    is all processors (#0 through #31)
复制代码

2、taskset命令

 taskset命名用于获取或者设定CPU亲和性.

复制代码
# 命令行形式
taskset [options] mask command [arg]...
taskset [options] -p [mask] pid

PARAMETER
 
   mask : cpu亲和性,当没有-c选项时, 其值前无论有没有0x标记都是16进制的,
        当有-c选项时,其值是十进制的.
    command : 命令或者可执行程序
    arg : command的参数
    pid : 进程ID,可以通过ps/top/pidof等命令获取
OPTIONS
    
-a, --all-tasks (旧版本中没有这个选项)
        这个选项涉及到了linux中TID的概念,他会将一个进程中所有的TID都执行一次CPU亲和性设置.
        TID就是Thread ID,他和POSIX中pthread_t表示的线程ID完全不是同一个东西.
        Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),这个TID就是这个线程的真实PID. -p, --pid 操作已存在的PID,而不是加载一个新的程序 -c, --cpu-list 声明CPU的亲和力使用数字表示而不是用位掩码表示. 例如 0,5,7,9-11. -h, --help display usage information and exit -V, --version output version information and exit

  USAGE

    1) 使用指定的CPU亲和性运行一个新程序

      taskset [-c] mask command [arg]...

        举例:使用CPU0运行ls命令显示/etc/init.d下的所有内容 

          taskset -c 0 ls -al /etc/init.d/

    2) 显示已经运行的进程的CPU亲和性

      taskset -p pid

        举例:查看init进程(PID=1)的CPU亲和性

          taskset -p 1

    3) 改变已经运行进程的CPU亲和力

        taskset -p[c] mask pid

        举例:打开2个终端,在第一个终端运行top命令,第二个终端中

          首先运行:[~]# ps -eo pid,args,psr | grep top #获取top命令的pid和其所运行的CPU号

          其次运行:[~]# taskset -cp 新的CPU号 pid       #更改top命令运行的CPU号

          最后运行:[~]# ps -eo pid,args,psr | grep top #查看是否更改成功

  PERMISSIONS
        一个用户要设定一个进程的CPU亲和性,如果目标进程是该用户的,则可以设置,如果是其他用户的,则会设置失败,提示 Operation not permitted.当然root用户没有任何限制.

        任何用户都可以获取任意一个进程的CPU亲和性.

复制代码

 taskset命令其实就是使用sched_getaffinity()和sched_setaffinity()接口实现的,相信看完了第3节你也能自己实现一个taskset命令.

有兴趣的可以看一下其源代码:ftp://ftp.kernel.org/pub/linux/utils/util-linux/vX.YZ/util-linux-X.YZ-xxx.tar.gz   /schedutils/taskset.c

 

3、编程API

下面是用用于设置和获取CPU亲和性相关的API.

 

复制代码
#define _GNU_SOURCE
#include <sched.h>
#include <pthread.h> //for pthread functions(last 4) 注意<pthread.h>包含<sched.h>

/* MACRO */
    /* The following macros are provided to operate on the CPU set set */
        /* Clears set, so that it contains no CPUs */
        void CPU_ZERO(cpu_set_t *set);
        void CPU_ZERO_S(size_t setsize, cpu_set_t *set);
        
        /* Add CPU cpu to set */
        void CPU_SET(int cpu, cpu_set_t *set);
        void CPU_SET_S(int cpu, size_t setsize, cpu_set_t *set);
        
        /* Remove CPU cpu from set */
        void CPU_CLR(int cpu, cpu_set_t *set);
        void CPU_CLR_S(int cpu, size_t setsize, cpu_set_t *set);
        
        /* Test to see if CPU cpu is a member of set */
        int CPU_ISSET(int cpu, cpu_set_t *set);
        int CPU_ISSET_S(int cpu, size_t setsize, cpu_set_t *set);
        
        /* Return the number of CPUs in set */
        void CPU_COUNT(cpu_set_t *set);
        void CPU_COUNT_S(size_t setsize, cpu_set_t *set);
    
    /* The following macros perform logical operations on CPU sets */
        /* Store the logical AND of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */
        void CPU_AND(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
        void CPU_AND_S(size_t setsize, cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
        
        /* Store the logical OR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */
        void CPU_OR(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
        void CPU_OR_S(size_t setsize, cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
        
        /* Store  the logical XOR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */
        void CPU_XOR(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
        void CPU_XOR_S(size_t setsize, cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
        
        /* Test whether two CPU set contain exactly the same CPUs. */
        int CPU_EQUAL(cpu_set_t *set1, cpu_set_t *set2);
        int CPU_EQUAL_S(size_t setsize, cpu_set_t *set1, cpu_set_t *set2);
    
    /* The following macros are used to allocate and deallocate CPU sets: */
        /* Allocate a CPU set large enough to hold CPUs in the range 0 to num_cpus-1 */
        cpu_set_t *CPU_ALLOC(int num_cpus);
    
        /* Return the size in bytes of the CPU set that would be needed to  hold  CPUs  in the  range 0 to num_cpus-1. 
           This macro provides the value that can be used for the setsize argument in the CPU_*_S() macros */
        size_t CPU_ALLOC_SIZE(int num_cpus);
        
        /* Free a CPU set previously allocated by CPU_ALLOC(). */
        void CPU_FREE(cpu_set_t *set);

/* API */
    /* Set the CPU affinity for a task */
    int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
    /* Get the CPU affinity for a task */
    int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
    
    /* set CPU affinity attribute in thread attributes object */
    int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);
    /* get CPU affinity attribute in thread attributes object */
    int pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);
    
    /* set CPU affinity of a thread */
    int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
    /* get CPU affinity of a thread */
    int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);
复制代码

相关的宏通常都分为2种,一种是带_S后缀的,一种不是不带_S后缀的, 从声明上看带_S后缀的宏都多出一个参数 setsize.

从功能上看他们的区别是带_S后缀的宏是用于操作动态申请的CPU set(s),所谓的动态申请其实就是使用宏 CPU_ALLOC 申请,

参数setsize 可以是通过宏 CPU_ALLOC_SIZE 获得,两者的用法详见下面的例子.

相关的API只有6个, 前2个是用来设置进程的CPU亲和性,需要注意的一点是,当这2个API的第一个参数pid为0时,表示使用调用进程的进程ID;

后4个是用来设置线程的CPU亲和性。其实sched_setaffinity()也可以用来设置线程的CPU的亲和性,也就是taskset “-a”选项中提到的TID概念。

3.1 例子一:使用2种方式(带和不带_S后缀的宏)获取当前进程的CPU亲和性

复制代码
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h> /* sysconf */
#include <stdlib.h> /* exit */
#include <stdio.h>

int main(void)
{
    int i, nrcpus;
    cpu_set_t mask;
    unsigned long bitmask = 0;
    
    CPU_ZERO(&mask);
    
     /* Get the CPU affinity for a pid */
    if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) 
    {   
        perror("sched_getaffinity");
        exit(EXIT_FAILURE);
    }
    
       /* get logical cpu number */
    nrcpus = sysconf(_SC_NPROCESSORS_CONF);
    
    for (i = 0; i < nrcpus; i++)
    {
        if (CPU_ISSET(i, &mask))
        {
            bitmask |= (unsigned long)0x01 << i;
            printf("processor #%d is set\n", i); 
        }
    }
    printf("bitmask = %#lx\n", bitmask);

    exit(EXIT_SUCCESS);
}
/*----------------------------------------------------------------*/
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h> /* sysconf */
#include <stdlib.h> /* exit */
#include <stdio.h>

int main(void)
{
    int i, nrcpus;
    cpu_set_t *pmask;
    size_t cpusize;
    unsigned long bitmask = 0;

    /* get logical cpu number */
    nrcpus = sysconf(_SC_NPROCESSORS_CONF);
    
    pmask = CPU_ALLOC(nrcpus);
    cpusize = CPU_ALLOC_SIZE(nrcpus);
    CPU_ZERO_S(cpusize, pmask);
    
    /* Get the CPU affinity for a pid */
    if (sched_getaffinity(0, cpusize, pmask) == -1) 
    {
        perror("sched_getaffinity");
        CPU_FREE(pmask);
        exit(EXIT_FAILURE);
    }
    for (i = 0; i < nrcpus; i++)
    {
        if (CPU_ISSET_S(i, cpusize, pmask))
        {
             bitmask |= (unsigned long)0x01 << i;
            printf("processor #%d is set\n", i); 
        }
    }
      printf("bitmask = %#lx\n", bitmask);
      
    CPU_FREE(pmask);
    exit(EXIT_SUCCESS);
}
复制代码

  执行结果如下(4核CPU):

  执行结果

 

 3.2 例子二:设置进程的CPU亲和性后再获取显示CPU亲和性

复制代码
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h> /* sysconf */
#include <stdlib.h> /* exit */
#include <stdio.h>

int main(void)
{
    int i, nrcpus;
    cpu_set_t mask;
    unsigned long bitmask = 0;
    
    CPU_ZERO(&mask);
    
    CPU_SET(0, &mask); /* add CPU0 to cpu set */
    CPU_SET(2, &mask); /* add CPU2 to cpu set */

      /* Set the CPU affinity for a pid */
    if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) 
    {   
        perror("sched_setaffinity");
        exit(EXIT_FAILURE);
    }
    
    CPU_ZERO(&mask);
    
     /* Get the CPU affinity for a pid */
    if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) 
    {   
        perror("sched_getaffinity");
        exit(EXIT_FAILURE);
    }

       /* get logical cpu number */
    nrcpus = sysconf(_SC_NPROCESSORS_CONF);
    
    for (i = 0; i < nrcpus; i++)
    {
        if (CPU_ISSET(i, &mask))
        {
            bitmask |= (unsigned long)0x01 << i;
            printf("processor #%d is set\n", i); 
        }
    }
    printf("bitmask = %#lx\n", bitmask);

    exit(EXIT_SUCCESS);
}
复制代码

 

 3.3 例子三:设置线程的CPU属性后再获取显示CPU亲和性

这个例子来源于Linux的man page.

复制代码
#define _GNU_SOURCE
#include <pthread.h> //不用再包含<sched.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;
    
    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++) //CPU_SETSIZE 是定义在<sched.h>中的宏,通常是1024
    {
        if (CPU_ISSET(j, &cpuset))
        {
            printf("    CPU %d\n", j);
        }
    }
    exit(EXIT_SUCCESS);
}
复制代码

 

 

3.4 例子四:使用seched_setaffinity设置线程的CPU亲和性

复制代码
#define _GNU_SOURCE
#include <sched.h>
#include <stdlib.h>
#include <sys/syscall.h> // syscall

int main(void)
{
    pid_t tid;
    int i, nrcpus;
    cpu_set_t mask;
    unsigned long bitmask = 0;
    
    CPU_ZERO(&mask);
    CPU_SET(0, &mask); /* add CPU0 to cpu set */
    CPU_SET(2, &mask); /* add CPU2 to cpu set */

    // get tid(线程的PID,线程是轻量级进程,所以其本质是一个进程)
    tid = syscall(__NR_gettid); // or syscall(SYS_gettid);

      /* Set the CPU affinity for a pid */
    if (sched_setaffinity(tid, sizeof(cpu_set_t), &mask) == -1) 
    {
        perror("sched_setaffinity");
        exit(EXIT_FAILURE);
    }
    
    exit(EXIT_SUCCESS);
}
复制代码

 

 

 

---------------------------------------------------------------------------------------------------------------------

参考文献:

http://www.yboren.com/posts/44412.html?utm_source=tuicool

http://www.ibm.com/developerworks/cn/linux/l-affinity.html

http://saplingidea.iteye.com/blog/633616

http://blog.csdn.net/ttyttytty12/article/details/11726569

 https://en.wikipedia.org/wiki/Processor_affinity

http://blog.chinaunix.net/uid-23622436-id-3311579.html

http://www.cnblogs.com/emanlee/p/3587571.html

http://blog.chinaunix.net/uid-26651253-id-3342161.html

http://blog.csdn.net/delphiwcdj/article/details/8476547

http://www.man7.org/linux/man-pages/man3/pthread_setaffinity_np.3.html

http://www.man7.org/linux/man-pages/man3/pthread_attr_setaffinity_np.3.html

man CPU_SET taskset


管理处理器的亲和性(affinity)

原文地址:http://www.ibm.com/developerworks/cn/linux/l-affinity.html#download

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值