如何获取显卡的GPU占用率和显存占用情况

本文介绍了一种使用 NVIDIA 的 SDK 和 nvapi.dll 库获取显卡 GPU 占用率的方法。通过 C++ 封装类 KGpuMon 实现了获取 GPU 占用率、显存使用情况等功能。适用于游戏开发、性能调优等场景。
AI助手已提取文章相关产品:

在游戏的性能调优过程中,经常会需要获取CPU占用率、IO、显卡GPU占用率等基础性能数据,下面就简述一下获取nvdia显卡GPU占用率的方法。 nvdia 显卡在驱动安装后,可以通过nvapi.dll来获取显卡的相关信息。有关nvdia、AMD显卡sdk的相关资料在它们的网站上均有下载,但貌似非注册开发者可获取到的信息有限。

下面提供一个简单封装了的用来获取显卡信息的c++类,由于代码是根据网上可找到的有限资料写成,难免可能存在错误,如有问题欢迎指出。

// KGpuMon.h  源代码
#pragma once

#define MAX_GPU_NUM     4L      // 监控的GPU个数(NVIDIA定义的最多GPU个数是64,这里最多只监控4个)
#define MY_PROCESS_ERROR(Condition) do { if (!(Condition)) goto Exit0; } while (false)

#define MAX_DISPLAY_CARDS               4       // 最多监控4块显卡(暂时应该够了吧)
// 常量定义
#define MAX_PHYSICAL_GPUS               64
#define SHORT_STRING_MAX                64
#define MAX_THERMAL_SENSORS_PER_GPU     3
#define MAX_CLOCKS_PER_GPU              0x120
#define MAX_PSTATES_PER_GPU             8
#define MAX_USAGES_PER_GPU              33
#define MAX_COOLER_PER_GPU              20
#define MAX_MEMORY_VALUES_PER_GPU       5

// 接口ID值
#define ID_NvAPI_Initialize                     0x0150E828
#define ID_NvAPI_GPU_GetFullName                0xCEEE8E9F
#define ID_NvAPI_GPU_GetThermalSettings         0xE3640A56
#define ID_NvAPI_EnumNvidiaDisplayHandle        0x9ABDD40D
#define ID_NvAPI_GetPhysicalGPUsFromDisplay     0x34EF9506
#define ID_NvAPI_EnumPhysicalGPUs               0xE5AC921F
#define ID_NvAPI_GPU_GetTachReading             0x5F608315
#define ID_NvAPI_GPU_GetAllClocks               0x1BD69F49
#define ID_NvAPI_GPU_GetPStates                 0x60DED2ED
#define ID_NvAPI_GPU_GetUsages                  0x189A1FDF
#define ID_NvAPI_GPU_GetCoolerSettings          0xDA141340
#define ID_NvAPI_GPU_SetCoolerLevels            0x891FA0AE
#define ID_NvAPI_GPU_GetMemoryInfo              0x774AA982
#define ID_NvAPI_GetDisplayDriverVersion        0xF951A4D1
#define ID_NvAPI_GetInterfaceVersionString      0x01053FA5
#define ID_NvAPI_GPU_GetPCIIdentifiers          0x2DDFB66E

// 版本号参数定义
#define GPU_THERMAL_SETTINGS_VER                (sizeof(NvGPUThermalSettings) | 0x10000)
#define GPU_CLOCKS_VER                          (sizeof(NvClocks) | 0x20000)
#define GPU_PSTATES_VER                         (sizeof(NvPStates) | 0x10000)
#define GPU_USAGES_VER                          (sizeof(NvUsages) | 0x10000)
#define GPU_COOLER_SETTINGS_VER                 (sizeof(NvGPUCoolerSettings) | 0x20000)
#define GPU_MEMORY_INFO_VER                     (sizeof(NvMemoryInfo) | 0x20000)
#define DISPLAY_DRIVER_VERSION_VER              (sizeof(NvDisplayDriverVersion) | 0x10000)
#define GPU_COOLER_LEVELS_VER                   (sizeof(NvGPUCoolerLevels) | 0x10000)

enum NvStatus
{
    enumNvStatus_OK = 0,
    enumNvStatus_ERROR = -1,
    enumNvStatus_LIBRARY_NOT_FOUND = -2,
    enumNvStatus_NO_IMPLEMENTATION = -3,
    enumNvStatus_API_NOT_INTIALIZED = -4,
    enumNvStatus_INVALID_ARGUMENT = -5,
    enumNvStatus_NVIDIA_DEVICE_NOT_FOUND = -6,
    enumNvStatus_END_ENUMERATION = -7,
    enumNvStatus_INVALID_HANDLE = -8,
    enumNvStatus_INCOMPATIBLE_STRUCT_VERSION = -9,
    enumNvStatus_HANDLE_INVALIDATED = -10,
    enumNvStatus_OPENGL_CONTEXT_NOT_CURRENT = -11,
    enumNvStatus_NO_GL_EXPERT = -12,
    enumNvStatus_INSTRUMENTATION_DISABLED = -13,
    enumNvStatus_EXPECTED_LOGICAL_GPU_HANDLE = -100,
    enumNvStatus_EXPECTED_PHYSICAL_GPU_HANDLE = -101,
    enumNvStatus_EXPECTED_DISPLAY_HANDLE = -102,
    enumNvStatus_INVALID_COMBINATION = -103,
    enumNvStatus_NOT_SUPPORTED = -104,
    enumNvStatus_PORTID_NOT_FOUND = -105,
    enumNvStatus_EXPECTED_UNATTACHED_DISPLAY_HANDLE = -106,
    enumNvStatus_INVALID_PERF_LEVEL = -107,
    enumNvStatus_DEVICE_BUSY = -108,
    enumNvStatus_NV_PERSIST_FILE_NOT_FOUND = -109,
    enumNvStatus_PERSIST_DATA_NOT_FOUND = -110,
    enumNvStatus_EXPECTED_TV_DISPLAY = -111,
    enumNvStatus_EXPECTED_TV_DISPLAY_ON_DCONNECTOR = -112,
    enumNvStatus_NO_ACTIVE_SLI_TOPOLOGY = -113,
    enumNvStatus_SLI_RENDERING_MODE_NOTALLOWED = -114,
    enumNvStatus_EXPECTED_DIGITAL_FLAT_PANEL = -115,
    enumNvStatus_ARGUMENT_EXCEED_MAX_SIZE = -116,
    enumNvStatus_DEVICE_SWITCHING_NOT_ALLOWED = -117,
    enumNvStatus_TESTING_CLOCKS_NOT_SUPPORTED = -118,
    enumNvStatus_UNKNOWN_UNDERSCAN_CONFIG = -119,
    enumNvStatus_TIMEOUT_RECONFIGURING_GPU_TOPO = -120,
    enumNvStatus_DATA_NOT_FOUND = -121,
    enumNvStatus_EXPECTED_ANALOG_DISPLAY = -122,
    enumNvStatus_NO_VIDLINK = -123,
    enumNvStatus_REQUIRES_REBOOT = -124,
    enumNvStatus_INVALID_HYBRID_MODE = -125,
    enumNvStatus_MIXED_TARGET_TYPES = -126,
    enumNvStatus_SYSWOW64_NOT_SUPPORTED = -127,
    enumNvStatus_IMPLICIT_SET_GPU_TOPOLOGY_CHANGE_NOT_ALLOWED = -128,
    enumNvStatus_REQUEST_USER_TO_CLOSE_NON_MIGRATABLE_APPS = -129,
    enumNvStatus_OUT_OF_MEMORY = -130,
    enumNvStatus_WAS_STILL_DRAWING = -131,
    enumNvStatus_FILE_NOT_FOUND = -132,
    enumNvStatus_TOO_MANY_UNIQUE_STATE_OBJECTS = -133,
    enumNvStatus_INVALID_CALL = -134,
    enumNvStatus_D3D10_1_LIBRARY_NOT_FOUND = -135,
    enumNvStatus_FUNCTION_NOT_FOUND = -136
};

enum NvThermalController
{
    enumNvThermalController_NONE = 0,
    enumNvThermalController_GPU_INTERNAL,
    enumNvThermalController_ADM1032,
    enumNvThermalController_MAX6649,
    enumNvThermalController_MAX1617,
    enumNvThermalController_LM99,
    enumNvThermalController_LM89,
    enumNvThermalController_LM64,
    enumNvThermalController_ADT7473,
    enumNvThermalController_SBMAX6649,
    enumNvThermalController_VBIOSEVT,
    enumNvThermalController_OS,
    enumNvThermalController_UNKNOWN = -1,
};

enum NvThermalTarget
{
    enumNvThermalTarget_NONE = 0,
    enumNvThermalTarget_GPU = 1,
    enumNvThermalTarget_MEMORY = 2,
    enumNvThermalTarget_POWER_SUPPLY = 4,
    enumNvThermalTarget_BOARD = 8,
    enumNvThermalTarget_ALL = 15,
    enumNvThermalTarget_UNKNOWN = -1
};

typedef struct _NvSensor
{
    NvThermalController Controller;
    unsigned int DefaultMinTemp;
    unsigned int DefaultMaxTemp;
    unsigned int CurrentTemp;
    NvThermalTarget Target;
}NvSensor;

typedef struct _NvGPUThermalSettings
{
    unsigned int Version;
    unsigned int Count;
    NvSensor Sensor[MAX_THERMAL_SENSORS_PER_GPU];
}NvGPUThermalSettings;

typedef struct _NvClocks
{
    unsigned int Version;
    unsigned int Clock[MAX_CLOCKS_PER_GPU];
}NvClocks;

typedef struct _NvPState
{
    bool Present;
    int Percentage;
}NvPState;

typedef struct _NvPStates
{
    unsigned int Version;
    unsigned int Flags;
    NvPState PStates[MAX_PSTATES_PER_GPU];
}NvPStates;

typedef struct _NvUsages
{
    unsigned int Version;
    unsigned int Usages[MAX_USAGES_PER_GPU];
}NvUsages;

typedef struct _NvCooler
{
    int Type;
    int Controller;
    int DefaultMin;
    int DefaultMax;
    int CurrentMin;
    int CurrentMax;
    int CurrentLevel;
    int DefaultPolicy;
    int CurrentPolicy;
    int Target;
    int ControlType;
    int Active;
}NvCooler;

typedef struct _NvGPUCoolerSettings
{
    unsigned int Version;
    unsigned int Count;
    NvCooler Coolers[MAX_COOLER_PER_GPU];
}NvGPUCoolerSettings;

typedef struct _NvLevel
{
    int Level;
    int Policy;
}NvLevel;

typedef struct _NvGPUCoolerLevels
{
    unsigned int Version;
    NvLevel Levels[MAX_COOLER_PER_GPU];
}NvGPUCoolerLevels;

typedef struct _NvMemoryInfo
{
    unsigned int Version;
    unsigned int Values[MAX_MEMORY_VALUES_PER_GPU];
}NvMemoryInfo;

typedef struct _NvDisplayDriverVersion
{
    unsigned int Version;
    unsigned int DriverVersion;
    unsigned int BldChangeListNum;    
    char szBuildBranch[SHORT_STRING_MAX];
    char szAdapter[SHORT_STRING_MAX];
}NvDisplayDriverVersion;

typedef int NvPhysicalGpuHandle;
typedef int NvDisplayHandle;

// 函数定义
typedef void* (*nvapi_QueryInterfaceType)(unsigned int uiInterfaceID);
typedef NvStatus (*NvAPI_InitializeType)();
typedef NvStatus (*NvAPI_GPU_GetFullNameType)(const NvPhysicalGpuHandle gpuHandle, char *pszName);
typedef NvStatus (*NvAPI_GPU_GetThermalSettingsType)(const NvPhysicalGpuHandle gpuHandle, int sensorIndex, NvGPUThermalSettings *pnvGPUThermalSettings);
typedef NvStatus (*NvAPI_EnumNvidiaDisplayHandleType)(const int thisEnum, NvDisplayHandle *pDisplayHandle);
typedef NvStatus (*NvAPI_GetPhysicalGPUsFromDisplayType)(const NvDisplayHandle displayHandle, NvPhysicalGpuHandle *pGpuHandles, unsigned int *pGpuCount);
typedef NvStatus (*NvAPI_EnumPhysicalGPUsType)(NvPhysicalGpuHandle *pGpuHandles, int *pGpuCount);
typedef NvStatus (*NvAPI_GPU_GetTachReadingType)(const NvPhysicalGpuHandle gpuHandle, int *pnValue);
typedef NvStatus (*NvAPI_GPU_GetAllClocksType)(const NvPhysicalGpuHandle gpuHandle, NvClocks *pnvClocks);
typedef NvStatus (*NvAPI_GPU_GetPStatesType)(const NvPhysicalGpuHandle gpuHandle, NvPStates *pnvPStates);
typedef NvStatus (*NvAPI_GPU_GetUsagesType)(const NvPhysicalGpuHandle gpuHandle, NvUsages *pnvUsages);
typedef NvStatus (*NvAPI_GPU_GetCoolerSettingsType)(const NvPhysicalGpuHandle gpuHandle, int coolerIndex, NvGPUCoolerSettings *pnvGPUCoolerSettings);
typedef NvStatus (*NvAPI_GPU_SetCoolerLevelsType)(const NvPhysicalGpuHandle gpuHandle, int coolerIndex, NvGPUCoolerLevels *pnvGPUCoolerLevels);
typedef NvStatus (*NvAPI_GPU_GetMemoryInfoType)(const NvDisplayHandle displayHandle, NvMemoryInfo *pnvMemoryInfo);
typedef NvStatus (*NvAPI_GetDisplayDriverVersionType)(const NvDisplayHandle displayHandle, NvDisplayDriverVersion *pnvDisplayDriverVersion);
typedef NvStatus (*NvAPI_GetInterfaceVersionStringType)(char *pszVersion);
typedef NvStatus (*NvAPI_GPU_GetPCIIdentifiersType)(
    const NvPhysicalGpuHandle gpuHandle, 
    unsigned int *puiDeviceId, 
    unsigned int *puiSubSystemId, 
    unsigned int *puiRevisionId, 
    unsigned int *puiExtDeviceId
    );

//*****************************以下是类内部使用的结构体************************************//
/*
* @brief GPU信息
*/
typedef struct _GPU_INFO
{
    NvPhysicalGpuHandle     nvGpuHandle;        // GPU句柄
    int                     nUsage;             // GPU占用率
}GPU_INFO;

/*
* @brief 显卡信息
*/
typedef struct _DISPLAY_CARD_INFO
{
    NvDisplayHandle nvDisplayHandle;            // 显卡句柄
    int             nGpuCount;                  // Gpu个数
    DWORD           dwTotalMemory;              // 总显存大小(KB)
    DWORD           dwFreeMemory;               // 空闲显存大小(KB)

    GPU_INFO        sGpuInfo[MAX_GPU_NUM];      // GPU信息
}DISPLAY_CARD_INFO;
//*****************************************************************************************//

/*
* @brief 显卡相关信息(可用于导出的结构体)
*/
typedef struct _DISPLAY_INFO
{
    int         nGpuCount;                  // Gpu个数
    int         nGpuUsages[MAX_GPU_NUM];    // Gpu占用率
    DWORD       dwTotalMemory;              // 总显存大小(KB)
    DWORD       dwFreeMemory;               // 空闲显存大小(KB)
}DISPLAY_INFO;

class KGpuMon
{
public:
    KGpuMon(void);
    ~KGpuMon(void);

    BOOL Init();
    BOOL Unit();

    int GetDisplayCardCount();
    BOOL GetDisplayInfo(const int nCardIndex, DISPLAY_INFO *pDisplayInfo);
private:
    int     EnumDisplayCards();
    BOOL    GetGpuHandles(const NvDisplayHandle nvDisplayHandle, DISPLAY_CARD_INFO *pCardInfo);

    BOOL    GetDisplayCardGpuUsages(const NvDisplayHandle nvDisplayHandle, DISPLAY_CARD_INFO *pCardInfo);
    BOOL    GetDisplayCardMemoryInfo(const NvDisplayHandle nvDisplayHandle, DISPLAY_CARD_INFO *pCardInfo);
private:
    nvapi_QueryInterfaceType m_pfnNvapi_QueryInterface;
    NvAPI_InitializeType m_pfnNvAPI_Initialize;
    NvAPI_GPU_GetFullNameType m_pfnNvAPI_GPU_GetFullName;
    NvAPI_GPU_GetThermalSettingsType m_pfnNvAPI_GPU_GetThermalSettings;
    NvAPI_EnumNvidiaDisplayHandleType m_pfnNvAPI_EnumNvidiaDisplayHandle;
    NvAPI_GetPhysicalGPUsFromDisplayType m_pfnNvAPI_GetPhysicalGPUsFromDisplay;
    NvAPI_EnumPhysicalGPUsType m_pfnNvAPI_EnumPhysicalGPUs;
    NvAPI_GPU_GetTachReadingType m_pfnNvAPI_GPU_GetTachReading;
    NvAPI_GPU_GetAllClocksType m_pfnNvAPI_GPU_GetAllClocks;
    NvAPI_GPU_GetPStatesType m_pfnNvAPI_GPU_GetPStates;
    NvAPI_GPU_GetUsagesType m_pfnNvAPI_GPU_GetUsages;
    NvAPI_GPU_GetCoolerSettingsType m_pfnNvAPI_GPU_GetCoolerSettings;
    NvAPI_GPU_SetCoolerLevelsType m_pfnNvAPI_GPU_SetCoolerLevels;
    NvAPI_GPU_GetMemoryInfoType m_pfnNvAPI_GPU_GetMemoryInfo;
    NvAPI_GetDisplayDriverVersionType m_pfnNvAPI_GetDisplayDriverVersion;
    NvAPI_GetInterfaceVersionStringType m_pfnNvAPI_GetInterfaceVersionString;
    NvAPI_GPU_GetPCIIdentifiersType m_pfnNvAPI_GPU_GetPCIIdentifiers;

    
    int                 m_nDisplayCardCount;
    DISPLAY_CARD_INFO*  m_pDisplayCards;
    HMODULE             m_hNvApiDll;
};


//**************************************************************************************************/
// KGpuMon.cpp 源代码
#include "StdAfx.h"
#include "KGpuMon.h"

KGpuMon::KGpuMon(void)
{
    m_hNvApiDll = NULL;
    m_nDisplayCardCount = 0;
    m_pDisplayCards = NULL;
}

KGpuMon::~KGpuMon(void)
{
    Unit();
}

BOOL KGpuMon::Init()
{
    BOOL bResult = FALSE;
    BOOL bRetCode = FALSE;

    int nIndex = 0;
    int nResult = 0;

    m_hNvApiDll = LoadLibrary(_T("nvapi.dll"));
    if (m_hNvApiDll)
    {
        m_pfnNvapi_QueryInterface = (nvapi_QueryInterfaceType)GetProcAddress(m_hNvApiDll, "nvapi_QueryInterface");
        if (m_pfnNvapi_QueryInterface)
        {
            m_pfnNvAPI_Initialize = (NvAPI_InitializeType)m_pfnNvapi_QueryInterface(ID_NvAPI_Initialize);
            m_pfnNvAPI_GPU_GetFullName = (NvAPI_GPU_GetFullNameType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetFullName);
            m_pfnNvAPI_GPU_GetThermalSettings = (NvAPI_GPU_GetThermalSettingsType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetThermalSettings);
            m_pfnNvAPI_EnumNvidiaDisplayHandle = (NvAPI_EnumNvidiaDisplayHandleType)m_pfnNvapi_QueryInterface(ID_NvAPI_EnumNvidiaDisplayHandle);
            m_pfnNvAPI_GetPhysicalGPUsFromDisplay = (NvAPI_GetPhysicalGPUsFromDisplayType)m_pfnNvapi_QueryInterface(ID_NvAPI_GetPhysicalGPUsFromDisplay);
            m_pfnNvAPI_EnumPhysicalGPUs = (NvAPI_EnumPhysicalGPUsType)m_pfnNvapi_QueryInterface(ID_NvAPI_EnumPhysicalGPUs);
            m_pfnNvAPI_GPU_GetTachReading = (NvAPI_GPU_GetTachReadingType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetTachReading);
            m_pfnNvAPI_GPU_GetAllClocks = (NvAPI_GPU_GetAllClocksType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetAllClocks);
            m_pfnNvAPI_GPU_GetPStates = (NvAPI_GPU_GetPStatesType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetPStates);
            m_pfnNvAPI_GPU_GetUsages = (NvAPI_GPU_GetUsagesType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetUsages);
            m_pfnNvAPI_GPU_GetCoolerSettings = (NvAPI_GPU_GetCoolerSettingsType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetCoolerSettings);
            m_pfnNvAPI_GPU_SetCoolerLevels = (NvAPI_GPU_SetCoolerLevelsType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_SetCoolerLevels);
            m_pfnNvAPI_GPU_GetMemoryInfo = (NvAPI_GPU_GetMemoryInfoType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetMemoryInfo);
            m_pfnNvAPI_GetDisplayDriverVersion = (NvAPI_GetDisplayDriverVersionType)m_pfnNvapi_QueryInterface(ID_NvAPI_GetDisplayDriverVersion);
            m_pfnNvAPI_GetInterfaceVersionString = (NvAPI_GetInterfaceVersionStringType)m_pfnNvapi_QueryInterface(ID_NvAPI_GetInterfaceVersionString);
            m_pfnNvAPI_GPU_GetPCIIdentifiers = (NvAPI_GPU_GetPCIIdentifiersType)m_pfnNvapi_QueryInterface(ID_NvAPI_GPU_GetPCIIdentifiers);

            if (m_pfnNvAPI_Initialize)
            {
                nResult = m_pfnNvAPI_Initialize();
                if (enumNvStatus_OK == nResult)
                {
                    m_pDisplayCards = new DISPLAY_CARD_INFO[MAX_DISPLAY_CARDS];
                    ZeroMemory(m_pDisplayCards, MAX_DISPLAY_CARDS * sizeof(DISPLAY_CARD_INFO));

                    // 获取显卡个数
                    nResult = EnumDisplayCards();
                    MY_PROCESS_ERROR(nResult > 0);

                    // 获取每块显卡的GPU个数
                    for (nIndex = 0; nIndex < m_nDisplayCardCount; ++nIndex)
                    {
                        bRetCode = GetGpuHandles(m_pDisplayCards[nIndex].nvDisplayHandle, &m_pDisplayCards[nIndex]);
                        MY_PROCESS_ERROR(bRetCode);
                    }

                    bResult = TRUE;
                }
            }
        }
    }
Exit0:
    return bResult;
}

BOOL KGpuMon::Unit()
{
    m_nDisplayCardCount = 0;

    if (m_pDisplayCards)
    {
        delete []m_pDisplayCards;
        m_pDisplayCards = NULL;
    }

    if (m_hNvApiDll)
    {
        FreeLibrary(m_hNvApiDll);
        m_hNvApiDll = NULL;
    }

    return TRUE;
}

BOOL KGpuMon::GetDisplayInfo(const int nCardIndex, DISPLAY_INFO *pDisplayInfo)
{
    BOOL bResult = FALSE;

    int nIndex = 0;

    if (nCardIndex < m_nDisplayCardCount)
    {
        bResult = GetDisplayCardGpuUsages(m_pDisplayCards[nCardIndex].nvDisplayHandle, &m_pDisplayCards[nCardIndex]);
        MY_PROCESS_ERROR(bResult);

        pDisplayInfo->nGpuCount = m_pDisplayCards[nCardIndex].nGpuCount;
        for (nIndex = 0; nIndex < pDisplayInfo->nGpuCount; ++nIndex)
        {
            pDisplayInfo->nGpuUsages[nIndex] = m_pDisplayCards[nCardIndex].sGpuInfo[nIndex].nUsage;
        }

        bResult = GetDisplayCardMemoryInfo(m_pDisplayCards[nCardIndex].nvDisplayHandle, &m_pDisplayCards[nCardIndex]);
        MY_PROCESS_ERROR(bResult);

        pDisplayInfo->dwTotalMemory = m_pDisplayCards[nCardIndex].dwTotalMemory;
        pDisplayInfo->dwFreeMemory = m_pDisplayCards[nCardIndex].dwFreeMemory;
    }
Exit0:
    return bResult;
}

int KGpuMon::GetDisplayCardCount()
{
    return m_nDisplayCardCount;
}

int KGpuMon::EnumDisplayCards()
{
    NvStatus nvResult;
    NvDisplayHandle nvDisplayCardHandle;

    int nIndex = 0;

    m_nDisplayCardCount = 0;
    if (m_pfnNvAPI_EnumNvidiaDisplayHandle)
    {
        for (nIndex = 0; nIndex < MAX_DISPLAY_CARDS; ++nIndex)
        {
            nvResult = m_pfnNvAPI_EnumNvidiaDisplayHandle(nIndex, &nvDisplayCardHandle);
            if (enumNvStatus_OK == nvResult)
            {
                m_pDisplayCards[m_nDisplayCardCount].nvDisplayHandle = nvDisplayCardHandle;
                ++m_nDisplayCardCount;
            }
        }
    }

    return m_nDisplayCardCount;
}

BOOL KGpuMon::GetGpuHandles(const NvDisplayHandle nvDisplayHandle, DISPLAY_CARD_INFO *pCardInfo)
{
    BOOL bResult = FALSE;

    NvStatus nvStatus;
    NvPhysicalGpuHandle *pnvHandles = NULL;

    int nIndex = 0;
    unsigned int uiGpuCount = 0;

    if (m_pfnNvAPI_GetPhysicalGPUsFromDisplay)
    {
        pnvHandles = new NvPhysicalGpuHandle[MAX_PHYSICAL_GPUS];
        nvStatus = m_pfnNvAPI_GetPhysicalGPUsFromDisplay(nvDisplayHandle, pnvHandles, &uiGpuCount);
        if (enumNvStatus_OK == nvStatus)
        {
            pCardInfo->nGpuCount = min(uiGpuCount, MAX_GPU_NUM);
            for (nIndex = 0; nIndex < pCardInfo->nGpuCount; ++nIndex)
            {
                pCardInfo->sGpuInfo[nIndex].nvGpuHandle = pnvHandles[nIndex];
            }

            bResult = TRUE;
        }

        delete []pnvHandles;
        pnvHandles = NULL;
    }

    return bResult;
}

BOOL KGpuMon::GetDisplayCardGpuUsages(const NvDisplayHandle nvDisplayHandle, DISPLAY_CARD_INFO *pCardInfo)
{
    BOOL bResult = FALSE;

    int nIndex = 0;

    NvStatus nvStatus = enumNvStatus_ERROR;
    NvUsages *pnvUsages = NULL;

    if (m_pfnNvAPI_GPU_GetUsages)
    {
        pnvUsages = new NvUsages;
        pnvUsages->Version = GPU_USAGES_VER;
        for (nIndex = 0; nIndex < pCardInfo->nGpuCount; ++nIndex)
        {
            nvStatus = m_pfnNvAPI_GPU_GetUsages(pCardInfo->sGpuInfo[nIndex].nvGpuHandle, pnvUsages);
            if (enumNvStatus_OK == nvStatus)
            {
                pCardInfo->sGpuInfo[nIndex].nUsage = pnvUsages->Usages[2];
            }
        }

        delete pnvUsages;
        pnvUsages = NULL;

        bResult = (enumNvStatus_OK == nvStatus) ? TRUE : FALSE;
    }

    return bResult;
}

BOOL KGpuMon::GetDisplayCardMemoryInfo(const NvDisplayHandle nvDisplayHandle, DISPLAY_CARD_INFO *pCardInfo)
{
    BOOL bResult = FALSE;

    int nIndex = 0;

    NvStatus nvStatus = enumNvStatus_ERROR;
    NvUsages *pnvUsages = NULL;
    NvMemoryInfo sMemoryInfo;

    if (m_pfnNvAPI_GPU_GetMemoryInfo)
    {
        sMemoryInfo.Version = GPU_MEMORY_INFO_VER;
        nvStatus = m_pfnNvAPI_GPU_GetMemoryInfo(nvDisplayHandle, &sMemoryInfo);
        if (enumNvStatus_OK == nvStatus)
        {
            pCardInfo->dwTotalMemory = (DWORD)(sMemoryInfo.Values[0]);
            pCardInfo->dwFreeMemory = (DWORD)(sMemoryInfo.Values[4]);

            bResult = TRUE;
        }
    }

    return bResult;
}



您可能感兴趣的与本文相关内容

<think>我们被要求使用C++获取集成显卡GPU占用率。注意,集成显卡通常指的是与CPU集成在一起的图形处理单元(例如Intel HD Graphics, AMD APU等)。由于不同的硬件厂商(如Intel, AMD, NVIDIA)提供的API可能不同,因此我们需要根据不同的硬件提供不同的方法。 然而,我们注意到用户提供的引用中提到了ONNX Runtime的执行提供者(包括CPUCUDA)以及一些关于GPU的信息,但没有直接提供获取GPU占用率的方法。但是,引用[4]中提到了使用QtOpenGL进行硬件加速,以及GPU使用率的监控。这提示我们,获取GPU占用率通常需要依赖于硬件厂商提供的特定API或第三方库。 常见的获取GPU利用率的方法包括: 1. 使用厂商特定的API:例如,NVIDIA提供NVML库,AMD提供ADL SDK,Intel提供Intel GPU Tools(例如Intel Performance Counter Monitor)等。 2. 使用操作系统提供的接口:在Windows中,我们可以使用Performance Counters(性能计数器)或WMI(Windows Management Instrumentation)来获取GPU使用率。在Linux中,可以使用如`nvidia-smi`(仅NVIDIA)或`intel_gpu_top`(Intel)等工具,或者读取`/sys/class`下的文件。 3. 使用跨平台的第三方库,例如Open Hardware Monitor、libstatgrab等。 由于用户要求使用C++,并且是集成显卡,我们假设可能是Intel集成显卡(因为Intel集成显卡在PC中非常常见)。下面我们分别针对不同平台(WindowsLinux)给出可能的解决方案。 ### Windows平台 在Windows平台上,我们可以使用Windows Performance Counters(性能计数器)来获取GPU使用率。从Windows 8开始,系统内置了GPU性能计数器。我们可以通过PDH(Performance Data Helper)库来查询。 以下是一个使用PDH查询GPU利用率的示例代码(注意:需要链接pdh.lib): ```cpp #include <windows.h> #include <pdh.h> #include <pdhmsg.h> #include <iostream> #pragma comment(lib, "pdh.lib") int main() { PDH_STATUS status; PDH_HQUERY query; PDH_HCOUNTER counter; const wchar_t* counterPath = L"\\GPU Engine(*)\\Utilization Percentage"; // 创建查询 status = PdhOpenQuery(nullptr, 0, &query); if (status != ERROR_SUCCESS) { std::cerr << "PdhOpenQuery failed with status: " << status << std::endl; return 1; } // 添加计数器 status = PdhAddCounter(query, counterPath, 0, &counter); if (status != ERROR_SUCCESS) { std::cerr << "PdhAddCounter failed with status: " << status << std::endl; PdhCloseQuery(query); return 1; } // 收集数据(需要等待一段时间,例如1秒,以便有数据) Sleep(1000); // 收集查询数据 status = PdhCollectQueryData(query); if (status != ERROR_SUCCESS) { std::cerr << "PdhCollectQueryData failed with status: " << status << std::endl; PdhCloseQuery(query); return 1; } // 获取计数器值 PDH_FMT_COUNTERVALUE counterVal; status = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, nullptr, &counterVal); if (status != ERROR_SUCCESS) { std::cerr << "PdhGetFormattedCounterValue failed with status: " << status << std::endl; PdhCloseQuery(query); return 1; } // 注意:由于GPU可能有多个引擎(如3D、视频编解码等),我们可能需要枚举所有实例并求 // 上述代码仅获取了一个实例,实际需要遍历所有实例并累加 std::wcout << L"GPU Usage: " << counterVal.doubleValue << L"%" << std::endl; // 关闭查询 PdhCloseQuery(query); return 0; } ``` 注意:上面的代码是一个简化版本。实际上,GPU利用率计数器是按引擎(如3D引擎、视频引擎等)分别计数的。因此,我们需要枚举所有实例,并过滤出属于集成显卡的实例(通常以"engtype_3D"等命名),然后将它们的利用率相加(注意:每个引擎的利用率是独立的,但总利用率通常是所有引擎的最大值或者平均值?实际上,我们通常关心的是3D引擎的利用率,或者整体引擎利用率的总?这取决于具体需求。在任务管理器中,我们看到的是所有引擎利用率的综合表现)。 更完整的做法是枚举所有计数器实例,然后对每个实例进行求(或者取其中一个代表,如3D引擎)。这需要先使用`PdhEnumObjectItems`来枚举实例。 ### Linux平台 对于Linux平台,如果是Intel集成显卡,我们可以使用`intel_gpu_top`工具,但它是命令行工具。我们也可以直接读取sysfs文件系统。例如,我们可以读取: ``` /sys/class/drm/card0/device/gt/gt0/engines/* ``` 或者读取性能计数器文件。但是,这些文件的位置内容可能因内核版本驱动版本而异。 另一种方法是使用libdrm库perf工具。但这里提供一个简单的读取sysfs文件的方法: 例如,我们可以读取`/sys/class/drm/card0/device/gpu_busy_percent`(如果存在)。这个文件直接给出了GPU占用百分比。 示例代码: ```cpp #include <iostream> #include <fstream> #include <string> int main() { std::ifstream file("/sys/class/drm/card0/device/gpu_busy_percent"); if (!file) { std::cerr << "Failed to open file" << std::endl; return 1; } std::string line; if (std::getline(file, line)) { try { int usage = std::stoi(line); std::cout << "GPU Usage: " << usage << "%" << std::endl; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } } else { std::cerr << "Failed to read from file" << std::endl; return 1; } return 0; } ``` 注意:文件路径`/sys/class/drm/card0/`可能因系统而异,可能需要尝试不同的card(如card1)。另外,不是所有的Intel集成显卡都提供了这个文件。 ### 跨平台方案 为了实现跨平台,我们可以使用第三方库,例如: 1. **NVIDIA Management Library (NVML)**:仅支持NVIDIA显卡。 2. **AMD ADL SDK**:仅支持AMD显卡。 3. **Intel GPU Tools**:仅支持Intel显卡。 4. **Open Hardware Monitor**:这是一个开源项目,提供对硬件传感器的访问,包括GPU使用率。但它是一个.NET库,不直接支持C++。 5. **libstatgrab**:这个库支持获取系统统计信息,包括CPU、内存等,但目前不支持GPU。 因此,跨平台方案可能需要针对不同的显卡操作系统编写不同的代码,或者使用一个封装了不同硬件的库,如**libgpumon**(但这是一个假想的库,实际上可能不存在)。另一种方法是使用系统命令(如`nvidia-smi`,`intel_gpu_top`)并解析输出,但这在性能上可能不是最佳选择。 ### 结论 由于集成显卡的多样性,我们需要根据具体的硬件操作系统来选择合适的方法。在Windows上,使用性能计数器是较为通用的方法(适用于NVIDIA、AMDIntel)。在Linux上,对于Intel集成显卡,读取sysfs文件是一种简单的方法。 因此,我们建议: 1. 确定操作系统(Windows还是Linux)。 2. 确定显卡厂商(Intel, AMD等)。 3. 根据以上信息选择相应的API或文件读取方式。 如果用户需要跨平台的解决方案,可能需要编写条件编译代码,针对不同平台硬件厂商分别处理。 §§相关问题§§ 1. 如何使用C++在Windows上获取独立显卡(如NVIDIA)的GPU占用率? 2. 在Linux系统中,如何通过编程方式读取AMD集成显卡占用率? 3. 有没有跨平台的C++库可以获取多种硬件的GPU占用率? 4. 如何获取GPU的其他信息,比如温度、显存使用情况? </think>要使用C++获取集成显卡GPU占用率,可通过以下方法实现。集成显卡(如Intel HD Graphics/UHD Graphics)的监控主要依赖厂商特定API或系统级接口: ### 方法1:使用Intel GPU Tools(Linux平台) 适用于Linux系统,通过读取Intel提供的sysfs接口获取GPU数据: ```cpp #include <fstream> #include <iostream> #include <string> int getIntelGPUUsage() { std::ifstream file("/sys/class/drm/card0/device/gpu_busy_percent"); if (!file.is_open()) { return -1; // 文件打开失败 } std::string line; if (std::getline(file, line)) { try { return std::stoi(line); // 返回百分比数值 } catch (...) { return -2; // 转换异常 } } return -3; // 读取失败 } int main() { int usage = getIntelGPUUsage(); if (usage >= 0) { std::cout << "GPU占用率: " << usage << "%" << std::endl; } else { std::cerr << "获取失败 (错误码: " << usage << ")" << std::endl; } return 0; } ``` > **说明**: > - 路径`/sys/class/drm/card0/device/gpu_busy_percent`是Intel集成显卡的标准接口[^1] > - 需安装`intel-gpu-tools`包:`sudo apt install intel-gpu-tools` --- ### 方法2:使用Windows Performance Counters(Windows平台) 通过Windows PDH(Performance Data Helper)API获取GPU数据: ```cpp #include <windows.h> #include <pdh.h> #include <pdhmsg.h> #include <iostream> #pragma comment(lib, "pdh.lib") int main() { PDH_HQUERY query; PDH_HCOUNTER counter; PDH_FMT_COUNTERVALUE counterVal; // 创建查询 if (PdhOpenQuery(nullptr, 0, &query) != ERROR_SUCCESS) { std::cerr << "无法打开查询" << std::endl; return 1; } // 添加GPU利用率计数器(适用于集成显卡) if (PdhAddCounter(query, L"\\GPU Engine(*)\\Utilization Percentage", 0, &counter) != ERROR_SUCCESS) { std::cerr << "无法添加计数器" << std::endl; PdhCloseQuery(query); return 1; } // 收集数据(需等待至少1秒) PdhCollectQueryData(query); Sleep(1000); PdhCollectQueryData(query); // 获取格式化值 if (PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, nullptr, &counterVal) == ERROR_SUCCESS) { std::cout << "GPU占用率: " << counterVal.doubleValue << "%" << std::endl; } else { std::cerr << "读取数据失败" << std::endl; } PdhCloseQuery(query); return 0; } ``` > **关键点**: > 1. 计数器路径`\\GPU Engine(*)\\Utilization Percentage`适用于所有GPU类型[^2] > 2. 需过滤`engtype_3D`实例获取3D渲染利用率 > 3. Windows 8+系统原生支持该接口[^3] --- ### 方法3:使用Intel OneAPI(跨平台) 通过Intel SDK直接访问GPU指标: ```cpp #include <sycl/sycl.hpp> #include <iostream> int main() { try { sycl::device d(sycl::gpu_selector_v); auto usage = d.get_info<sycl::info::device::gpu_utilization>(); std::cout << "GPU占用率: " << usage << "%" << std::endl; } catch (sycl::exception const &e) { std::cerr << "错误: " << e.what() << std::endl; } return 0; } ``` > **要求**: > - 安装[Intel OneAPI基础工具包](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) > - 驱动程序需支持SYCL 2020标准[^4] --- ### 注意事项 1. **权限问题**:Linux需`sudo`或用户加入`video`组 2. **硬件支持**:较旧硬件(如HD 4000之前)可能无监控接口 3. **多显卡系统**:需确认目标设备路径(如`/sys/class/drm/card1`) 4. **Windows版本**:性能计数器需Win8+,旧系统需安装特定SDK > 建议优先使用方法1(Linux)或方法2(Windows),两者均为操作系统原生方案,无需额外依赖库。
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值