本文共 4774 字,大约阅读时间需要 15 分钟。
Perfmon(运行命令perfmon.msc或perfmon即可打开)性能监视器主要用来对指定的系统性能指标进行实时监控。Windows提供Pdh(performance data helper)库,方便通过程序获取里面的性能计数信息。
Windows通过计数器(Counter)提供操作系统、程序、服务以及驱动等的信息,以便对系统进行监视或查找性能瓶颈。
Windows提供了多种方式获取性能计数,下图展示了消费者(获取计数器的程序)、注册表、PDH等之间的互相关联关系:
Pdh接口说明
要使用性能计数器,需要引用对应的库:
#include#include #pragma comment(lib,"pdh.lib")
获取计数器一般需要以下步骤:
PdhOpenQuery:打开Pdh;
PdhAddCounter:添加要关注的计数器(可以添加多个);
PdhCollectQueryData:收集计数;因很多计数需要区间值,所以需要调用两次Query(间隔至少1s),然后再获取计数值。
PdhGetFormattedCounterValue:获取计数值;
计数器路径
每个计数器由其名称与路径(可在性能监视器中查看到)唯一标识:
\\Computer\PerfObject(ParentInstance/ObjectInstance#InstanceIndex)\Counter
其中:
Computer
:为要监视机器名或IP地址,对本机可忽略;
PerfObject
:为要监视的性能对象名称,可以是CPU、内存、硬盘、程序等等(如Processor Information
表示CPU,Network Interface
表示网卡);
ParentInstance,ObjectInstance,InstanceIndex
:在要监视的对象有多个实例时,用于区分;注意,因#
在此被用于表示实例索引,所以ParentInstance等中若有#
则需要替换为_
;
通过调用Pdh接口,即可获取对应计数信息。
计数器
要获取性能计数,需要得知对应的计数器路径;常见计数器路径都比较好获取,网卡需要获取当期使用网卡的接口描述。
以下示例获取CPU利用率、可用内存大小,以及网卡的收发数据量。
void getResourceCounter(){ HQUERY query; PDH_STATUS status = PdhOpenQuery(NULL, NULL, &query); if (status != ERROR_SUCCESS) cout << "Open Query Error" << endl; HCOUNTER cpuCounter, memCounter; HCOUNTER recvCounter, sentCounter; string strGet = getNetInterface(); wstring strInterface = L"\\Network Interface(" + xugd::clib::XuStr::str2wstr(strGet) + L")\\"; wcout << strInterface << endl; status = PdhAddCounter(query, TEXT("\\Processor Information(_Total)\\% Processor Time"), NULL, &cpuCounter); if (status != ERROR_SUCCESS) cout << "Add CPU Counter Error" << endl; status = PdhAddCounter(query, TEXT("\\Memory\\Available MBytes"), NULL, &memCounter); if (status != ERROR_SUCCESS) cout << "Add Memory Counter Error" << endl; status = PdhAddCounter(query, (strInterface + L"Bytes Received/sec").c_str(), NULL, &recvCounter); if (status != ERROR_SUCCESS) cout << "Add Received Counter Error" << endl; status = PdhAddCounter(query, (strInterface + L"Bytes Sent/sec").c_str(), NULL, &sentCounter); if (status != ERROR_SUCCESS) cout << "Add Sent Counter Error" << endl; int nIndex = 0; cout << setiosflags(ios::fixed) << setprecision(4); while (true) { PdhCollectQueryData(query); Sleep(1000); PdhCollectQueryData(query); PDH_FMT_COUNTERVALUE pdhValue; DWORD dwValue; status = PdhGetFormattedCounterValue(cpuCounter, PDH_FMT_DOUBLE, &dwValue, &pdhValue); if (status != ERROR_SUCCESS) cout << "Get Value Error" << endl; cout << setw(3) << ++nIndex << " - CPU: " << pdhValue.doubleValue << "%"; status = PdhGetFormattedCounterValue(memCounter, PDH_FMT_LONG, &dwValue, &pdhValue); if (status != ERROR_SUCCESS) cout << "Get Value Error" << endl; cout << "; \tMemory: " << pdhValue.longValue << "MB"; status = PdhGetFormattedCounterValue(recvCounter, PDH_FMT_LONG, &dwValue, &pdhValue); if (status != ERROR_SUCCESS) cout << "Get Value Error" << endl; cout << "; \tRecv: " << pdhValue.longValue; status = PdhGetFormattedCounterValue(sentCounter, PDH_FMT_LONG, &dwValue, &pdhValue); if (status != ERROR_SUCCESS) cout << "Get Value Error" << endl; cout << "; \tSent: " << pdhValue.longValue << endl; Sleep(1000 * 10); } PdhCloseQuery(query);}
网卡接口
一般电脑上都有多个网卡接口,如何获取当前正在使用的呢?可以通过GetBestInterface接口获取对应索引,然后通过GetAdaptersInfo获取具体信息。
笔记本上等很可能使用的是无线网卡,所以不能根据网卡类型(type)判断。#include#pragma comment(lib, "IPHlpApi.lib")string getNetInterface() { ULONG ulSize = 0; IP_ADAPTER_INFO *pAdapter = nullptr; if (GetAdaptersInfo(pAdapter, &ulSize) == ERROR_BUFFER_OVERFLOW) { pAdapter = (IP_ADAPTER_INFO*)new char[ulSize]; } else { cout << "GetAdaptersInfo fail" << endl; return ""; } if (GetAdaptersInfo(pAdapter, &ulSize) != ERROR_SUCCESS) { cout<< "GetAdaptersInfo fail" << endl; return ""; } IPAddr ipAddr = { 0 }; DWORD dwIndex = -1; DWORD nRet = GetBestInterface(ipAddr, &dwIndex); if (NO_ERROR != nRet) { cout << "GetBestInterface fail: " << nRet << endl; } string strInterface; for (auto *pCur = pAdapter; pCur != NULL; pCur = pCur->Next) { //if (pCur->Type != MIB_IF_TYPE_ETHERNET) // continue; if (pCur->Index == dwIndex) { cout << "Best Interface!! "; strInterface = pCur->Description; } cout << "Descrip: " << pCur->Description; cout << ", Name: " << pCur->AdapterName << endl; cout << "IP: " << pCur->IpAddressList.IpAddress.String; cout << ", Gateway: " << pCur->GatewayList.IpAddress.String << endl << endl; } delete pAdapter; return strInterface;}
转载地址:http://ngnlf.baihongyu.com/