第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++;
        }
    }

}

程序運行后任務管理器效果如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM