How do I get GPU usage per process?
Asked Answered
M

2

6

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. 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.

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). One such application is Process Explorer from SysInternals.

I am asking, how may I do this in Windows in C? I am aware that if there is such a way, it would target Vista and above.

Mignon answered 22/10, 2012 at 18:9 Comment(3)
What about OpenCL applications? And your question is heavily operating system specific (on Linux, it is different than on Windows).Pycno
Yes, Windows is the operating system I am targeting. And what about OpenCL applications? It is in fact because of OpenCL that I initially wrote my application, so my GPU/s doesn't overheat.Mignon
Just a quick hint: look at Process Hacker C source code; it looks like direct 3d statistics API calls are used there.Highjack
A
2

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.

Download latest NVML SDK (Tespla Deployment Kit) and take a look at these two functions:

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.

Advantageous answered 23/10, 2012 at 10:51 Comment(0)
H
0

You would need to call somewhat undocumented direct3d API function D3DKMTQueryStatistics.

Sample code taken from 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;
}

More calls to D3DKMTQueryStatistics can be sampled from gpumon.c code here.

Highjack answered 6/3, 2017 at 13:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.