0. 引入
Performance Monitor 中主要通过不同的计数器来监听不同模块的值。基于计数器来进行分析,可以开箱即用,使用非常低的开销获取到系统和应用的信息。
如果我们需要在自己的应用中,直接使用这些信息,Windows 也提供了一套 API,PDH(Performance Data Helper),详细信息可以看:https://learn.microsoft.com/en-us/windows/win32/perfctrs/consuming-counter-data。
接下来我们就来看看,如何通过 C++ 来获取性能计数器的值。
- 创建 Query
HQUERY hQuery;
PDH_STATUS status = PdhOpenQuery(NULL, 0, &hQuery);
- 指定计数器
HCOUNTER hCounter;
// \Processor(_Total)\Interrupts/sec
PDH_STATUS status = PdhAddCounter(hQuery, counterPath.c_str(), 0, &hCounter);
- 收集数据
PDH_STATUS status = PdhCollectQueryData(hQuery);
Sleep(1000); // 等待 1 秒
PDH_STATUS status = PdhCollectQueryData(hQuery);
这里需要先获取一次,等待 1s 后再获取一次,如果只获取一次可能会存在某些数据不存在的问题。
- 格式化数据
PDH_FMT_COUNTERVALUE counterValue;
PDH_STATUS status = PdhGetFormattedCounterValue(hCounter, PDH_FMT_DOUBLE, NULL, &counterValue);
double result = counterValue.doubleValue;
汇总 Demo 如下
将性能计数器封装成类:
PerformanceCounter.h
如下
#pragma once
#include <windows.h>
#include <pdh.h>
#include <pdhmsg.h>
#include <string>
#include <map>
#include <mutex>
#include <stdexcept>
#pragma comment(lib, "pdh.lib")
class PerformanceCounter {
public:
// 构造函数
PerformanceCounter();
// 禁止复制构造和赋值
PerformanceCounter(const PerformanceCounter&) = delete;
PerformanceCounter& operator=(const PerformanceCounter&) = delete;
// 移动构造和赋值
PerformanceCounter(PerformanceCounter&& other) noexcept;
PerformanceCounter& operator=(PerformanceCounter&& other) noexcept;
// 添加计数器
void AddCounter(const std::wstring& counterPath);
// 移除计数器
void RemoveCounter(const std::wstring& counterPath);
// 收集数据
void CollectData();
// 获取所有计数器的值
std::map<std::wstring, double> GetValues();
// 析构函数
~PerformanceCounter();
private:
HQUERY hQuery; // 查询句柄
std::map<std::wstring, HCOUNTER> counterHandles; // 计数器路径与句柄的映射
std::mutex mtx; // 用于线程安全
void Close(); // 关闭查询并释放资源
};
PerformanceCounter.cpp
如下
#include "perf_counter.h"
#include <stdexcept>
#include <iostream>
// 构造函数
PerformanceCounter::PerformanceCounter() : hQuery(nullptr) {
PDH_STATUS status = PdhOpenQuery(NULL, 0, &hQuery);
if (status != ERROR_SUCCESS) {
throw std::runtime_error("Failed to open PDH query.");
}
}
// 移动构造函数
PerformanceCounter::PerformanceCounter(PerformanceCounter&& other) noexcept
: hQuery(other.hQuery), counterHandles(std::move(other.counterHandles)) {
other.hQuery = nullptr;
}
// 移动赋值运算符
PerformanceCounter& PerformanceCounter::operator=(PerformanceCounter&& other) noexcept {
if (this != &other) {
Close();
hQuery = other.hQuery;
counterHandles = std::move(other.counterHandles);
other.hQuery = nullptr;
}
return *this;
}
// 添加计数器
void PerformanceCounter::AddCounter(const std::wstring& counterPath) {
std::lock_guard<std::mutex> lock(mtx);
if (counterHandles.find(counterPath) != counterHandles.end()) {
throw std::runtime_error("Counter already exists.");
}
HCOUNTER hCounter;
PDH_STATUS status = PdhAddCounter(hQuery, counterPath.c_str(), 0, &hCounter);
if (status != ERROR_SUCCESS) {
throw std::runtime_error("Failed to add counter.");
}
counterHandles[counterPath] = hCounter;
}
// 移除计数器
void PerformanceCounter::RemoveCounter(const std::wstring& counterPath) {
std::lock_guard<std::mutex> lock(mtx);
auto it = counterHandles.find(counterPath);
if (it == counterHandles.end()) {
throw std::runtime_error("Counter not found.");
}
PdhRemoveCounter(it->second);
counterHandles.erase(it);
}
// 收集数据
void PerformanceCounter::CollectData() {
std::lock_guard<std::mutex> lock(mtx);
PDH_STATUS status = PdhCollectQueryData(hQuery);
if (status != ERROR_SUCCESS) {
throw std::runtime_error("Failed to collect PDH data.");
}
}
// 获取所有计数器的值
std::map<std::wstring, double> PerformanceCounter::GetValues() {
std::lock_guard<std::mutex> lock(mtx);
std::map<std::wstring, double> results;
for (const auto& [path, hCounter] : counterHandles) {
PDH_FMT_COUNTERVALUE counterValue;
PDH_STATUS status = PdhGetFormattedCounterValue(hCounter, PDH_FMT_DOUBLE, NULL, &counterValue);
if (status != ERROR_SUCCESS) {
throw std::runtime_error("Failed to get value.");
}
results[path] = counterValue.doubleValue;
}
return results;
}
// 关闭查询并释放资源
void PerformanceCounter::Close() {
if (hQuery) {
PdhCloseQuery(hQuery);
hQuery = nullptr;
}
}
// 析构函数
PerformanceCounter::~PerformanceCounter() {
Close();
}
0