您的位置:首页 > 其它

Windows性能计数器相关基础(一)

2014-12-05 09:50 302 查看
来源网站: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格式显示的,因此可导入电子表格,以更方便地进行分析。然而,所收集的数据最实用的格式将取决于实际问题情形的独特组合、选取的选项和执行分析的用户。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: