linux cpu繫結
一、說明
執行環境:虛擬機器 gentoo4.4.6 ,3核心cpu
gcc 4.9.3
參考資料:文中部分程式碼和內容參照以下網路資料,如有侵權,請及時聯絡。
Linux程序或執行緒繫結到CPU:
《unix環境高階程式設計》第11章:執行緒
二、中斷繫結cpu
以網絡卡中斷為例:對於網絡卡中斷來說,有時會因為大量的網路中斷導致cpu繁忙,可以通過將網絡卡中斷繫結到特定的cpu,這樣即使網路再繁忙,也不會使cpu響應其它請求變得太慢。
圖中說明網絡卡中斷為19,其smp_affinity 0x07,注意,這個值是以16進製表示,換成二進位制就是
如果只讓網絡卡中斷繫結一個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);