问题
This is a follow up to my previous question: help with python ctypes and nvapi
I am posting another question because I already selected an answer in my previous question and the question has shifted direction now.
Using python, I am trying to query nvapi.dll to get my gpu usage value.
This is how you would do it in C# (referenced below): http://code.google.com/p/open-hardware-monitor/source/browse/trunk/Hardware/Nvidia/NVAPI.cs
Because I only need a small subset of the functionality I don't really want to swap into using another language. I think that ctypes should be able to do this... I just cannot figure out how to do it. I have never really used Python ctypes before.
In order to query for the gpu usage I first need to call the NvAPI_Initialize function. One must also use the query interface to reference the function:
from ctypes import *
nvapi = WinDLL("nvapi.dll")
nvapi_QueryInterface = nvapi.nvapi_QueryInterface
Using the above code, I have access to the nvapi_QueryInterface, but I cannot figure out how to replicate this portion:
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;
}
}
to reference the init and usage functions:
GetDelegate(0x0150E828, out NvAPI_Initialize);
GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages);
My understanding of this may still be wrong, but I've spent a good deal of time trying to figure this out so I hope someone can help push me in the right direction because I am a little lost as to how to proceed.
Can someone help me understand how I can make this small portion of the code work directly in python? I just need to be able to call the NvAPI_GPU_GetUsages function at the end of the day.
Thanks.
回答1:
In order to query for the gpu usage I first need to call the NvAPI_Initialize function.
There are actually two initialization functions involved: the one from the static library nvapi.lib, which tries to dynamically load nvapi.dll, locates some functions and calls the second initialization function from the dynamic link library. The steps involved when calling NvApi_Initialize from the static library are roughly as follows:
Check if nvapi.dll is already loaded, if not, load it
Use GetProcAddress to get a pointer to
nvapi_QueryInterface
from the DLL Use the newly obtained function to query for the interface with the Id 0x150E828. This will be the second initialization function from the dynamic libraryCall the obtained initialization function. If the function was successful (indicated by a return value of 0), obtain two new function pointers via
nvapi_QueryInterface
, using the ids 0x33C7358C (let's call this ENTER) and 0x593E8644 (EXIT).
So, if you want to stay pure Python, you basically have to replicate these steps using ctypes, which would be pretty easy. After you are done, there is a cleanup function in nvapi.dll, which you can query using the id 0xD22BDD7E. If you are done using the library, remember to call this function.
Now on to the real problem: unfortunately, there is no function NvAPI_GPU_GetUsages
in the December 2010 NVIDIA SDK. There is, however, NvAPI_GPU_GetDynamicPstatesInfoEx
which will allow you to request an array of structures of type NV_GPU_DYNAMIC_PSTATES_INFO_EX
to be filled, which in turn will contain the utilization as percentage of time during the last second for a given domain (i.e. GPU, frame buffer and video engine).
Basically, if you want to retrieve GPU usage information, you transfer the NV_GPU_DYNAMIC_PSTATES_INFO_EX
struct to Python (see Structures and unions in the ctypes documentation), create an array of at least 3 structures and pass that array to the NvAPI_GPU_GetDynamicPstatesInfoEx
function, which you would have to query from the dynamic link library first, using the id 0x60DED2ED.
This is, by the way, where the two functions come into play you queries during initialization - it's a sort of locking mechanism. While not strictly necessary (i.e. you can omit this during calling), you are encouraged to call them, i.e.
Enter()
NvAPI_GPU_GetDynamicPstatesInfoEx(array_of_structs)
Exit()
You are supposed to be able to find at at which position in the array GPU usage information is stored by looking at the NVAPI_GPU_UTILIZATION_DOMAIN_GPU macro (or constant), unfortunately, there does not seem to be a declaration included in the header files for the SDK. Still, you could easily verify this by comparing the results of your code with the NVIDIA system tool that displays GPU usage information.
Hope that helps.
来源:https://stackoverflow.com/questions/6165628/use-python-ctypes-to-interface-with-nvapi-follow-up-with-demonstration-code