編程之美第一道題目就是如何讓CPU使用率曲線成爲一條正弦曲線,本文在Linux下實現這個效果。
程序運行時間
一個進程的運行時間大致分爲user time,kernel time和waiting time
- 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;
- }
- while(1)
- {
- for(i = 0; i < 100000; i ++); //CPU忙,佔用的時間是user time
- usleep(10000); //CPU閒,屬於waiting time
- }
- int main()
- {
- int i;
- while(1)
- {
- for(i = 0; i < n; i++);
- usleep(m);
- }
- return 0;
- }
- .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
注:上面說一個時鐘週期執行一條指令是不合適的,各種指令的執行時間不同。計算機裏的週期主要有時鐘週期,機器週期,指令週期。一條指令的週期稱爲指令週期,由幾個機器週期做成,而一個機器組成由幾個時鐘週期組成。上面的三條指令都需要取內存,因此時間長。如果把循環變量放在寄存器裏,那麼用的時間要小的多:
將內存數-8(%ebp)改爲寄存器數%ebx
- .L2:
- movl $0, %ebx
- jmp .L3
- .L4:
- addl $1, %ebx
- .L3:
- cmpl $13199999, %ebx
- jle .L4
- movl $60000, (%esp)
- call usleep
- jmp .L2
- //僞代碼
- int main()
- {
- int start_time, current_time;
- while(1)
- {
- start_time = GetCurrentTime();
- current_time = start_time;
- while(current_time - start_time < 60)
- current_time = GetCurrentTime();
- sleep(60);
- }
- }
- #include <stdio.h>
- #include <stdlib.h>
- int main()
- {
- struct timeval tv;
- long long start_time,end_time;
- while(1)
- {
- gettimeofday(&tv,NULL);
- start_time = tv.tv_sec*1000000 + tv.tv_usec;
- end_time = start_time;
- while((end_time - start_time) < 60000)
- {
- gettimeofday(&tv,NULL);
- end_time = tv.tv_sec*1000000 + tv.tv_usec;
- }
- usleep(60000);
- }
- return 0;
- }
現在我們用這種方法實現CPU使用率的正弦曲線。
首先要確定這個曲線的函數。這個函數的最大值是1,最小值是0,因此肯定是0.5(sin(tx) + 1)。
怎麼確定t呢?
我們可以認爲,曲線的更新週期應該大於100ms,我們以100ms爲單位,把100ms的平均使用率作爲這100ms末的使用率。
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- int main()
- {
- struct timeval tv;
- long long start_time,end_time;
- long long busy_time[100];
- long long idle_time[100];
- int i;
- for(i = 0; i < 100; i++)
- {
- busy_time[i] = 100000 * 0.5 * (sin(i*0.0628) + 1);
- idle_time[i] = 100000 - busy_time[i];
- }
- i = 0;
- while(1)
- {
- gettimeofday(&tv,NULL);
- start_time = tv.tv_sec*1000000 + tv.tv_usec;
- end_time = start_time;
- while((end_time - start_time) < busy_time[i])
- {
- gettimeofday(&tv,NULL);
- end_time = tv.tv_sec*1000000 + tv.tv_usec;
- }
- usleep(idle_time[i]);
- i = (i+1)%100;
- }
- return 0;
- }