1. 程式人生 > >linux cpu繫結

linux cpu繫結

一、說明

執行環境:虛擬機器 gentoo4.4.6 3核心cpu

          gcc 4.9.3

參考資料:文中部分程式碼和內容參照以下網路資料,如有侵權,請及時聯絡。

        Linux程序或執行緒繫結到CPU

        unix環境高階程式設計》第11章:執行緒

二、中斷繫結cpu

 以網絡卡中斷為例:對於網絡卡中斷來說,有時會因為大量的網路中斷導致cpu繁忙,可以通過將網絡卡中斷繫結到特定的cpu,這樣即使網路再繁忙,也不會使cpu響應其它請求變得太慢。

 

圖中說明網絡卡中斷為19,其smp_affinity 0x07,注意,這個值是以16進製表示,換成二進位制就是

0111, 也就說明3cpu核心都可以相應網絡卡中斷(虛擬機器中設定了該系統使用3cpu),

   如果只讓網絡卡中斷繫結一個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佔用情況看,虛擬機器中的3cpu感覺都快滿了。這一結果與網友的一篇部落格不符合:

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消耗了,我們就能控制只佔用一個cpuusr部分

   此外,我也做過小實驗,用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比較悠閒,且其它兩個cpusys佔用也很低

   列印語句: 如果指定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);