使用PDH获取GPU使用统计数据

问题描述 投票:0回答:1

我正在尝试获取一些有关 GPU 的统计数据。主要是我想获取总 VRAM 和使用量,以及 GPU 利用率(更喜欢 3d 核心,但会满足总使用量)。

闲逛了一段时间后,我发现我可以使用以下程序显示所有 PDH 计数器。

#include <windows.h>
#include <iostream>
#include <pdh.h>
#include <pdhmsg.h>
#pragma comment(lib, "pdh.lib")

void browseCounters() {
    PDH_BROWSE_DLG_CONFIG dlgConfig = {0};
    dlgConfig.bIncludeInstanceIndex = FALSE;
    dlgConfig.bSingleCounterPerAdd = TRUE;
    dlgConfig.bSingleCounterPerDialog = TRUE;
    dlgConfig.bLocalCountersOnly = FALSE;
    dlgConfig.bWildCardInstances = TRUE;
    dlgConfig.bHideDetailBox = TRUE;
    dlgConfig.bInitializePath = FALSE;
    dlgConfig.bDisableMachineSelection = FALSE;
    dlgConfig.bIncludeCostlyObjects = FALSE;
    dlgConfig.bShowObjectBrowser = FALSE;
    dlgConfig.hWndOwner = NULL;
    dlgConfig.szReturnPathBuffer = new char[PDH_MAX_COUNTER_PATH];
    dlgConfig.cchReturnPathLength = PDH_MAX_COUNTER_PATH;
    dlgConfig.pCallBack = NULL;
    dlgConfig.dwCallBackArg = 0;
    dlgConfig.CallBackStatus = ERROR_SUCCESS;
    dlgConfig.dwDefaultDetailLevel = PERF_DETAIL_WIZARD;

    // Create a non-const copy of the string literal
    char *caption = new char[17];
    strcpy(caption, "Select a counter");
    dlgConfig.szDialogBoxCaption = caption;

    PDH_STATUS status = PdhBrowseCounters(&dlgConfig);

    if (status == ERROR_SUCCESS) {
        std::wcout << L"Selected Counter: " << dlgConfig.szReturnPathBuffer << std::endl;
    } else {
        std::cout << "Error: " << status << std::endl;
    }

    delete[] dlgConfig.szReturnPathBuffer;
}

int main() {
    browseCounters();
    system("pause");
    return 0;
}

浏览完可用的柜台后,我看到一些正是我想要的。我看到有一个 GPU 引擎选项卡。选择该选项并单击“确定”后,我会得到计数器“\GPU Engine(*)\Utilization Percentage”。使用此计数器始终返回 0 利用率百分比。我尝试过使用不同的计数器并将我的 GPU 名称放入计数器路径中,但我无法使其正常工作。

这是我遇到问题的功能。 Main 调用此函数,而 while 循环会永远打印 GPU 利用率。

void printGPU() {
    PDH_HQUERY gpuQuery;
    PDH_HCOUNTER gpuCounter;

    // Open a query
    PdhOpenQueryW(NULL, 0, &gpuQuery);

    // Replace "Your_GPU_Instance_Name" with the actual name of your GPU instance
    wchar_t gpuCounterPath[MAX_PATH];
    swprintf_s(gpuCounterPath, L"\\GPU Engine(*)\\Utilization Percentage");

    PDH_STATUS pdhStatus = PdhAddCounterW(gpuQuery, gpuCounterPath, 0, &gpuCounter);
    if (pdhStatus != ERROR_SUCCESS) {
        std::cerr << "Error adding GPU counter: " << pdhStatus << std::endl;
        return;
    }

    while (true) {  // Adjust the loop condition based on your needs
        // Collect data
        PdhCollectQueryData(gpuQuery);
        // Wait for a short period (e.g., 1 second)
        Sleep(1000);
        // Collect data again
        PdhCollectQueryData(gpuQuery);

        // Read and update GPU usage
        PDH_FMT_COUNTERVALUE counterValue;
        PdhGetFormattedCounterValue(gpuCounter, PDH_FMT_DOUBLE, NULL, &counterValue);

        double gpuUsage = counterValue.doubleValue;

        std::cout << "GPU Utilization: " << gpuUsage << "%" << std::endl;
    }

    // Close the query
    PdhCloseQuery(gpuQuery);
}

我正在对 CPU 做同样的事情,并且它工作正常。我只是更新核心列表及其使用百分比。这让我怀疑路径不正确。

void GetCpuUsage() { // Function to get CPU usage percentage for each core

    PDH_HQUERY coresQuery;
    PDH_HCOUNTER counters[numCores];  // numcores is gotten earier in the code and is set to be the number of system cores
    PDH_HCOUNTER totalCounter;  // New counter for total CPU usage

    // Open a query
    PdhOpenQuery(NULL, 0, &coresQuery);


    // Add counters for each CPU core
    for (int i = 0; i < numCores; ++i) {
        wchar_t counterPath[MAX_PATH];
        swprintf_s(counterPath, L"\\Processor(%d)\\%% Processor Time", i);

        // Convert wide string to narrow string
        char narrowCounterPath[MAX_PATH];
        WideCharToMultiByte(CP_ACP, 0, counterPath, -1, narrowCounterPath, MAX_PATH, NULL, NULL);

        PdhAddCounter(coresQuery, narrowCounterPath, 0, &counters[i]);
    }


    // Add counter for total CPU usage
    wchar_t totalCounterPath[MAX_PATH];
    swprintf_s(totalCounterPath, L"\\Processor(_Total)\\%% Processor Time");

    // Convert wide string to narrow string
    char narrowTotalCounterPath[MAX_PATH];
    WideCharToMultiByte(CP_ACP, 0, totalCounterPath, -1, narrowTotalCounterPath, MAX_PATH, NULL, NULL);

    PdhAddCounter(coresQuery, narrowTotalCounterPath, 0, &totalCounter);



    while(pollCPUusage) { // loop forever while main program is open

        // Collect data
        PdhCollectQueryData(coresQuery);
        // Wait for a short period (e.g., 1 second)
        Sleep(500);
        // Collect data again
        PdhCollectQueryData(coresQuery);

        // critical section
        {
            // lock mutex
            std::lock_guard<std::mutex> lock(coresMutex);

            // Read and update CPU usage for each core
            for (int i = 0; i < numCores; ++i) {
                PDH_FMT_COUNTERVALUE counterValue;
                PdhGetFormattedCounterValue(counters[i], PDH_FMT_DOUBLE, NULL, &counterValue);

                cores[i] = counterValue.doubleValue;

                //std::cout << "CPU Core " << i << " Usage: " << counterValue.doubleValue << "%" << std::endl;
            }


            // Read and update total CPU usage
            PDH_FMT_COUNTERVALUE totalCounterValue;
            PdhGetFormattedCounterValue(totalCounter, PDH_FMT_DOUBLE, NULL, &totalCounterValue);
            totalPctUsage = totalCounterValue.doubleValue;

        } // end of critical section mutex auto unlocks at this point

    }

    // Close the query
    PdhCloseQuery(coresQuery);
}

非常感谢任何帮助。

c++ performance gpu pdh
1个回答
0
投票

您的 GPU 计数器的实例名称中包含通配符 (*)。因此,您需要使用 PdhGetFormattedCounterArray 函数而不是 PdhGetFormattedCounterValue (https://learn.microsoft.com/en-us/windows/win32/api/pdh/nf-pdh-pdhgetformattedcounterarrayw)。要计算 GPU 总利用率,请循环返回数组中的所有条目并将它们相加。

© www.soinside.com 2019 - 2024. All rights reserved.