电脑Idle状态

 

l  Idle状态判断标准

Idle状态判断周期为15分钟,有三个条件:1.在这个周期内没有输入;2.在这个周期内CPU空闲时间超过90%;3.在这个周期内磁盘的空闲时间超过90%。

l  Windows下获取CPU使用率的方法大概有三种:

1.      Windows自带的API,一般包含在头文件windows.h中;

2.      Performance Data Helper(PDH),性能数据助手;

3.      Windows ManagementInstrumentation(WMI),windows管理规格。

 

综合Idle状态不仅要判断CPU空闲时间,还要判断磁盘空闲时间,用PDH库获取更进一步的性能数据来的更简单方便。

根据MSDN中PDH使用的文档,使用pdh库获取性能数据需要执行以下几个步骤:

使用pdh库前,需要包含相应的头文件和加载相应的库:

#pragma comment (lib,”pdh.lib”)

#include <Pdh.h>

#include <PdhMsg.h>

1.      创建查询(Create a query)

2.      添加查询到计数器(Add counters to the query)

3.      收集性能数据(Collect the performance data)

4.      关闭查询(Close the query)

 

核心代码如下:

BOOL Querysystemperformance(LPCTSTRCounterPath)

{

         HQUERYquery;

         PDH_STATUSstatus = PdhOpenQuery(NULL, NULL, &query);

         if(status != ERROR_SUCCESS)

                   returnFALSE;

         HCOUNTERcounter;

         counter= (HCOUNTER *)GlobalAlloc(GPTR, sizeof(HCOUNTER));

         status= PdhAddCounter(query, CounterPath, NULL, &counter);

         if(status != ERROR_SUCCESS)

                   returnFALSE;

         PdhCollectQueryData(query);

         Sleep(1000);

         PdhCollectQueryData(query);

         PDH_FMT_COUNTERVALUEpdhValue;

         DWORDdwValue;

         status= PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, &dwValue,&pdhValue);

         if(status != ERROR_SUCCESS)

                   returnFALSE;

         cout<<pdhValue.doubleValue <<endl;

         PdhCloseQuery(query);

         returnTRUE;

}

 

在添加查询到计数器时,用到函数PdhAddCounter,函数原型如下:

PDH_STATUS PdhAddCounter(   _In_  PDH_HQUERY   hQuery,  _In_ LPCTSTR     szFullCounterPath,   _In_  DWORD_PTR    dwUserData,   _Out_ PDH_HCOUNTER*phCounter );

这里第二个参数保湿一个完整的计数器路径(szFullCounterPath,计数器路径可以有很多方法表示,本例使用字符串方法表示格式如下:

ComputerperfObject(ParentInstance/objectInstance#InstanceIndex)counter

以下是MSDN上对该表示方法的介绍:

The Computer element specifies the name or IPaddress of the computer from which you want to query performance data. Thecomputer name is optional if the counter is located on the local computer.

The PerfObject element specifies theperformance object to query. A performance object can be a physical component,such as processors, disks, and memory, or a system object, such as processesand threads. Each system object is related to a functional element within thecomputer and has a set of standard counters assigned to it. Each computer mayhave a different set of performance objects and counters installed on itbecause applications can install their own performance objects and counters.For a list of the performance objects and counters installed on your computer,see theAdd Counters dialog box in the Performance tool on yourcomputer. These objects are also listed in the PDH browse dialog box (seeBrowsing Counters). For a list of system performance objects and counters, seeCounters by Object.

The ParentInstance, ObjectInstance, andInstanceIndex are included in the path if multiple instances of the object canexist. For example, processes and threads are multiple instance objects becausemore than one process or thread can run at the same time. If an object can havemore than one instance, the counter path must specify an object instance.

 

 

 

 

在这里我要说的是可以根据系统的Performance Monitor(性能监视器)获取该参数。

1、 打开性能监视器,此时显示的是CPU占用率。

2、 下方计数器处,右击-》属性,就可以看到计数器完整路径。

3、 下图是磁盘空闲时间计数器的完整路径。

如果想要获取其他系统性能数据,在性能监视器汇总加入其他计数器,然后查看属性获取计数器完整路径即可。

如果打开性能监视器弹出如下图的警告,可参考

http://help.stnts.com/html/201503/3912.html解决。

 

 

 

 


创建查询

在使用pdh 库之前,我们需要包含相应的头文件和加载相应的库:
#include <Pdh.h>
...
#pragma comment(lib,"pdh.lib")

创建查询使用函数是PdhOpenQuery,我们看一下官方文档对于这个函数的定义

PDH_STATUS PdhOpenQuery(
  _In_  LPCTSTR    szDataSource,
  _In_  DWORD_PTR  dwUserData,
  _Out_ PDH_HQUERY *phQuery
);
  • szDataSource 
    该参数用来指定日志文件的名字以获取性能数据,一般设置成NULL,表示实时获取数据。
  • dwUserData 
    和查询相关的值,不特别指定一般也是NULL。
  • phQuery 
    用于查询的句柄,这个稍后会用到。

好了,接下来就开始查询:

HQUERY query;
PDH_STATUS status = PdhOpenQuery(NULL, NULL, &query);

需要注意的是,如果执行成功,则PdhOpenQuery返回ERROR_SUCCESS,我们可以写个判读语句判读是否执行成功。

if (status != ERROR_SUCCESS)
    cout << "Open Query Error" << endl;

 

添加查询到计数器

查看文档,对应的函数为 PdhAddCounter,先看一下函数原型。

PDH_STATUS PdhAddCounter(
  _In_  PDH_HQUERY   hQuery,
  _In_  LPCTSTR      szFullCounterPath,
  _In_  DWORD_PTR    dwUserData,
  _Out_ PDH_HCOUNTER *phCounter
);

使用该函数我们可以添加query到计数器中,注意第二个参数,这表示还需要一个完整的计数器路径(szFullCounterPath),这个计数器路径怎么写,文档中也给出了几种方法,我们这里介绍字符串方法。

这种方法直接指定计数器路径为一个字符串,如果总是监视同一个计数器,并且你对计数器路径的的格式和语法比较熟悉,那用这个方法比较合适。

计数器路径的格式如下:

\\Computer\PerfObject(ParentInstance/ObjectInstance#InstanceIndex)\Counter

看了一头雾水是不是?参照官方文档我们一点一点解释。

  • Computer 
    这个指目标机器的名字或者ip地址,如果是获取本机数据,则可以省略。

  • PerfObject 
    这个指的是要查询的性能对象,这个性能对象可以是硬件(比如处理器,磁盘,内存),也可以是系统对象(比如进程,线程)

  • ParentInstance/ObjectInstance#InstanceIndex 
    如果查询的对象存在多实例,路径中就包含这三者。 
    举个例子,进程和线程就是多实例对象,因为同一时间能运行多个进程或线程。 
    那么如果一个对象有多实例,计数器路径就必须指定到某一个对象实例。

说的再详细点,假设我们要监控Explorer,那格式就是:

(Explorer)

如果要监控该进程下的某个子线程,那格式就是:

(Explorer/0)

如果该进程下的子线程名字都一样,则通过#符号来区分开,需要注意的是,子线程的索引从0开始,但是查询第一个子线程不要写#0,直接写线程名字,从第二个子线程开始才是#1,那么第三个子线程就是#2,以此类推。

(Explorer/0#1)
  • Counter 
    最后就是这个Counter,这就是你想要查询的计数器。

最终这个格式是什么样子的呢,我们这里要查询的是CPU 的使用率,那就得知道某一刻CPU总的使用时间,格式如下:

\Processor Information(_Total)\% Processor Time

注意% 和Processor 之间有个空格,对于反斜杠’\’,我们要写两次用来转义,实际代码如下。

HCOUNTER counter;
counter = (HCOUNTER *)GlobalAlloc(GPTR, sizeof(HCOUNTER));

status = PdhAddCounter(query, LPCSTR("\\Processor Information(_Total)\\% Processor Time"), NULL, &counter);
if (status != ERROR_SUCCESS)
{
        //...
}

那对于cpu使用率是这种格式,那其他性能计数器是什么格式呢?凭空捏造可造不出来!

其实,对于windows系统,我们打开性能监视器就可以看到,运行窗口输入”perfmon.msc”,如图:

运行窗口

点击确定就可以看到本机系统的性能监视器:

性能监视器

在性能监视器页面,当前显示的是”% Processor Time”,也就是cpu的使用时间,那假如要看内存应该怎么操作?

首先,图表页面右击,选择添加计数器

添加计数器

然后显示如图页面,从下面的列表中找到Memory,然后选择Available MBytes,这表示可用内存(单位:MB),然后点击添加,这样我们就添加了可用内存的计数器。

可用内存

然后,刚才的监视器页面就多了一条计数器,看到没?

计数器

但这还只是图形化的计数器,我们要的是具体的计数器路径呀? 
别急,在对应的”Available MBytes”上右击—>属性,就能看到对应的计数器路径了,怎么样,是不是很方便?

计数器路径

知道对应的计数器路径,我们在代码中就可以使用了。

收集性能数据

将query 添加到计数器之后,我们就要开始收集性能数据了,相应函数:

PDH_STATUS PdhCollectQueryData(
  _Inout_ PDH_HQUERY hQuery
);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

需要注意的是,大部分像使用率这样的计数器,需要收集两份样本,中间用Sleep()函数间隔1s 或者更久。

PdhCollectQueryData(query);

Sleep(1000);

PdhCollectQueryData(query);

显示性能数据

收集完数据之后,就要将数据显示出来了,函数如下:

PDH_STATUS PdhGetFormattedCounterValue(
  _In_  PDH_HCOUNTER          hCounter,
  _In_  DWORD                 dwFormat,
  _Out_ LPDWORD               lpdwType,
  _Out_ PPDH_FMT_COUNTERVALUE pValue
);

各个参数可以查阅官方文档,我们这里获取CPU的使用率。PDH_FMT_COUNTERVALUE pdhValue;

DWORD dwValue;

status = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &dwValue, &pdhValue);
if (status != ERROR_SUCCESS)
{
    //...
}

对于第二个参数,一般情况下我们使用PDH_FMT_DOUBLE,但是对于计数对象是处理器,我们还需要考虑要不要PDH_FMT_NOCAP100。

如果设置本标记,则计数器的百分比数值的上限可以大于100,例如:多个处理器的使用率。

如果不设置本标记,则计数器的百分比数值的上限为100。
  •  

现在,我们可以获取cpu 的使用率了。

cout << pdhValue.doubleValue << endl;

关闭查询

既然打开了查询,那最后就要关闭查询。

PdhCloseQuery(query);

最后照例,放上程序源码(windows8.1 + visual studio2013)。

#pragma comment(lib,"pdh.lib")

#include <iostream>
#include <Pdh.h>
#include <PdhMsg.h>

using namespace std;

int main(int argc, char **argv)
{
    HQUERY query;
    PDH_STATUS status = PdhOpenQuery(NULL, NULL, &query);

    if (status != ERROR_SUCCESS)
        cout << "Open Query Error" << endl;

    HCOUNTER counter;

    counter = (HCOUNTER *)GlobalAlloc(GPTR, sizeof(HCOUNTER));

    status = PdhAddCounter(query, LPCSTR("\\Processor Information(_Total)\\% Processor Time"), NULL, &counter);

    if (status != ERROR_SUCCESS)
        cout << "Add Counter Error" << endl;

    PdhCollectQueryData(query);

    Sleep(1000);

    PdhCollectQueryData(query);

    PDH_FMT_COUNTERVALUE pdhValue;
    DWORD dwValue;

    status = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, &dwValue, &pdhValue);
    if (status != ERROR_SUCCESS)
        cout << "Get Value Error" << endl;

    cout << pdhValue.doubleValue << endl;

    PdhCloseQuery(query);

    return 0;

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值