CPU綁定和CPU親和性

將進程/線程與cpu綁定,最直觀的好處就是提高了cpu cache的命中率,從而減少內存訪問損耗,提高程序的速度。我覺得在NUMA架構下,這個操作對系統運行速度的提升有較大的意義,而在SMP架構下,這個提升可能就比較小。這主要是因爲兩者對於cache、總線這些資源的分配使用方式不同造成的,NUMA每個cpu有自己的一套資源體系, SMP中每個核心還是需要共享這些資源的,從這個角度來看,NUMA使用cpu綁定時,每個核心可以更專注地處理一件事情,資源體系被充分使用,減少了同步的損耗。SMP由於一部分資源的共享,在進行了綁定操作後,受到的影響還是很大的。

通過linux提供的幾個api, 可以輕鬆地完成這個優化:

#include <sched.h>

int sched_setaffinity(pid_t pid, size_t cpusetsize,cpu_set_t *mask);    //設定pid 綁定的cpu,   
int sched_getaffinity(pid_t pid, size_t cpusetsize,cpu_set_t *mask);    //查看pid 綁定的cpu。



cpu_set_t  //是一個掩碼數組,一共有1024位,每一位都可以對應一個cpu核心  
//以下宏,都是對這個掩碼進行操作的。如果需要,一個進程是可以綁定多個cpu的。  
void CPU_ZERO(cpu_set_t *set);  
void CPU_SET(int cpu, cpu_set_t *set);  
void CPU_CLR(int cpu, cpu_set_t *set);  
int CPU_ISSET(int cpu, cpu_set_t *set); 




下面是一個實例。

  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);      //如果覺得不明顯,改成這個,  

  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. }  

編譯:

  1. gcc -o cpu simple_affinity.c -lpthread  

執行./cpu [cpu num / masks] ,使用top觀察cpu使用狀況。 使用./cpu 0 時,可以發現,兩顆核心使用率都比較高, 使用./cpu 1時,可以發現,1核的壓力比較重。


當然還可以對線程進行cpu綁定。

  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


轉自:http://blog.csdn.net/joker0910/article/details/7484371
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章