编程之美 1.1 让cpu占用率曲线听你指挥(多核处理器)

【目录】

不考虑其他进程,cpu画正弦曲线

获取总体cpu利用率

获取多核处理器单个cpu利用率

考虑其他进程,cpu画正弦曲线


 

下面的程序针对多核处理器,可以设置让任何一个cpu显示相应的曲线(本文以正弦曲线为例)

代码编译环境:windows 7 64位 酷睿 i5 处理器,vs2010.

可以修改CpuSin函数的计算 busySpan 和 idleSpan的部分以显示不同的曲线。

下面的代码没有考虑cpu中其他进程的占用情况,这种情况详见第二部分

 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 }

运行结果:

编程之美 1.1 让cpu占用率曲线听你指挥(多核处理器)


下面我们考虑其他进程对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行

结果如下:

编程之美 1.1 让cpu占用率曲线听你指挥(多核处理器)

 

【版权声明】转载请注明出处 http://www.cnblogs.com/TenosDoIt/p/3242910.html

你可能感兴趣的:(编程之美)