Windows下使用PDH获取性能计数器(CPU、内存、网络流量等)

性能计数器

获取计数

网卡接口

 

Perfmon(运行命令perfmon.msc或perfmon即可打开)性能监视器主要用来对指定的系统性能指标进行实时监控。Windows提供Pdh(performance data helper)库,方便通过程序获取里面的性能计数信息。

性能计数器

Windows通过计数器(Counter)提供操作系统、程序、服务以及驱动等的信息,以便对系统进行监视或查找性能瓶颈。

Windows提供了多种方式获取性能计数,下图展示了消费者(获取计数器的程序)、注册表、PDH等之间的互相关联关系:

Pdh接口说明

要使用性能计数器,需要引用对应的库:

#include <Pdh.h>
#include <PdhMsg.h>
#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 <IPHlpApi.h>
#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;
}

 

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt通过PDH获取网络流量需要使用Windows性能数据帮助程序(PDH)接口。以下是获取网络流量的示例代码: ```cpp #include <windows.h> #include <pdh.h> #include <pdhmsg.h> #include <QDebug> #define MAX_COUNTER_PATH 256 void getNetworkStat(double* inBytes, double* outBytes) { PdhQueryOptions(NULL, PDH_GLOBAL_MACHINE, NULL); HCOUNTER inCounter; HCOUNTER outCounter; wchar_t inCounterPath[MAX_COUNTER_PATH]; wchar_t outCounterPath[MAX_COUNTER_PATH]; // 获取网络接口的计数器路径 PdhLookupPerfNameByIndex(NULL, 2, (LPWSTR)inCounterPath, NULL); PdhLookupPerfNameByIndex(NULL, 10, (LPWSTR)outCounterPath, NULL); // 打开网络接口的计数器 PdhOpenQuery(NULL, 0, NULL); PdhAddCounter(NULL, inCounterPath, 0, &inCounter); PdhAddCounter(NULL, outCounterPath, 0, &outCounter); PdhCollectQueryData(NULL); // 获取网络流量PDH_FMT_COUNTERVALUE inValue; PDH_FMT_COUNTERVALUE outValue; PdhCollectQueryData(NULL); PdhGetFormattedCounterValue(inCounter, PDH_FMT_DOUBLE, NULL, &inValue); PdhGetFormattedCounterValue(outCounter, PDH_FMT_DOUBLE, NULL, &outValue); *inBytes = inValue.doubleValue; *outBytes = outValue.doubleValue; // 关闭计数器和查询 PdhCloseQuery(NULL); PdhCloseCounter(inCounter); PdhCloseCounter(outCounter); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); double inBytes; double outBytes; getNetworkStat(&inBytes, &outBytes); qDebug() << "In Bytes: " << inBytes << " Out Bytes: " << outBytes; return a.exec(); } ``` 在这个示例代码中,我们使用 `PdhLookupPerfNameByIndex` 函数获取网络接口计数器的路径,并使用 `PdhOpenQuery` 函数打开查询,然后使用 `PdhAddCounter` 函数打开计数器。最后使用 `PdhGetFormattedCounterValue` 获取计数器的值。注意,需要在程序结束时使用 `PdhCloseCounter` 和 `PdhCloseQuery` 函数关闭计数器和查询。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值