如何指定程序執行的CPU
coolshell最新的文章《效能調優攻略》在“多核CPU調優”章節,提到“我們不能任由作業系統負載均衡,因為我們自己更瞭解自己的程式,所以,我們可以手動地為其分配CPU核,而不會過多地佔用CPU0,或是讓我們關鍵程序和一堆別的程序擠在一起。”。在文章中提到了Linux下的一個工具,taskset,可以設定單個程序執行的CPU。
同時,因為最近在看redis的相關資料,redis作為單程序模型的程式,為了充分利用多核CPU,常常在一臺server上會啟動多個例項。而為了減少切換的開銷,有必要為每個例項指定其所執行的CPU。
下文,將會介紹taskset命令,以及sched_setaffinity系統呼叫,兩者均可以指定程序執行的CPU例項。
1.taskset
taskset是LINUX提供的一個命令(ubuntu系統可能需要自行安裝,schedutils package)。他可以讓某個程式執行在某個(或)某些CPU上。
以下均以redis-server舉例。
1)顯示程序執行的CPU
命令taskset -p 21184
顯示結果:
pid 21184's current affinity mask: ffffff
注:21184是redis-server執行的pid
顯示結果的ffffff實際上是二進位制24個低位均為1的bitmask,每一個1對應於1個CPU,表示該程序在24個CPU上執行
2)指定程序執行在某個特定的CPU上
命令taskset -pc 3 21184
顯示結果:
pid 21184's current affinity list: 0-23
pid 21184's new affinity list: 3
注:3表示CPU將只會執行在第4個CPU上(從0開始計數)。
3)程序啟動時指定CPU
命令taskset -c 1 ./redis-server ../redis.conf
結合這上邊三個例子,再看下taskset的manual,就比較清楚了。
OPTIONS
-p, --pid
operate on an existing PID and not launch a new task
-c, --cpu-list
specify a numerical list of processors instead of a bitmask. The list may contain multiple items, separated by comma, and ranges. For example, 0,5,7,9-11.
2.sched_setaffinity系統呼叫
問題描述
sched_setaffinity可以將某個程序繫結到一個特定的CPU。你比作業系統更瞭解自己的程式,為了避免排程器愚蠢的排程你的程式,或是為了在多執行緒程式中避免快取失效造成的開銷,你可能會希望這樣做。如下是sched_setaffinity的例子,其函式手冊可以參考(http://www.linuxmanpages.com/man2/sched_getaffinity.2.php):
1 /* Short test program to test sched_setaffinity 2 * (which sets the affinity of processes to processors). 3 * Compile: gcc sched_setaffinity_test.c 4 * -o sched_setaffinity_test -lm 5 * Usage: ./sched_setaffinity_test 6 * 7 * Open a "top"-window at the same time and see all the work 8 * being done on CPU 0 first and after a short wait on CPU 1. 9 * Repeat with different numbers to make sure, it is not a 10 * coincidence. 11 */ 12 13 #include <stdio.h> 14 #include <math.h> 15 #include <sched.h> 16 17 double waste_time(long n) 18 { 19 double res = 0; 20 long i = 0; 21 while(i <n * 200000) { 22 i++; 23 res += sqrt (i); 24 } 25 return res; 26 } 27 28 int main(int argc, char **argv) 29 { 30 unsigned long mask = 1; /* processor 0 */ 31 32 /* bind process to processor 0 */ 33 if (sched_setaffinity(0, sizeof(mask), &mask) <0) { 34 perror("sched_setaffinity"); 35 } 36 37 /* waste some time so the work is visible with "top" */ 38 printf ("result: %f\n", waste_time (2000)); 39 40 mask = 2; /* process switches to processor 1 now */ 41 if (sched_setaffinity(0, sizeof(mask), &mask) <0) { 42 perror("sched_setaffinity"); 43 } 44 45 /* waste some more time to see the processor switch */ 46 printf ("result: %f\n", waste_time (2000)); 47 }
根據你CPU的快慢,調整waste_time的引數。然後使用top命令,就可以看到程序在不同CPU之間的切換。(啟動top命令後按“1”,可以看到各個CPU的情況)。
父程序和子程序之間會繼承對affinity的設定。因此,大膽猜測,taskset實際上是首先執行了sched_setaffinity系統呼叫,然後fork+exec使用者指定的程序。