zoukankan      html  css  js  c++  java
  • 第1章 游戏之乐——让CPU占用率曲线听你指挥

    让CPU占用率曲线听你指挥

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

    1. CPU的占用率固定在50%,为一条直线;
    2. CPU的占用率为一条直线,但是具体占用率由命令行参数决定(参数范围1~100);
    3. CPU的占用率状态是一个正弦曲线。

    【解法一】 简单的解法

      一个空的for循环for(int i=0;i<n;i++); 写成汇编代码后进行分析:

    loop:
    mov dx i  ;将i置入dx寄存器
    inc   dx    ;将dx从寄存器加1
    mov i  dx ;将dx中的值赋回i
    cmp i  n   ;比较i和n
    jl    loop  ; i小于n时则重复循环

    需要执行5条代码,假设要运行的CPU是2.66Ghz(2.66*10^9个时钟周期每秒)。现在CPU每个时钟周期可以执行两条以上的代码,那么我们就取平均值两条,于是让(2660000000*2)/5=1064000000(循环/秒),如果让CPU工作1秒钟,然后休息1秒钟,波形很可能就是锯齿状的——先达到一个峰值(>50%),然后跌到一个很低的占用率。

    于是尝试降两个数量级。用10ms是因为它不大不小,比较接近Windows的调度时间片。如果太小会造成线程频繁被唤醒和挂起,无形中增加了内核时间的不确定性影响。最后我们得到如下代码:

    package chapter1youxizhile;
    /**
     * 【解法一】简单的方法
     * 运行的CPU是2.66Ghz(2.66*10^9个时钟周期每秒)
     * @author DELL
     *
     */
    public class ControlCPU1 {
    
        public static void main(String[] args) {
            for( ; ; ){
                for(int i=0;i<10640000;i++);  //运行10ms
                try {
                    Thread.sleep(10);  //休眠10ms
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    
        }
    
    }

      在不断调整10640000后,我们就可以在一台指定的机器上获得一条大致稳定的50%CPU占用率直线。

    【解法二】使用System.currentTimeMillis()和Thread.sleep()

    package chapter1youxizhile;
    /**
     * 【解法二】使用System.currentTimeMillis()和Thread.sleep()
     * 运行的CPU是2.66Ghz(2.66*10^9个时钟周期每秒)
     * @author DELL
     *
     */
    public class CopyOfControlCPU2 {
        
        public static void main(String[] args) {
            int busyTime = 10;  //繁忙时间10ms
            int idleTime = busyTime;  //空闲时间
            while(true){
                long startTime = System.currentTimeMillis(); //获取系统运行时间
                while(System.currentTimeMillis()-startTime<= busyTime) ;
                try {
                    Thread.sleep(idleTime);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    
        }
    
    }

     效果如下:

      这两种解法都是假设目前系统上只有当前程序在运行,但实际上,操作系统中有很多程序会同时执行各种各样的任务,如果此刻其他进程使用了10%的CPU,那么我们的程序应该只能使用40%的CPU,这样才能达到50%的效果。

      怎么做呢?这就需要用到另个工具的帮忙——Perform.exe。如下图所示:

      我们可以写程序来查询Perform的值,Mircrosoft .Net Framework提供了PerformanceCounter这一对象,可以方便地得到当前各种性能的数据,包括CPU的使用率。例如下面这个程序:

     【解法三】能动态适应的解法

    //C# code
    static void MakeUsage(float level)
    {
        PerformanceCounter p = new PerformanceCounter("Processor", "% Processor Time", "_Total");
        while(true)
        {
            if(p.NextValue()>level)
                System.Threading.Thread.Sleep(10);
        }
    }

      可以看到,上面的解法能方便地处理各种CPU使用率的参数。这个程序可以解答前面提到的问题2。

    【解法四】正弦曲线

    package chapter1youxizhile;
    /**
     * 【解法四】正弦曲线
     * @author DELL
     *
     */
    public class CopyOfCopyOfControlCPU4 {
        static final double SPLIT = 0.01;  //2PI周期步长
        static final int COUNT = 200;  //取点个数
        static final double PI = 3.1415926;
        static final int INTERVAL = 300;  //空闲和繁忙的总时间
        public static void main(String[] args) {
            long busySpan[];  //CPU繁忙时间的数组
            long idleSpan[];  //CPU空闲时间的数组
            busySpan = new long[COUNT];
            idleSpan = new long[COUNT];
            int half = INTERVAL/2;
            double radian = 0.0;
            for(int i=0;i<COUNT;i++){
                busySpan[i] = (long) (half+(Math.sin(PI*radian)*half));
                idleSpan[i] = INTERVAL - busySpan[i];
                radian += SPLIT;
            }
            long startTime = 0;
            int j = 0;
            while(true){
                j = j%COUNT;  //实现周期循环
                startTime = System.currentTimeMillis();
                while((System.currentTimeMillis()-startTime)<=busySpan[j]) ;
                try {
                    Thread.sleep(idleSpan[j]);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                j++;
            }
        }
    
    }

    程序运行后任务管理器效果如下:

  • 相关阅读:
    新手第一次联系oracle的碰到的触发器不能创建的问题
    dubbo注册中心占位符无法解析问题(二)
    dubbo注册中心占位符无法解析问题(一)
    .
    Ubuntu16 安装后配置
    TiDB-----使用 TiUP cluster 在单机上模拟生产环境部署步骤
    TiDB 单机安装(在 Linux OS 上部署本地测试环境)
    WPF查找子控件和父控件方法
    Java基础相关
    C++ namespace浅析
  • 原文地址:https://www.cnblogs.com/gaopeng527/p/4598073.html
Copyright © 2011-2022 走看看