【目录】
下面的程序针对多核处理器,可以设置让任何一个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 和 idleSpan33 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 else67 {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 }
运行结果:
下面我们考虑其他进程对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 else11 {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 else107 {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
联系客服