如何获取每个进程的GPU使用情况?

6
我有一个温度监控程序,之前编写的时候监控着我AMD显卡上的温度和风扇,检查风扇故障或过热。问题在于,在避免过热之前,它需要提前知道哪个进程将使用GPU(图形处理器),并将其终止或优雅地停止。 为了使我的程序更加动态,我需要一种找到正在使用GPU的进程的方法,就像哪个进程正在使用CPU时间一样(任务管理器)。SysInternals的Process Explorer是这样一种应用程序之一。 我想问,在Windows中如何用C语言实现此功能?我知道如果有这样的方法,它会针对Vista及以上版本。

OpenCL应用程序怎么样?而且你的问题与操作系统有很大关系(在Linux上,它与Windows上不同)。 - Basile Starynkevitch
是的,Windows是我要针对的操作系统。那么OpenCL应用程序呢?实际上正是因为OpenCL,我最初编写了我的应用程序,以防止我的GPU过热。 - farmdve
只是一个快速提示:看一下Process Hacker的C 源代码;它看起来像是直接使用了3D统计API调用。 - Anton Krouglov
2个回答

2
如果您拥有Tesla板或高端Quadro,并在运行Windows Server 2008 R2 64位、Windows 7 64位(或32/64位Linux)操作系统,则可以使用NVML来完成此操作。
请下载最新的NVML SDK(Tespla部署套件),并查看这两个函数:
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)允许查询风扇速度和温度。

0

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

以下是从ProcessHacker论坛中获取的示例代码:

#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代码这里采样更多的D3DKMTQueryStatistics调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接