zoukankan      html  css  js  c++  java
  • Windows性能计数器相关基础(一)

    来源网站:http://www.ibm.com/developerworks/cn/websphere/techjournal/0310_braithwaite/braithwaite.html#sec4-3

    开始时,在访问所需功能的自定义应用程序的开头包含若干头文件是必要的:

    #include <windows.h>, #include <pdh.h>, #include <PDHMSG.H>, #include <WINPERF.H>

    现在,让我们看一看在使用 PDH获取性能数据时需要包括的 自定义程序的四个基本步骤中的每一个。下面将详细讨论每个部分以及将要执行每项任务的功能查询。

    1. 创建查询

    查询是计数器的集合,它是用自定义代码创建的,用于管理性能数据的集合。查询用在 PDH函数调用中更新它管理的计数器,因而获取性能数据。创建查询会返回一个句柄,可以用它来访问 PDH函数中的查询。

     
    PdhOpenQuery:
    创建一个新的查询。需要两个输入参数,返回一个参数和一个返回代码。样本用法: 
    if( (pdhStatus = PdhOpenQuery( pszDataSource, dwUserData, &hQuery)) == ERROR_SUCCESS)
    输入参数:
    pszDataSource 字符串,它引用要从中读取数据的日志文件。对于实时数据捕获,请指定 NULL 值。
    dwUserData 与此查询相关的用户定义的值。它可以是识别此查询惟一的值,而如果没有分配值,则 C++ WORD/DWORD数据类型的 0 也将是足够的。
    返回的参数:
    hQuery 指向已创建的查询的句柄。这个指针在随后的任何 PDH函数调用中都是必需的。

    如果成功地开始了此查询,那么它将返回值 ERROR_SUCCESS ;否则将返回错误的代码。

    2. 使计数器与查询相关联
     
    PdhAddCounter:
    将计数器添加到查询。需要三个输入参数,返回一个参数和一个返回代码。样本用法: 
    if( (pdhStatus = PdhAddCounter( hQuery, szFullCounterPath, dwUserData, &phCounter)) != ERROR_SUCCESS)
    输入参数:
    hQuery 指向您想将此计数器添加到的查询的句柄。
    szFullCounterPath 指向计数器的路径的指针。在传送此参数之前,必须首先用计数器的详细资料对其进行初始化,为了做到这一点,可以创建 PDH_COUNTER_PATH_ELEMENTS 数据结构,它包含机器、对象、计数器和实例的名称,如下所示: 
    PDH_COUNTER_PATH_ELEMENTS spdhCPE; 
    spdhCPE.szMachineName = "Some Value"; 
    spdhCPE.szObjectName = "Some Value"; 
    spdhCPE.szInstanceName = "Some Value"; 
    spdhCPE.szCounterName = "Some Value"; 然后,将此数据结构传送到下面的 PdhMakeCounterPath函数调用中。
    dwUserData 与此查询相关的用户定义的值。它可以是识别此查询惟一的值,而如果没有分配值,则 C++ WORD/DWORD数据类型的 0 也将是足够的。
    Returned Parameters:
    phCounter 指向已创建的查询的句柄。
     
    PdhMakeCounterPath: 
    创建指向使用 PDH_COUNTER_PATH_ELEMENTS结构的成员的计数器的全路径。需要三个输入参数,返回一个参数和一个返回代码。样本用法: 
    pdhStatus = PdhMakeCounterPath( &spdhCPE, szFullPathBuffer, &dwpcchBufferSize, dwFlags);
    输入参数:
    spdhCPE 指向 PDH_COUNTER_PATH_ELEMENTS 的指针。
    dwpcchBufferSize 如果函数调用成功,就将此参数的值设置为可用缓冲器的大小。要不然,就将它设置为所需的缓冲器的大小*。因而,此参数可以是输入参数,也可以是输出参数。 

    (*分析此参数的值并且相应地扩展缓冲器可能是必要的。)
    dwFlags 指定计数器值的格式。它可以是:
    • PDH_PATH_WBEM_RESULT:以 WMI格式返回结果。
    • PDH_PATH_WBEM_INPUT:假定输入值采用 WMI格式。
    • 0:以注册路径项的列表的形式返回结果。
    返回参数:
    szFullPathBuffer 指向将要在 PdhAddCounter函数中使用的计数器的全路径。
    dwpcchBufferSize 参见上面的 dwpcchBufferSize 输入参数。

    3. 收集和处理数据

    收集:

    既然设置了查询和添加了容器,现在就可以开始收集性能数据了。要做到这一点,可以收集原始数据并人工处理它,也可以使用内置的 PDH日志记录函数。

    用于人工处理:

     
    PdhCollectQueryData:
    检索调用时在查询中指定的所有计数器的原始数据、实时数据。需要一个输入参数,返回一个返回代码。样本用法: 
    if( (pdhStatus = PdhCollectQueryData( hQuery)) != ERROR_SUCCESS)
    输入参数:
    hQuery 指向您想要从中收集数据的查询的句柄。

    在使用函数来收集数据时,如果不首先以某种方式对收集的数据进行处理,那么它们将会是无效的。例如,如果计数器长时间地监视某些事情(例如,每秒的 I/O数据字节),那么从 PdhCollectQueryData返回的原始值将只是数据字节的运行总数。要获得实际的每秒数据字节,您将必须接受两个样本(来获取初始值和结束值),然后根据样本之间的持续时间来进行区分。(使用 PdhGetFormattedCounterValue 函数可以为您完成这一过程。)

    用于日志记录方法:

    也可以如上获得相同的数据,并将其直接写入日志文件。要做到这一点,只需打开用于写入的日志,然后在每次收集数据时更新日志就行了。完成这项任务所需的两个函数是 PdhOpenLog和 PdhUpdateLog:

     
    PdhOpenLog:
    打开用于写入的日志。需要六个输入参数,返回一个参数和一个返回代码。样本用法: 
    pdhStatus = PdhOpenLog (szLogFileName, dwAccessFalgs, lpdwLogType, hQuery, dwMaxSize, szUserText, pdhLog)
    输入参数:
    szLogFileName 字符串,它表示要创建的日志文件的名称/路径。
    dwAccessFlags 所需的对日志文件的访问级别。这些值可以是:
    • PDH_LOG_READ_ACCESS(读取)
    • PDH_LOG_WRITE_ACCESS(写入)
    • PDH_LOG_UPDATE_ACCESS(打开的用于写入的现有日志)
    需要使用 OR运算符与下面的某个值组合的读取、写入和更新标志:
    • PDH_LOG_CREATE_NEW(已创建的新日志文件)
    • PDH_LOG_CREATE_ALWAYS(清除任何具有相同名称的现有日志)
    • PDH_LOG_OPEN_EXISTING(打开一个现有的日志文件,如果它不存在的话,就创建一个新的日志文件)
    • PDH_LOG_OPEN_ALWAYS(打开一个现有的日志文件或创建一个新的日志文件)
    lpdwLogType 要打开的日志的格式。这个值可以是:
    • PDH_LOG_TYPE_UNDEFINED(未定义的)
    • PDH_LOG_TYPE_CSV(日志有列头,后面紧跟着数据值;值是用双引号和逗号隔开的)
    • PDH_LOG_TYPE_SQL(SQL 格式的数据)
    • PDH_LOG_TYPE_TSV(日志有列头,后面紧跟着数据值;值是用双引号和标记隔开的)
    • PDH_LOG_TYPE_BINARY(二进制格式)
    • PDH_LOG_TYPE_PERFMON(性能监视器用来存储数据的只读格式;在本质上与二进制是相同的,不过缺少有效的空格方式)
    hQuery 指向在其上打开日志的查询的句柄。
    dwMaxSize 最大的日志文件大小。
    szUserText 用于描述日志文件的内容的字符串。
    返回参数:
    pdhLog 指向日志文件的句柄。
     
    PdhUpdateLog:
    更新日志。需要两个输入参数,返回一个返回代码。样本用法: 
    pdhStatus = PdhUpdateLog (hLog, dwText))
    输入参数:
    hLog 指向要更新的日志文件得句柄。
    dwText 指定要添加到日志文件的任何附加文本,比如用户想要在性能数据之外添加的注释。

    一旦不再需要该日志,就应该使用 PdhCloseLog函数关闭它:

     
    PdhCloseLog: 
    关闭该日志。需要两个输入参数,返回一个返回代码。样本用法: 
    pdhStatus = PdhCloseLog (hLog, dwFlag)
    输入参数:
    hLog 指向要关闭的日志文件的句柄。
    dwFlag 可以设置为 PDH_FLAGS_CLOSE_QUERY,在这种情况下,查询与日志是同时关闭的。

    处理:

    要处理从 PdhCollectQueryData调用检索的原始数据,就有必要调用 PdhGetFormattedDataValue。在长时间监视计数器时,这尤其重要,因为 PdhCollectQueryData函数返回的是运行的整个数据,而不是每秒的数据。

     
    PdhGetFormattedCounterValue: 
    检索格式化数据(formatted data)。需要两个输入参数,返回两个参数和一个返回代码。样本用法: 
    pdhStatus = PdhGetFormattedCounterValue( hCounter, dwFormat, &dwValue, pdhValue);此函数接受对 PdhCollectQueryData的最后一次调用返回的样本来执行它的计算。如果是长时间监视计数器,该函数就接受来自对 PdhCollectQueryData的前两次调用的数据。
    输入参数:
    hCounter 指向将要格式化其值的的计数器的句柄。
    dwFormat 指定以哪一种格式返回数据:
    • PDH_FMT_DOUBLE(双精度浮点型)
    • PDH_FMT_LARGE(64位整型)
    • PDH_FMT_LONG(长整型)
    返回参数:
    &dwValue 返回计数器的类型(比如文本或数值(可选))的指针。
    pdhValue 指向包含计数器值的格式化计数器数据结构的指针。

    当使用日志记录方法时,可以以多种方式处理数据,这取决于指定的格式。例如,如果数据是采用 CSV格式写入的,那么就可以把日志文件导入电子表格。如何处理日志完全由用户决定。

    4. 关闭查询

    当查询变得多余时(因为已经收集了全部所需的数据),就可以通过调用 PdhCloseQuery函数来关闭查询。(如果是使用日志,PdhCloseLog也可以关闭查询。)

     
    PdhCloseQuery: 
    关闭查询。需要一个输入参数,返回一个返回代码。样本用法: 
    pdhStatus = PdhCloseQuery (hQuery)
    输入参数:
    hQuery 要关闭的查询得句柄。

    上面概述的函数代表了PDH库中可用的函数的样本,我们用它们说明了可以如何构造自定义应用程序。从 MicrosoftWeb站点可以获得可用函数的完整清单。

    样本应用程序

    下面是基于本文中所讨论的示例的样本代码。此代码示范了一个非常简单的监视应用程序,其中所有的值都是硬编码的,我们的目的只在于为您编写更复杂的应用程序提供一个良好的开端。下面的代码列出了将写入日志的最后输出。

    #include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    #include <pdh.h>
    #include <pdhmsg.h>
    int __cdecl _tmain (void)
    { HLOG phLog;
       PDH_STATUS          pdhStatus;
       HCOUNTER            phCounter;
       DWORD               count;
       char               szFileName[24];
       WORD               dwUserData = 0;
       HQUERY              hQuery = NULL;
       DWORD              logType = PDH_LOG_TYPE_CSV;
       CHAR                szCounterPath[45]= TEXT("\Process(calc)\% Processor Time");
       Strcpy              ( szFileName,"QuickMonitor.log");
    // Open a query.
       (pdhStatus = PdhOpenQuery( NULL, 0, &hQuery));
    // Add a counter.
       pdhStatus = PdhAddCounter( hQuery, szCounterPath,dwUserData,&phCounter);
    // Open the log file for write access.
       pdhStatus = PdhOpenLog (szFileName, PDH_LOG_WRITE_ACCESS |PDH_LOG_CREATE_ALWAYS ,
       &logType, hQuery, 0, NULL, &phLog);
    // Capture 10 samples and write them to the log.
       for (count = 0; count <= 10; count++) {
           pdhStatus = PdhUpdateLog (phLog, TEXT("SomeText."));
           Sleep(1000); // Sleep for 1 seconds betweensamples
       }
    // Close the log and the Query
       pdhStatus = PdhCloseLog (phLog, PDH_FLAGS_CLOSE_QUERY);
       return 0;
    }
    在把上面的代码构建成 exe文件并且从命令行运行它之后,就创建了称为 QuickMonitor.log 的日志文件,并且将包含类似于下面这样的数据:
    "(PDH-CSV 4.0) (GMT Daylight Time)(-60)","Process(calc)\% Processor Time"
    "09/07/2003 11:21:25.367","5.06732874742129e-008"
    "09/07/2003 11:21:26.398","0.98039215686274506"
    "09/07/2003 11:21:27.430","0"
    "09/07/2003 11:21:28.461","0.97087378640776689"
    "09/07/2003 11:21:29.503","3.8461538461538463"
    "09/07/2003 11:21:30.554","1.9047619047619049"
    "09/07/2003 11:21:31.766","0.82644628099173556"
    "09/07/2003 11:21:32.808","6.7307692307692308"
    "09/07/2003 11:21:33.859","6.666666666666667"
    "09/07/2003 11:21:34.891","5.825242718446602"
    "09/07/2003 11:21:35.922","3.8834951456310676"
    这个示例中的数据展示了机器 CPU 的 0和 6.7%之间所用的计算进程,不过非常基本并且脱离了上下文。
    上面的数据是以 CSV格式显示的,因此可导入电子表格,以更方便地进行分析。然而,所收集的数据最实用的格式将取决于实际问题情形的独特组合、选取的选项和执行分析的用户。



  • 相关阅读:
    Java对【JSON数据的解析】--Gson解析法
    Java对【JSON数据的解析】--官方解析法
    Java之JSON数据
    网络编程应用:基于UDP协议【实现聊天程序】--练习
    {网络编程}和{多线程}应用:基于UDP协议【实现多发送方发送数据到同一个接收者】--练习
    PHP获取页面执行时间的方法(推荐)
    Linux下查看CPU型号,内存大小,硬盘空间的命令(详解)
    Elasticsearch 全字段搜索_all,query_string查询,不进行分词
    mysql 查询某字段值全是数字
    linux服务器中Apache隐藏index.php失败
  • 原文地址:https://www.cnblogs.com/lovelyx/p/4867149.html
Copyright © 2011-2022 走看看