zoukankan      html  css  js  c++  java
  • 编程之美 — 让CPU占用率绘制任意图形

      《编程之美》第一章给出了一个面试题:

      写一个程序,让用户来决定Windows任务管理器(Task Manager)的CPU占用率,程序越精简越好,计算机语言不限。例如,你可以实现下面三种情况:

      1.CPU的占用率固定在50%,为一条直线;

      2.CPU的占用率为一条直线,但具体占用率由命令行参数决定(参数范围1~100);

      3.CPU的占用率状态是一条正弦曲线。

      最一般的思路:CPU占用率为一条直线,首先要搞清楚什么是CPU占用率,CPU占用率是你运行的程序占用的CPU资源,表示你的机器在某个时间点的运行程序的情况。其实在某一时间点,CPU要么被占用,要么没被占用,即占用率要么为1,要么为0;那为什么还有占用率为50%之说呢,其实这里的时间指的一段时间,这个时间对人来可能就是滴答一下就流逝了,人的感觉可能是一个时间点,但对于机器来说,这就是一个时间段,时间周期。这样就好理解了,在一段时间内,CPU占用率就是CPU被占用的时间除以这段时间的总时间,即:

      CPU占用率 = CPU被占用的时间 / 总时间

      在《编程之美》中已经给出了根据CPU主频计算for(int i = 0; i < n; i++)循环n的大小,我的电脑的主频是2.00GHZ,所以for里面运行1s才跳出的n的大小为:

      2 × 109 × 2 ÷ 5 = 8 × 108,其中后面乘以2表示CPU每个时钟周期执行两条代码,而for(int i = 0; i < n; i++);转成汇编是5条,所以除以5。

      为了接近Windows的调试时间片,取Sleep(10),那么此时,n取8000000。

      具体程序如下:

    #include <iostream>
    #include <windows.h>
    using namespace std;
    
    int main()
    {
        while(true)
        {
            for(int i = 0; i < 8000000; i++)
            {
                ;
            }
    
            Sleep(10);
        }
    
        return 0;
    }

      运行结果:

      结果几近一条直线,但有较大的波动,特别是你还在运行其它程序时,比如拖到鼠标,波动会更大。

      上面计算存在许多近似:n计算的近似;以for()循环汇编代码的条数代替CPU时钟周期执行的代码数等等。

      可利用GetTickCount()更精确获取系统时间,GetTickCount()获取的是系统到“现在”所经历时间的毫秒数。

    #include <iostream>
    #include <windows.h>
    using namespace std;
    int main() { _int64 start_time = 0; int run_time = 10; int sleep_time = run_time; while(true) { start_time = GetTickCount(); while((GetTickCount() - start_time) <= run_time); Sleep(sleep_time); } return 0; }

      运行结果:

      从结果可以看出,直线的波动较小,GetTickCount()可获取更精确的系统时间。

      下面来让CPU占用率绘制正弦曲线:

      下面是《编程之美》上的代码:

    #include <Windows.h>
    #include <stdlib.h>
    #include <math.h>
    
    const double SPLIT = 0.01;
    const int COUNT = 200;
    const double PI = 3.13159265;
    const int INTERVAL = 300;
    
    int main()
    {
        DWORD busySpan[COUNT];
        DWORD idleSpan[COUNT];
        int half = INTERVAL / 2;
        double radian = 0.0;
        for(int i = 0; i < COUNT; i++)
        {
            busySpan[i] = (DWORD)(half + (sin(PI * radian) * half));
            idleSpan[i] = INTERVAL - busySpan[i];
            radian += SPLIT;
    
        }
    
        DWORD startTime = 0;
        int j = 0;
        while(true)
        {
            j = j % COUNT;
            startTime = GetTickCount();
            while((GetTickCount() - startTime) <= busySpan[j])
            {
                ;
            }
            Sleep(idleSpan[j]);
            j++;
        }
        
        return 0;
    }

      运行结果:

      这里主要讲下下面代码的意思:

     for(int i = 0; i < COUNT; i++)
        {
            busySpan[i] = (DWORD)(half + (sin(PI * radian) * half));
            idleSpan[i] = INTERVAL - busySpan[i];
            radian += SPLIT;
    
        }

      我们知道绘制一条正弦曲线,只要知道0~2∏之间的CPU占用率的值就行了,其它就是周期移动就行了。

      题目要求CPU占用率为正弦曲线,所以不仿设busySpan[i] / (busySpan[i] + idleSpan[i]) = asin(∏ti + φ) + b;

      还知道busySpan[i] / (busySpan[i] + idleSpan[i]) + idleSpan[i] / (busySpan[i] + idleSpan[i]) = 1,这里(busySpan[i] + idleSpan[i])等于INTERVAL。综合上面两个方面,可取φ = 0;a = b = INTERVAL/2。

      ∏ × SPLIT × COUNT = 2∏,正好为正弦函数的一个周期。

      扩展:如何让CPU占用率为半圆形曲线

      参考程序如下:

    #include <windows.h>
    #include <stdlib.h>
    #include <math.h>
    
    const double SPLIT = 0.01;
    const int COUNT = 200;
    const int INTERVAL = 300;
    
    int main()
    {
        DWORD busySpan[COUNT];
        DWORD idleSpan[COUNT];
        double radian = 0.0;
        for(int i = 0; i < COUNT; i++)
        {
            busySpan[i] = (DWORD)(INTERVAL * sqrt(1 - pow((1 - radian) , 2)));
            idleSpan[i] = INTERVAL - busySpan[i];
            radian += SPLIT;
    
        }
    
        DWORD startTime = 0;
        int j = 0;
        while(true)
        {
            j = j % COUNT;
            startTime = GetTickCount();
            while((GetTickCount() - startTime) <= busySpan[j])
            {
                ;
            }
            Sleep(idleSpan[j]);
            j++;
        }
    
        return 0;
    }

      运行结果:

      当然你还可以让它绘制出更漂亮的图形。

  • 相关阅读:
    用ps 查看线程状态
    机器学习资料收集
    [转]漫谈数据中心CLOS网络架构
    MBR中“起始磁头/扇区/柱面“同"逻辑区块地址(LBA)"的区别
    [转]硬盘分区表知识——详解硬盘MBR
    [转]什么是总线?什么是前端总线?
    语言的编译-汇编-链接
    计算机进行小数运算会出错

    计算机底层是如何访问显卡的?
  • 原文地址:https://www.cnblogs.com/danshui/p/2685097.html
Copyright © 2011-2022 走看看