You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PDH获取GPU使用统计信息时遇到问题求助

PDH获取GPU利用率始终为0的排查与解决

核心问题分析

你遇到的\GPU Engine(*)\Utilization Percentage计数器返回0的问题,大概率是计数器路径不准确,或是采样逻辑不符合PDH的工作机制(GPU利用率和CPU一样,需要两次采样差值计算)。结合你的CPU功能正常的情况,重点从以下几点排查:


1. 修正计数器路径

\GPU Engine(*)\Utilization Percentage的通配符*会匹配所有GPU引擎实例(包括3D、Copy、Video Decode等),如果直接获取未被使用的引擎实例,自然返回0。要获取3D核心利用率,需要指定具体的GPU索引+引擎类型:

  • 打开Windows性能监视器(perfmon),在“添加计数器”中找到GPU Engine,展开后查看对应3D引擎的完整路径,比如:
    • 对于单GPU,路径可能是\GPU Engine(0, 3D)\Utilization Percentage
    • 带型号的路径可能是\GPU Engine(NVIDIA GeForce RTX 3080, 3D)\Utilization Percentage
  • 替换你代码中的计数器路径为上述具体路径,避免使用通配符。

2. 调整采样逻辑

PDH的利用率类计数器(包括CPU、GPU)需要两次采样并计算差值才能得到有效数值,第一次采样仅初始化基线,返回0是正常的:

  • 调用PdhCollectQueryData后,等待100~500ms(根据需求调整),再调用一次PdhCollectQueryData,之后再调用PdhGetFormattedCounterValue获取利用率。

3. 显存统计的正确计数器

如果你还需要总显存和已用显存,使用以下计数器路径(同样需要指定具体GPU实例):

  • 总专用显存:\GPU Memory(你的GPU型号)\Dedicated Capacity
  • 已用专用显存:\GPU Memory(你的GPU型号)\Dedicated Usage

示例代码(C++)

以下是修正后的GPU 3D利用率获取代码,包含正确的采样逻辑和路径指定:

#include <pdh.h>
#include <pdhmsg.h>
#include <iostream>
#include <windows.h>

#pragma comment(lib, "pdh.lib")

void PrintGPUStats() {
    PDH_HQUERY hQuery = nullptr;
    PDH_HCOUNTER h3DUtilCounter = nullptr;
    PDH_HCOUNTER hUsedMemCounter = nullptr;
    PDH_FMT_COUNTERVALUE counterVal;

    // 初始化查询
    if (PdhOpenQuery(nullptr, 0, &hQuery) != ERROR_SUCCESS) {
        std::cerr << "PDH查询初始化失败" << std::endl;
        return;
    }

    // 替换为你从perfmon获取的实际计数器路径
    const wchar_t* gpu3DPath = L"\\GPU Engine(0, 3D)\\Utilization Percentage";
    const wchar_t* gpuUsedMemPath = L"\\GPU Memory(0)\\Dedicated Usage";

    // 添加3D利用率计数器
    if (PdhAddCounter(hQuery, gpu3DPath, 0, &h3DUtilCounter) != ERROR_SUCCESS) {
        std::cerr << "添加GPU 3D计数器失败" << std::endl;
        goto cleanup;
    }

    // 添加已用显存计数器
    if (PdhAddCounter(hQuery, gpuUsedMemPath, 0, &hUsedMemCounter) != ERROR_SUCCESS) {
        std::cerr << "添加显存计数器失败" << std::endl;
        goto cleanup;
    }

    // 第一次采样(基线)
    PdhCollectQueryData(hQuery);
    Sleep(200); // 等待200ms获取差值

    // 第二次采样
    if (PdhCollectQueryData(hQuery) != ERROR_SUCCESS) {
        std::cerr << "采样数据失败" << std::endl;
        goto cleanup;
    }

    // 获取3D利用率
    if (PdhGetFormattedCounterValue(h3DUtilCounter, PDH_FMT_DOUBLE, nullptr, &counterVal) == ERROR_SUCCESS) {
        std::cout << "GPU 3D核心利用率: " << counterVal.doubleValue << "%" << std::endl;
    }

    // 获取已用显存(单位为MB)
    if (PdhGetFormattedCounterValue(hUsedMemCounter, PDH_FMT_LONG, nullptr, &counterVal) == ERROR_SUCCESS) {
        std::cout << "已用专用显存: " << counterVal.longValue / 1024 << " MB" << std::endl;
    }

cleanup:
    // 清理资源
    if (h3DUtilCounter) PdhRemoveCounter(h3DUtilCounter);
    if (hUsedMemCounter) PdhRemoveCounter(hUsedMemCounter);
    if (hQuery) PdhCloseQuery(hQuery);
}

int main() {
    PrintGPUStats();
    return 0;
}

额外排查点

  • 检查PdhAddCounter和PdhGetFormattedCounterValue的返回值,确认没有错误代码(比如PDH_CSTATUS_NO_INSTANCE表示路径中的实例不存在)。
  • 确保程序拥有足够权限(无需管理员,但如果是远程调用可能需要权限配置)。
  • 如果是笔记本电脑,确认GPU未处于节能模式(部分低功耗模式下计数器可能无数据)。

内容的提问来源于stack exchange,提问作者FunkyMunky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 08:15:03