如何获得每个进程的GPU使用率?

时间:2012-10-22 18:09:34

标签: c windows gpu temperature

我有一个温度监控程序,我写了一段时间后,监控我的AMD显卡上的温度和风扇,检查风扇故障或过热。 它的问题在于,它需要事先知道哪个进程将使用GPU(图形处理单元),以便杀死它或优雅地使其停止以避免过热。

为了让我的程序更具动态性,我需要一种方法来查找哪个进程正在使用GPU,就像哪个进程正在使用CPU时间(任务管理器)。其中一个应用程序是SysInternals的Process Explorer。

我在问,我怎样才能在Windows中用C做这个?我知道,如果有这样的方式,它将针对Vista及以上。

2 个答案:

答案 0 :(得分:1)

如果您有特斯拉主板或高端Quadro,并在Windows Server 2008 R2 64位,Windows 7 64位(或32/64位Linux)上运行,那么您可以使用NVML来做到这一点。

下载最新的NVML SDK (Tespla Deployment Kit)并查看这两个功能:

nvmlReturn_t nvmlDeviceGetComputeRunningProcesses (nvmlDevice_t device, 
                                                   unsigned int  infoCount,
                                                   nvmlProcessInfo_t * infos)

nvmlReturn_t nvmlDeviceGetTemperature (nvmlDevice_t device,
                                       nvmlTemperatureSensors_t sensorType,
                                       unsigned int * temp)

提防:

nvmlReturn_t nvmlDeviceGetFanSpeed (nvmlDevice_t device, unsigned int * speed)

它“检索设备风扇的预期运行速度”而不是真正的风扇速度。所以你不能用它来检查风扇故障。

我不知道nvmlDeviceGetComputeRunningProcesses可以在GeForce主板上使用,但Windows NvAPI(也适用于GeForce)可以同时查询风扇速度和温度。

答案 1 :(得分:0)

您需要调用一些未记录的direct3d API函数D3DKMTQueryStatistics。

取自ProcessHacker forum的示例代码:

#define _Field_size_(...)
#define _Field_size_bytes_(...)
#define _In_reads_bytes_opt_(...)
#define _Out_writes_bytes_all_opt_(...)
#define _Field_size_bytes_part_(...)
#define _In_range_(...)
#define _Out_writes_bytes_(...)
#define _Check_return_
#define _Inout_
#define _In_
#define _Out_

#define NTDDI_VERSION NTDDI_WIN7
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include "d3dkmthk.h"

#pragma comment(lib, "gdi32.lib")  // Doesn't do much, since it doesn't have the exports anyway...
#pragma comment(lib, "advapi32.lib")

typedef NTSTATUS (APIENTRY *PD3DKMTQueryStatistics)(_In_ CONST D3DKMT_QUERYSTATISTICS*);
typedef NTSTATUS (APIENTRY *PD3DKMTOpenAdapterFromDeviceName)(_Inout_ D3DKMT_OPENADAPTERFROMDEVICENAME*);

int _tmain(int argc, TCHAR *argv[])
{
    LUID luid = { 20 };
    TOKEN_PRIVILEGES privs = { 1, { luid, SE_PRIVILEGE_ENABLED } };
    HANDLE hToken;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
    {
        if (AdjustTokenPrivileges(hToken, FALSE, &privs, sizeof(privs), NULL, NULL))
        {
        }
        else { return -1; }
    }
    else { return -2; }
    D3DKMT_OPENADAPTERFROMDEVICENAME name = { _T("\\\\?\\pci#ven_10de&dev_0a2b&subsys_9072104d&rev_a2#4&12796cb&0&0008#{1ca05180-a699-450a-9a0c-de4fbe3ddd89}") };
    HMODULE hGdi32 = LoadLibrary(_T("gdi32.dll"));
    PD3DKMTOpenAdapterFromDeviceName D3DKMTOpenAdapterFromDeviceName = (PD3DKMTOpenAdapterFromDeviceName)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromDeviceName");
    NTSTATUS status = D3DKMTOpenAdapterFromDeviceName(&name);
    if (status == 0)
    {
        _tprintf(_T("name.AdapterLuid: %llx\n"), name.AdapterLuid);
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, GetCurrentProcessId());
        _tprintf(_T("hProcess: %#p\n"), hProcess);
        if (hProcess != NULL)
        {
            for (;;)
            {
                PD3DKMTQueryStatistics D3DKMTQueryStatistics = (PD3DKMTQueryStatistics)GetProcAddress(hGdi32, "D3DKMTQueryStatistics");
                D3DKMT_QUERYSTATISTICS stats = { D3DKMT_QUERYSTATISTICS_PROCESS, name.AdapterLuid, hProcess };
                status = D3DKMTQueryStatistics(&stats);
                if (status == 0)
                {
                    _tprintf(_T("Usage: %#llx\n"), stats.QueryResult.ProcessInformation.SystemMemory.BytesAllocated);
                }
                else { break; }
                fflush(stdout);
                Sleep(1000);
            }
        }
    }
    _tprintf(_T("%#x\n"), status);
    return status;
}

可以从gpumon.c代码here中抽取对D3DKMTQueryStatistics的更多调用。