博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows下使用PDH获取性能计数器(CPU、内存、网络流量等)
阅读量:2055 次
发布时间:2019-04-28

本文共 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/

你可能感兴趣的文章
阿里云《云原生》公开课笔记 第六章 应用编排与管理:Deployment
查看>>
阿里云《云原生》公开课笔记 第七章 应用编排与管理:Job和DaemonSet
查看>>
阿里云《云原生》公开课笔记 第八章 应用配置管理
查看>>
阿里云《云原生》公开课笔记 第九章 应用存储和持久化数据卷:核心知识
查看>>
linux系统 阿里云源
查看>>
国内外helm源记录
查看>>
牛客网题目1:最大数
查看>>
散落人间知识点记录one
查看>>
Leetcode C++ 随手刷 547.朋友圈
查看>>
手抄笔记:深入理解linux内核-1
查看>>
内存堆与栈
查看>>
Leetcode C++《每日一题》20200621 124.二叉树的最大路径和
查看>>
Leetcode C++《每日一题》20200622 面试题 16.18. 模式匹配
查看>>
Leetcode C++《每日一题》20200625 139. 单词拆分
查看>>
Leetcode C++《每日一题》20200626 338. 比特位计数
查看>>
Leetcode C++ 《拓扑排序-1》20200626 207.课程表
查看>>
Go语言学习Part1:包、变量和函数
查看>>
Go语言学习Part2:流程控制语句:for、if、else、switch 和 defer
查看>>
Go语言学习Part3:struct、slice和映射
查看>>
Go语言学习Part4-1:方法和接口
查看>>