《编程之美》读书笔记(一)——CPU利用率控制

第一个简单的例子, 思路:
      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);

测试平台: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;




但是同样代码在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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值