打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

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

编程之美 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 和 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

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Windows下监控打印机,获取打印任务信息
Windows API 教程(十) 注册表操作
让cpu占用率曲线听你指挥学习笔记
1.1
C语言实现时间片轮转法的cpu调度模拟
linux 下进程和线程指定CPU运行
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服