編程之美 1.1 讓cpu佔用率曲線聽你指揮(多核處理器)

【目錄】html

不考慮其餘進程,cpu畫正弦曲線windows

獲取整體cpu利用率api

獲取多核處理器單個cpu利用率函數

考慮其餘進程,cpu畫正弦曲線ui


 

下面的程序針對多核處理器,能夠設置讓任何一個cpu顯示相應的曲線(本文以正弦曲線爲例)spa

代碼編譯環境:windows 7 64位 酷睿 i5 處理器,vs2010.線程

能夠修改CpuSin函數的計算 busySpan 和 idleSpan的部分以顯示不一樣的曲線。code

下面的代碼沒有考慮cpu中其餘進程的佔用狀況,這種狀況詳見第二部分orm

 1 #include <windows.h>
 2 #include <stdio.h>
 3 #include <math.h>
 4 
 5 //把一條正弦曲線0~2pi 之間的弧度等分200份抽樣,計算每一個點的振幅
 6 //而後每隔300ms設置下一個抽樣點,並讓cpu工做對應振幅時間
 7 const int samplingCount = 200; //抽樣點數目
 8 const double pi = 3.1415926;
 9 const int totalAmplitude = 300; //每一個抽樣點對應時間片
10 const double delta = 2.0/samplingCount;  //抽樣弧度的增量
11 
12 int busySpan[samplingCount];//每一個抽樣點對應的busy時間
13 int idleSpan[samplingCount];//每一個抽樣點對應的idle時間
14 
15 //一個線程調用MakeUsageSin,並把該線程綁定到一個cpu,那麼該cpu呈現正弦曲線
16 DWORD WINAPI MakeUsageSin(LPVOID lpParameter)
17 {
18     DWORD startTime = 0;
19     for(int j = 0; ; j = (j + 1) % samplingCount)
20     {
21         startTime = GetTickCount();
22         while ((GetTickCount() - startTime) < busySpan[j]);
23         Sleep(idleSpan[j]);
24     }
25 }
26 
27 //若是cpuindex < 0 則全部cpu都顯示正弦曲線
28 //不然只有第 cpuindex個cpu顯示正弦曲線
29 //cpuindex 從 0 開始計數
30 void CpuSin(int cpuIndex)
31 {
32     //計算 busySpan 和 idleSpan
33     double radian = 0;
34     int amplitude = totalAmplitude / 2;
35     for (int i = 0; i < samplingCount; i++)
36     {
37         busySpan[i] = (DWORD)(amplitude + sin(pi*radian)*amplitude);
38         idleSpan[i] = totalAmplitude - busySpan[i];
39         radian += delta;
40     }
41 
42     //獲取系統cup數量
43     SYSTEM_INFO SysInfo;
44     GetSystemInfo(&SysInfo);
45     int num_processors = SysInfo.dwNumberOfProcessors;
46     if(cpuIndex + 1 > num_processors)
47     {
48         printf("error: the index of cpu is out of boundary\n");
49         printf("cpu number: %d\n", num_processors);
50         printf("your index: %d\n", cpuIndex);
51         printf("** tip: the index of cpu start from 0 **\n");
52         return;
53     }
54 
55     if(cpuIndex < 0)
56     {
57         HANDLE* threads = new HANDLE[num_processors];
58         for (int i = 0;i < num_processors;i++)
59         {
60             DWORD mask = 1<<i;
61             threads[i] = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
62             SetThreadAffinityMask(threads[i], 1<<i);//線程指定在某個cpu運行
63         }
64         WaitForMultipleObjects(num_processors, threads, TRUE, INFINITE);
65     }
66     else
67     {
68         HANDLE thread;
69         DWORD mask = 1;
70         thread = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
71         SetThreadAffinityMask(thread, 1<<cpuIndex);
72         WaitForSingleObject(thread,INFINITE);
73     }
74 
75 }
76 int main()
77 {
78 
79     CpuSin(0);
80     return 0;
81 }

運行結果:htm


下面咱們考慮其餘進程對cpu的影響,即須要檢測出某個cpu當前的使用率。

首先對於單核處理器獲取cpu利用率,或者多核處理器獲取總的cpu利用率,能夠經過windows api 「GetSystemTimes」 來實現

該函數聲明以下:BOOL GetSystemTimes(LPFILETIME  IdleTime,LPFILETIME   KernelTime,LPFILETIME   UserTime),具體能夠參考msdn接口介紹

cpu利用率計算公式爲:CPURate=100.0-(NowIdleTime-LastIdleTime)/(NowKernelTime-LastKernelTime+NowUserTime-LastUserTime)*100.0

計算總的cpu利用率或者單核處理器cpu利用率的類實現以下:

 1 class CCPUUseRate
 2 {
 3 public:
 4     BOOL Initialize() 
 5     {
 6         FILETIME ftIdle, ftKernel, ftUser;
 7         BOOL flag = FALSE;
 8         if (flag = GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
 9         {
10             m_fOldCPUIdleTime = FileTimeToDouble(ftIdle);
11             m_fOldCPUKernelTime = FileTimeToDouble(ftKernel);
12             m_fOldCPUUserTime = FileTimeToDouble(ftUser);
13 
14         }
15         return flag;
16     }
17     //調用Initialize後要等待1左右秒再調用此函數
18     int GetCPUUseRate()
19     {
20         int nCPUUseRate = -1;
21         FILETIME ftIdle, ftKernel, ftUser;
22         if (GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
23         {
24             double fCPUIdleTime = FileTimeToDouble(ftIdle);
25             double fCPUKernelTime = FileTimeToDouble(ftKernel);
26             double fCPUUserTime = FileTimeToDouble(ftUser);
27             nCPUUseRate= (int)(100.0 - (fCPUIdleTime - m_fOldCPUIdleTime) 
28                 / (fCPUKernelTime - m_fOldCPUKernelTime + fCPUUserTime - m_fOldCPUUserTime) 
29                 *100.0);
30             m_fOldCPUIdleTime = fCPUIdleTime;
31             m_fOldCPUKernelTime = fCPUKernelTime;
32             m_fOldCPUUserTime = fCPUUserTime;
33         }
34         return nCPUUseRate;
35     }
36 private:
37     double FileTimeToDouble(FILETIME &filetime)
38     {
39         return (double)(filetime.dwHighDateTime * 4.294967296E9) + (double)filetime.dwLowDateTime;
40     }
41 private:
42     double m_fOldCPUIdleTime;
43     double m_fOldCPUKernelTime;
44     double m_fOldCPUUserTime;
45 };

注意:先後兩次調用GetSystemTimes之間要間隔必定時間,使用方法以下:

 1 int main()
 2 {
 3     CCPUUseRate cpuUseRate;
 4     if (!cpuUseRate.Initialize())
 5     {
 6         printf("Error! %d\n", GetLastError());
 7         getch();
 8         return -1;
 9     }
10     else
11     {
12         while (true)
13         {    
14             Sleep(1000);
15             printf("\r當前CPU使用率爲:%4d%%", cpuUseRate.GetCPUUseRate());
16         }
17     }
18     return 0;
19 }

對於計算多核處理器中單個cpu的使用率,可使用pdh.h頭文件中的接口,該頭文件是visual studio自帶的,包含該頭文件時,還須要引入相關的lib庫:

 1 #include <TCHAR.h>
 2 #include <windows.h>
 3 #include <pdh.h>
 4 #include <cstdio>
 5 #include <cmath>
 6 #pragma comment(lib, "pdh.lib")
 7 
 8 //---------------------------------------------------comput the cpu usage rate
 9 static PDH_HQUERY cpuQuery;
10 static PDH_HCOUNTER cpuTotal;
11 
12 //cpuindex 爲指定的cpu id ,從0開始
13 void init(int cpuIndex)
14 {
15     PDH_STATUS Status = PdhOpenQuery(NULL, NULL, &cpuQuery);
16     if (Status != ERROR_SUCCESS) 
17     {
18         printf("\nPdhOpenQuery failed with status 0x%x.", Status);
19         exit(-1);
20     }
21     char buf[50];
22     sprintf(buf, "\\Processor(%d)\\%% Processor Time", cpuIndex);
23     PdhAddCounter(cpuQuery, LPCSTR(buf), NULL, &cpuTotal);
24     PdhCollectQueryData(cpuQuery);
25 }
26 
27 
28 double getCpuUsageRate()
29 {
30     PDH_FMT_COUNTERVALUE counterVal;
31     PdhCollectQueryData(cpuQuery);
32     PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
33     return counterVal.doubleValue;
34 }

注:該方法也能夠計算總的cpu利用率,只要把PdhAddCounter的第二個字符串參數改成"\\Processor(_Total)\\%% Processor Time"

      先後兩次調用PdhCollectQueryData之間也須要間隔必定時間

使用方法以下:

1 int main()
2 {
3     init(0);
4     while(1)
5     {
6         Sleep(800);
7         printf("\n%f\n", getCpuUsageRate());
8     }
9 }

利用上述方法獲取cpu當前利用率後,再畫正弦曲線,只須要改變進程的busy時間和idle時間,若是當前點曲線須要的cpu利用率是a%,cpu實際利用率是b%

若a>b, 那麼進程的busy時間爲該點時間片的(a-b)%

若a<=b,那麼進程busy時間爲0(實際狀況中因爲cpu使用率採集的不精確以及使用率的不斷變化,busy時間設置爲0效果不必定最好,本文中是設置爲原來時間的3/4)

實際上除了當前進程外,若是cpu一直佔用某個使用率,會影響曲線的形狀,特別是曲線的下部分.

代碼以下:

  1 #include <TCHAR.h>
  2 #include <windows.h>
  3 #include <pdh.h>
  4 #include <cstdio>
  5 #include <cmath>
  6 #pragma comment(lib, "pdh.lib")
  7 
  8 //---------------------------------------------------comput the cpu usage rate
  9 static PDH_HQUERY cpuQuery;
 10 static PDH_HCOUNTER cpuTotal;
 11 
 12 //cpuindex 爲指定的cpu id ,從0開始
 13 void init(int cpuIndex)
 14 {
 15     PDH_STATUS Status = PdhOpenQuery(NULL, NULL, &cpuQuery);
 16     if (Status != ERROR_SUCCESS) 
 17     {
 18         printf("\nPdhOpenQuery failed with status 0x%x.", Status);
 19         exit(-1);
 20     }
 21     char buf[50];
 22     sprintf(buf, "\\Processor(%d)\\%% Processor Time",cpuIndex);
 23     PdhAddCounter(cpuQuery, LPCSTR(buf), NULL, &cpuTotal);
 24     PdhCollectQueryData(cpuQuery);
 25 }
 26 
 27 
 28 double getCpuUsageRate()
 29 {
 30     PDH_FMT_COUNTERVALUE counterVal;
 31     PdhCollectQueryData(cpuQuery);
 32     PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
 33     return counterVal.doubleValue;
 34 }
 35 
 36 //--------------------------------------------------------------------cpu sin
 37 //把一條正弦曲線0~2pi 之間的弧度等分200份抽樣,計算每一個點的振幅
 38 //而後每隔300ms設置下一個抽樣點,並讓cpu工做對應振幅時間
 39 const int samplingCount = 200; //抽樣點數目
 40 const double pi = 3.1415926;
 41 const int totalAmplitude = 300; //每一個抽樣點對應時間片
 42 const double delta = 2.0/samplingCount;  //抽樣弧度的增量
 43 
 44 DWORD busySpan[samplingCount];//每一個抽樣點對應的busy時間
 45 int idleSpan[samplingCount];//每一個抽樣點對應的idle時間
 46 
 47 //一個線程調用MakeUsageSin,並把該線程綁定到一個cpu,那麼該cpu呈現正弦曲線
 48 DWORD WINAPI MakeUsageSin(LPVOID lpParameter)
 49 {
 50     DWORD startTime = 0;
 51     for(int j = 0; ; j = (j + 1) % samplingCount)
 52     {
 53         startTime = GetTickCount();
 54         DWORD realBusy = busySpan[j];
 55 
 56         double currentCpuUsageRate = getCpuUsageRate();
 57         if(currentCpuUsageRate < busySpan[j]*1.0/totalAmplitude)
 58             realBusy = (busySpan[j]*1.0/totalAmplitude - currentCpuUsageRate)*totalAmplitude;
 59         else
 60             realBusy *= 0.75; 
 61 
 62         while ((GetTickCount() - startTime) < realBusy);
 63         Sleep(idleSpan[j]);
 64     }
 65 }
 66 
 67 //若是cpuindex < 0 則全部cpu都顯示正弦曲線
 68 //不然只有第 cpuindex個cpu顯示正弦曲線
 69 //cpuindex 從 0 開始計數
 70 void CpuSin(int cpuIndex)
 71 {
 72     //計算 busySpan 和 idleSpan
 73     double radian = 0;
 74     int amplitude = totalAmplitude / 2;
 75     for (int i = 0; i < samplingCount; i++)
 76     {
 77         busySpan[i] = (DWORD)(amplitude + sin(pi*radian)*amplitude);
 78         idleSpan[i] = totalAmplitude - busySpan[i];
 79         radian += delta;
 80     }
 81 
 82     //獲取系統cup數量
 83     SYSTEM_INFO SysInfo;
 84     GetSystemInfo(&SysInfo);
 85     int num_processors = SysInfo.dwNumberOfProcessors;
 86     if(cpuIndex + 1 > num_processors)
 87     {
 88         printf("error: the index of cpu is out of boundary\n");
 89         printf("cpu number: %d\n", num_processors);
 90         printf("your index: %d\n", cpuIndex);
 91         printf("** tip: the index of cpu start from 0 **\n");
 92         return;
 93     }
 94 
 95     if(cpuIndex < 0)
 96     {
 97         HANDLE* threads = new HANDLE[num_processors];
 98         for (int i = 0;i < num_processors;i++)
 99         {
100             DWORD mask = 1<<i;
101             threads[i] = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
102             SetThreadAffinityMask(threads[i], 1<<i);//線程指定在某個cpu運行
103         }
104         WaitForMultipleObjects(num_processors, threads, TRUE, INFINITE);
105     }
106     else
107     {
108         init(cpuIndex);
109         HANDLE thread;
110         DWORD mask = 1;
111         thread = CreateThread(NULL, 0, MakeUsageSin, &mask, 0, NULL);
112         SetThreadAffinityMask(thread, 1<<cpuIndex);
113         WaitForSingleObject(thread,INFINITE);
114     }
115 
116 }
117 //-------------------------------------
118 
119 int main()
120 {
121     CpuSin(0);
122 }

主要改動在MakeUsageSin函數,初始化在上面代碼108行

結果以下:

 

【版權聲明】轉載請註明出處 http://www.cnblogs.com/TenosDoIt/p/3242910.html

相關文章
相關標籤/搜索