6

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

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

我在问,我如何在 C 中的 Windows 中执行此操作?我知道如果有这样的方法,它将针对 Vista 及更高版本。

4

2 回答 2

2

如果您有 Tesla 板或高端 Quadro 并在 Windows Server 2008 R2 64bit、Windows 7 64bit(或 32/64bit 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)

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

我不知道可以在 GeForce 板上工作的 nvmlDeviceGetComputeRunningProcesses 替换,但是 Windows NvAPI(也可以在 GeForce 上工作)允许查询风扇速度和温度。

于 2012-10-23T10:51:44.433 回答
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;
}

更多对 D3DKMTQueryStatistics 的调用可以从 gpumon.c 代码中采样

于 2017-03-06T13:10:11.057 回答