简体   繁体   English

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

[英]How do I get GPU usage per process?

I have a temperature monitor program I wrote a while back which monitors the temperatures and fans on my AMD Graphics cards, checking for fan failure OR overheats. 我有一个温度监控程序,我写了一会儿,监控我的AMD显卡上的温度和风扇,检查风扇故障或过热。 The problem with it, is that it needs to know in advance which process will be using the GPU(Graphics Processing Unit), in order to kill it or gracefully make it stop to avoid overheating. 它的问题在于,它需要事先知道哪个进程将使用GPU(图形处理单元),以便杀死它或优雅地使其停止以避免过热。

To make my program more dynamic, I needed a way to find which process is using the GPU, much like which process is using CPU time(Task Manager). 为了使我的程序更具动态性,我需要一种方法来查找哪个进程正在使用GPU,就像哪个进程正在使用CPU时间(任务管理器)。 One such application is Process Explorer from SysInternals. 一个这样的应用程序是来自SysInternals的Process Explorer。

I am asking, how may I do this in Windows in C? 我在问,我怎么能在Windows中用C做这个? I am aware that if there is such a way, it would target Vista and above. 我知道,如果有这样的方式,它将针对Vista及以上。

If you have a Tesla board or high-end Quadro and running on Windows Server 2008 R2 64bit , Windows 7 64bit (or 32/64bit Linux) then you can use NVML to do that. 如果你有一台Tesla主板或高端Quadro并在Windows Server 2008 R2 64位 ,Windows 7 64位 (或32/64位Linux)上运行,那么你可以使用NVML来做到这一点。

Download latest NVML SDK (Tespla Deployment Kit) and take a look at these two functions: 下载最新的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)

Watch out for: 提防:

nvmlReturn_t nvmlDeviceGetFanSpeed (nvmlDevice_t device, unsigned int * speed)

It "retrieves the intended operating speed of the device's fan" not real fan speed. 它“检索设备风扇的预期运行速度”而不是真正的风扇速度。 So you can't use it for checking fan failures. 所以你不能用它来检查风扇故障。

I'm not aware of nvmlDeviceGetComputeRunningProcesses replacement that'd work on GeForce boards, but Windows NvAPI (which also works on GeForce) allows to query both Fan Speed and Temperature. 我不知道nvmlDeviceGetComputeRunningProcesses可以在GeForce主板上使用,但Windows NvAPI (也适用于GeForce)可以同时查询风扇速度和温度。

You would need to call somewhat undocumented direct3d API function D3DKMTQueryStatistics. 您需要调用一些未记录的direct3d API函数D3DKMTQueryStatistics。

Sample code taken from ProcessHacker forum : 示例代码取自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;
}

More calls to D3DKMTQueryStatistics can be sampled from gpumon.c code here . 多次调用D3DKMTQueryStatistics可以从gpumon.c代码进行采样这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM