第一个简单的例子,
思路:
window任务管理器中的CPU利用率是怎样统计得到的(刷新周期1s内,CPU忙时间/刷新周期)
=〉CPU忙指什么(执行指令),CPU什么时候闲(Idle process)
=〉怎样[编程]让CPU忙,怎样让CPU闲? (空循环跑:忙; Sleep:闲)
=〉怎样编程控制忙的比例,让比例为想要的值(控制空循环的次数,控制闲的时间)
=〉idle时间长度确定,考虑操作系统调度(sleep(10))
=〉控制忙循环的确定(1. for循环,机器指令->汇编语言,结合CPU主频,估算迭代次数 =〉CPU忙时间长度)
(2. while循环,利用系统调用GetTickCount(),直到while循环持续了指定长度时间)
=〉*考虑其他进程的因素(利用额外工具,查询获得当前CPU利用率,动态决定是需要sleep,还是执行查询[忙])
=> 画正弦曲线,需要确定作图时一个周期上全部点的坐标,每个点的纵坐标有busy和sleep两部分构成,点间距取多少?书中给出的INTERVAL取300ms而不是更新周期1秒,不过,应该问题也不大。
实际编程实现画正弦函数,代码跟书上基本一样,只是在main函数最开始的地方调用了SetThreadAffinityMask函数来指定CPU,以防止线程迁移。
HANDLE h_cur = GetCurrentThread();
SetThreadAffinityMask(h_cur, 0x01);
SetThreadAffinityMask(h_cur, 0x01);
测试平台:1.Intel(R) Core(TM)2 Duo CPU T5850 @ 2.16GHz + VC++6
2. AMD Athlon(tm) II X2 245 + vs2010
程序在我的华硕本上跑,机器比较老,08年款机器,自带CPU是Intel(R) Core(TM)2 Duo CPU T5850 @ 2.16GHz,就是双核CPU,所以需要做CPU指定,即便如此出来结果还是很烂。
大概就是这样,在低谷的时候增长很缓慢,到了40%的时候一下子蹭蹭地飚上去了,但是又达不到100%。下降的时候起初降的比较慢,到80%的时候又一下子掉下去了,非常的奇怪。
百思不得其解之下又看了看书,书中提到“CPU主频会随电压和负荷而变化”,果然,从任务管理器可以看到,CPU在负荷较低时,主频为0.98GHz,随着负载增加,超过阈值后,主频变高(>25%:~1.3GHz,>40%: ~2.12GHz)。
我猜测应该是GetTickCount()或者Sleep()函数受到影响。
网上查了一下,GetTickCount()函数是由两个数相乘得到
t = shr(TickCountLow * TickCountMultiplier, 24);
TickCountLow - it is updated each time the clock ticks
TickCountMultiplier - it is calculated at system boot, look function ExComputeTickCountMultiplier
中文资料也说的差不多。
TickCountLow 表示机器启动后的滴答数(tick)。TickCountMultiplier表示每个滴答数的时间间隔:1毫秒的2^(-24)。
所以要取毫秒数时两值相乘后右移24位就可以了。
但是很奇怪,在台式机上AMD Athlon(tm) II X2 245上,也是双核,稍微修改了常量参数,但是结果还不错。
const int COUNT = 40;
const int INTERVAL = 1000;
const float SPLIT = 0.05;
const float PI = 3.1415926;
const int INTERVAL = 1000;
const float SPLIT = 0.05;
const float PI = 3.1415926;
但是同样代码在Duo CPU上就是有问题
备注:后续再尝试在笔记本上装vs2010重跑。
附1:C++代码
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main(int argc, char* argv[])
{
HANDLE h_cur = GetCurrentThread();
SetThreadAffinityMask(h_cur, 0x01);
/* const int COUNT = 200;
const int INTERVAL = 300;
const float SPLIT = 0.01;
const float PI = 3.1415926;*/
const int COUNT = 40;
const int INTERVAL = 1000;
const float SPLIT = 0.05;
const float PI = 3.1415926;
DWORD busyspan[COUNT];
DWORD idlespan[COUNT];
float radian = 0.0;
int half = INTERVAL/2;
for(int i=0; i<COUNT; i++){
busyspan[i] = (DWORD)(half + sin(PI*radian)*half);
idlespan[i] = INTERVAL - busyspan[i];
radian += SPLIT;
}
printf("busyspan:\n");
for(i=0; i<COUNT; i++){
printf("%d ",busyspan[i]);
}
int j = 0;
int k = 0;
DWORD startTime;
/*sin curve*/
while(1){
j = j%COUNT;
k = 0;
startTime = GetTickCount();
while((GetTickCount() - startTime) <= busyspan[j])
k++;
Sleep(idlespan[j]);
j++;
}
/*horizon curve*/
/*while(1){
startTime = GetTickCount();
while((GetTickCount() - startTime) <= 20)
;
Sleep(10);
}*/
return 0;
}