使用Python ctypes与nvapi接口(附示例代码)

4 投票
1 回答
2017 浏览
提问于 2025-04-16 18:32

这是我之前问题的后续:关于python ctypes和nvapi的帮助

我发这个新问题是因为我在之前的问题中已经选择了一个答案,而现在问题的方向发生了变化。

我想用python来查询nvapi.dll,以获取我的显卡使用率。

这是在C#中实现的方法(下面有链接):http://code.google.com/p/open-hardware-monitor/source/browse/trunk/Hardware/Nvidia/NVAPI.cs

因为我只需要其中一小部分功能,所以我不想换成其他语言。我觉得ctypes应该能做到这一点……但我就是搞不清楚怎么做。我之前从来没有用过Python的ctypes。

为了查询显卡使用率,我首先需要调用NvAPI_Initialize函数。同时还需要使用查询接口来引用这个函数:

from ctypes import *
nvapi = WinDLL("nvapi.dll")
nvapi_QueryInterface = nvapi.nvapi_QueryInterface

使用上面的代码,我可以访问nvapi_QueryInterface,但我不知道怎么复制这一部分:

private static void GetDelegate<T>(uint id, out T newDelegate)
  where T : class
{
    IntPtr ptr = nvapi_QueryInterface(id);
    if (ptr != IntPtr.Zero)
    {
        newDelegate =
          Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
    }
    else
    {
        newDelegate = null;
    }
}

来引用初始化和使用函数:

GetDelegate(0x0150E828, out NvAPI_Initialize);
GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages);

我对这个的理解可能还是不太对,但我花了不少时间在这上面,希望有人能帮我指明正确的方向,因为我有点迷茫,不知道该怎么继续。

有人能帮我理解如何让这小部分代码直接在python中工作吗?我最终只需要能够调用NvAPI_GPU_GetUsages函数。

谢谢。

1 个回答

4

为了查询GPU的使用情况,我首先需要调用NvAPI_Initialize这个函数。

其实,这里涉及到两个初始化函数:一个来自静态库nvapi.lib,它会尝试动态加载nvapi.dll,找到一些函数,然后调用动态链接库中的第二个初始化函数。调用NvApi_Initialize时的步骤大致如下:

  1. 检查nvapi.dll是否已经加载,如果没有,就加载它。

  2. 使用GetProcAddress获取nvapi_QueryInterface这个函数的指针。然后用这个新获得的函数来查询ID为0x150E828的接口。这就是动态库中的第二个初始化函数。

  3. 调用获得的初始化函数。如果这个函数成功了(返回值为0表示成功),就通过nvapi_QueryInterface获取两个新的函数指针,使用的ID是0x33C7358C(我们称之为ENTER)和0x593E8644(EXIT)。

所以,如果你想保持纯Python,你基本上需要用ctypes来复现这些步骤,这其实很简单。完成后,nvapi.dll中有一个清理函数,你可以用ID0xD22BDD7E来查询这个函数。如果你用完这个库,记得调用这个清理函数。

现在说说真正的问题:不幸的是,在2010年12月的NVIDIA SDK中没有这个函数。不过,有一个函数,它可以让你请求一个类型为NV_GPU_DYNAMIC_PSTATES_INFO_EX的结构数组,这个结构会包含在过去一秒内某个领域(比如GPU、帧缓冲和视频引擎)的使用率百分比。

基本上,如果你想获取GPU使用信息,你需要把NV_GPU_DYNAMIC_PSTATES_INFO_EX结构传到Python中(可以参考ctypes文档中的结构和联合),创建一个至少包含3个结构的数组,然后把这个数组传给函数。你需要先从动态链接库中查询这个函数,使用的ID是0x60DED2ED

顺便提一下,这就是你在初始化时查询的两个函数的作用——它们是一种锁定机制。虽然在调用时并不是严格必要的(也就是说可以省略),但建议你还是调用它们,比如:

Enter()
NvAPI_GPU_GetDynamicPstatesInfoEx(array_of_structs)
Exit()

你应该能够通过查看NVAPI_GPU_UTILIZATION_DOMAIN_GPU这个宏(或常量)来找到GPU使用信息在数组中的位置,不幸的是,SDK的头文件中似乎没有包含这个声明。不过,你可以通过将你的代码结果与NVIDIA系统工具显示的GPU使用信息进行比较来轻松验证这一点。

希望这能帮到你。

撰写回答