linux下讓程序執行在指定的cpu上

2021-08-31 12:29:42 字數 4995 閱讀 6033

收藏

最近負責的svr壓力比較大,業務邏輯有點複雜,能優化的地方已經全部優化了,

目前每秒3k次,cpu負載還是比較高

top看一下,4核的cpu負載不是太均衡,打算考慮一下將業務程序指定到3個cpu上執行,另外乙個cpu專門負責處理網路收發包;打算嘗試一下,如果還是不行,再過段時間,訪問量再增加的話,就要加機器了,嗚嗚

補充:今天測試了一下,效果挺好,同樣程序數的情況下,進行cpu繫結

每個cpu都利用起來了,負載也比不繫結的情況下好了很多

分析一下有效果的原因:

看了《linux核心設計與實現》的42節,覺得人為控制一下cpu的繫結還是有用處的

1、linux的smp負載均衡是基於程序數的,每個cpu都有乙個可執行程序佇列,只有當其中乙個cpu的可執行佇列裡程序數比其他cpu佇列程序數多25%時,才會將程序移動到另外空閒cpu上,也就是說cpu0上的程序數應該是比其他cpu上多,但是會在25%以內

2、我們的業務中耗費cpu的分四種型別,(1)網絡卡中斷(2)1個處理網路收發包程序(3)耗費cpu的n個worker程序(4)其他不太耗費cpu的程序

基於1中的 負載均衡是針對程序數,那麼(1)(2)大部分時間會出現在cpu0上,(3)的n個程序會隨著排程,平均到其他多個cpu上,(4)裡的程序也是隨著排程分配到各個cpu上;

當發生網絡卡中斷的時候,cpu被打斷了,處理網絡卡中斷,那麼分配到cpu0上的worker程序肯定是執行不了的

其他cpu上不是太耗費cpu的程序獲得cpu時,就算它的時間片很短,它也是要執行的,那麼這個時候,你的worker程序還是被影響到了;按照排程邏輯,一種非常惡劣的情況是:(1)(2)(3)的程序全部分配到cpu0上,其他不太耗費cpu的程序數很多,全部分配到cpu1,cpu2,cpu3上。。那麼網絡卡中斷發生的時候,你的業務程序就得不到cpu了

如果從業務的角度來說,worker程序執行越多,肯定業務處理越快,人為的將它**到其他負載低的cpu上,肯定能提高worker程序使用cpu的時間

找了個例子:

現在多cpu的趨勢越來越大了. 有時候為了更好地操作機器, 需要將某個程序繫結到具體的cpu上去. 下面給出了乙個程序繫結到具體的cpu上去的乙個例子.

view plaincopy to clipboardprint?

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······15001.#include

02.#include

03.#include

04.#include

05.#include

06.

07.#define __use_gnu

08.#include

09.#include

10.#include

11.

12.int main(int argc, char* argv)

13.

28.

29. myid = atoi(argv[1]);

30.

31. printf("system has %i processor(s). \n", num);

32.

33. cpu_zero(&mask);

34. cpu_set(myid, &mask);

35.

36. if (sched_setaffinity(0, sizeof(mask), &mask) == -1)

37.

40. while (1)

41.

48. for (i = 0; i < num; i++)

49.

54. }

55. }

56. return 0;

57.}

#include

#include

#include

#include

#include

#define __use_gnu

#include

#include

#include

int main(int argc, char* argv)

myid = atoi(argv[1]);

printf("system has %i processor(s). \n", num);

cpu_zero(&mask);

cpu_set(myid, &mask);

if (sched_setaffinity(0, sizeof(mask), &mask) == -1)

while (1)

for (i = 0; i < num; i++)}}

return 0;

}下面是在兩個終端分別執行了./cpu 0 ./cpu 2 後得到的結果. 效果比較明顯.

quote:

cpu0 : 5.3%us, 5.3%sy, 0.0%ni, 87.4%id, 0.0%wa, 0.0%hi, 2.0%si, 0.0%st

cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

cpu2 : 5.0%us, 12.2%sy, 0.0%ni, 82.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

cpu4 : 0.0%us, 0.0%sy, 0.0%ni, 99.7%id, 0.3%wa, 0.0%hi, 0.0%si, 0.0%st

cpu5 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

cpu6 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

cpu7 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

///cpu affinity (cpu親合力)

cpu親合力就是指在linux系統中能夠將乙個或多個程序繫結到乙個或多個處理器上執行.

乙個程序的cpu親合力掩碼決定了該程序將在哪個或哪幾個cpu上執行.在乙個多處理器系統中,設定cpu親合力的掩碼可能會獲得更好的效能.

乙個cpu的親合力掩碼用乙個cpu_set_t結構體來表示乙個cpu集合,下面的幾個巨集分別對這個掩碼集進行操作:

cpu_zero() 清空乙個集合

cpu_set()與cpu_clr()分別對將乙個給定的cpu號加到乙個集合或者從乙個集合中去掉.

cpu_isset()檢查乙個cpu號是否在這個集合中.

其實這幾個的用法與select()函式那幾個呼叫差不多.

下面兩個函式就是最主要的了:

sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)

該函式設定程序為pid的這個程序,讓它執行在mask所設定的cpu上.如果pid的值為0,則表示指定的是當前程序,使當前程序執行在mask所設定的那些cpu上.第二個引數cpusetsize是

mask所指定的數的長度.通常設定為sizeof(cpu_set_t).如果當前pid所指定的cpu此時沒有執行在mask所指定的任意乙個cpu上,則該指定的程序會從其它cpu上遷移到mask的指定的

乙個cpu上執行.

sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)

該函式獲得pid所指示的程序的cpu位掩碼,並將該掩碼返回到mask所指向的結構中.即獲得指定pid當前可以執行在哪些cpu上.同樣,如果pid的值為0.也表示的是當前程序.

這幾個巨集與函式的具體用法前面已經有講解.

關於cpu_set_t的定義

# define __cpu_setsize 1024

# define __ncpubits (8 * sizeof (__cpu_mask))

typedef unsigned long int __cpu_mask;

# define __cpuelt(cpu) ((cpu) / __ncpubits)

# define __cpumask(cpu) ((__cpu_mask) 1 << ((cpu) % __ncpubits))

typedef struct

cpu_set_t;

# define __cpu_zero(cpusetp) \

do while (0)

# define __cpu_set(cpu, cpusetp) \

((cpusetp)->__bits[__cpuelt (cpu)] |= __cpumask (cpu))

# define __cpu_clr(cpu, cpusetp) \

((cpusetp)->__bits[__cpuelt (cpu)] &= ~__cpumask (cpu))

# define __cpu_isset(cpu, cpusetp) \

(((cpusetp)->__bits[__cpuelt (cpu)] & __cpumask (cpu)) != 0)

在我的機器上sizeof(cpu_set_t)的大小為128,即一共有1024位.第一位代表乙個cpu號.某一位為1則表示某程序可以執行在該位所代表的cpu上.例如

cpu_set(1, &mask);

則mask所對應的第2位被設定為1.

此時如果printf("%d\n", mask.__bits[0]);就列印出2.表示第2位被置為1了.

具體我是參考man sched_setaffinity文件中的函式的.

然後再參考了一下ibm的 developerworks上的乙個講解

linux下讓程序執行在指定的cpu上

最近負責的svr壓力比較大,業務邏輯有點複雜,能優化的地方已經全部優化了,目前每秒3k次,cpu負載還是比較高 top看一下,4核的cpu負載不是太均衡,打算考慮一下將業務程序指定到3個cpu上執行,另外乙個cpu專門負責處理網路收發包 打算嘗試一下,如果還是不行,再過段時間,訪問量再增加的話,就要...

linux下讓程序執行在指定的cpu上

最近負責的svr壓力比較大,業務邏輯有點複雜,能優化的地方已經全部優化了,目前每秒3k次,cpu負載還是比較高 top看一下,4核的cpu負載不是太均衡,打算考慮一下將業務程序指定到3個cpu上執行,另外乙個cpu專門負責處理網路收發包 打算嘗試一下,如果還是不行,再過段時間,訪問量再增加的話,就要...

讓程序執行在指定的CPU

我的linode十分繁忙,在跑一些密集運算元據庫的rake任務時尤其如此。但我觀察發現,linode伺服器的4核cpu,只有第1個核心 cpu 0 非常忙,其他都處於idle狀態。不了解linux是如何排程的,但在linode的這種狀態下,顯然有優化的餘地。除了處理正常任務,cpu 0還需要處理各種...