編程之美第一道題目就是如何讓CPU使用率曲線成為一條正弦曲線,本文在Linux下實現這個效果。
程序運行時間
一個進程的運行時間大致分為user time,kernel time和waiting time
三個時間加起來就是進程從開始到結束用的時間。
user time是進程在用戶空間執行的時間
kernel time是進程在內核空間執行的時間
waiting time是進程等待IO或者其他事件所用的時間
例如
- int main()
- {
- int i;
- for(i = 0; i < 100000000; i ++) //用戶空間執行
- getpid(); //系統調用,內核空間執行
- //scanf和printf是C標准庫裡的,還要調用Linux的系統調用read和write
- scanf("%d\n",&i);
- printf("%d\n",i);
- return 0;
- }
使用time命令可以顯示進程運行的時間,real,user,sys。大部分時間都用來等IO了,因為人輸入的速度遠小於計算機的速度。
CPU的使用率是指所有進程的user time和kernel time之和除以real time。而一般情況下,user time遠大於kernel time。
如果一個系統中CPU使用率幾乎為0,那麼我們可以寫個程序控制CPU的使用率。
- while(1)
- {
- for(i = 0; i < 100000; i ++); //CPU忙,占用的時間是user time
- usleep(10000); //CPU閒,屬於waiting time
- }
讓CPU一直維持在50%
讓進程50%的時間做循環,%50的時間sleep就行了
- int main()
- {
- int i;
- while(1)
- {
- for(i = 0; i < n; i++);
- usleep(m);
- }
- return 0;
- }
關鍵是如何確定n和m的值。
我們先把m定死,進程睡眠60ms,linux調度時的時間片好像是15ms,但是usleep精度較低,所以我們讓它睡的時間長點。
然後再確定n,先隨便給n一個值,看看匯編代碼裡使用了幾條指令:
- .L2:
- movl $0, -8(%ebp)
- jmp .L3
- .L4:
- addl $1, -8(%ebp)
- .L3:
- cmpl $3999999, -8(%ebp)
- jle .L4
- movl $60000, (%esp)
- call usleep
- jmp .L2
紅色的是內層循環,有3條指令。CPU主頻是2.27GHz,如果按一個時鐘周期執行一條的話,那麼執行三條指令的時間為2.27x10-9x3 = 6.9x10-9s,要執行60ms,循環數n的大小為
60x10-3 / 6.9x10-9 = 8.69 x 106
試一試這個數,8690000
CPU使用率穩定在38%左右,看來我們低估了CPU的能力。我們可以根據38%這個數計算出n的大小了
CPU時間/(CPU時間+60ms)= 38%,因此86900使用的cpu時間為 36ms,8690000:36=n:60,求得n等於1448333,這次CPU使用率很精確的停留在50%左右。