You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As mentioned in #15, NvAPI should be unloaded only after Unload has been called for each previous call to Initialize, otherwise call chains like Initialize, Initialize, Unload, $SomeFunction will lead to an error. Code sample below can be used to reproduce the issue (while it works fine on Windows), caused by the block that starts at line 74:
nvapi_test.cpp
#include<windows.h>
#include<libloaderapi.h>
#include<array>
#include<iostream>
#include<memory>
#include<stdexcept>
#include<string>
#include"nvapi.h"
#include"nvapi_interface.h"usingnamespacestd::literals;staticconstexprint nvapi_interface_table_size = sizeof(nvapi_interface_table) / sizeof(*nvapi_interface_table);
intmain(void)
{
std::unique_ptr<std::remove_pointer_t<HMODULE>, decltype(&FreeLibrary)> nvapi = {LoadLibraryA("nvapi64.dll"), FreeLibrary};
if (!nvapi) throw std::runtime_error{"Failed to load NvAPI."s};
std::cout << "NvAPI loaded." << std::endl;
auto QueryInterface = reinterpret_cast<void *(*)(NvU32 id)>(GetProcAddress(nvapi.get(), "nvapi_QueryInterface"));
if (!QueryInterface) throw std::runtime_error{"Failed to find nvapi_QueryInterface."s};
auto QueryInterfaceByName = [&QueryInterface](const std::string& funcName) -> void*
{
void* result = nullptr;
for (int i = 0; i < nvapi_interface_table_size; ++i)
{
auto& entry = nvapi_interface_table[i];
if (entry.func == funcName)
{
*(void**)(&result) = QueryInterface(entry.id);
break;
}
}
if (!result) throw std::runtime_error{"Failed to find function: "s + funcName};
return result;
};
#defineQueryInterfaceTyped(x) reinterpret_cast<decltype(&x)>(QueryInterfaceByName(#x));
auto Initialize = QueryInterfaceTyped(NvAPI_Initialize);
auto Unload = QueryInterfaceTyped(NvAPI_Unload);
auto GetErrorMessage = QueryInterfaceTyped(NvAPI_GetErrorMessage);
auto EnumPhysicalGPUs = QueryInterfaceTyped(NvAPI_EnumPhysicalGPUs);
auto GPU_GetFullName = QueryInterfaceTyped(NvAPI_GPU_GetFullName);
auto GPU_GetThermalSettings = QueryInterfaceTyped(NvAPI_GPU_GetThermalSettings);
auto GPU_GetDynamicPstatesInfoEx = QueryInterfaceTyped(NvAPI_GPU_GetDynamicPstatesInfoEx);
NvAPI_ShortString errormsg = {0};
#defineNvAPI_Call(f, ...) \
if (auto res = f(__VA_ARGS__); res != NVAPI_OK) \
{ \
if (auto gem = GetErrorMessage(res, errormsg); gem != NVAPI_OK) \
("GetErrorMessage failed with status "s + std::to_string(gem)).copy(errormsg, NVAPI_SHORT_STRING_MAX - 1); \
throw std::runtime_error{#f + " failed: "s + errormsg}; \
}
NvAPI_Call(Initialize);
std::cout << "NvAPI initialized." << std::endl;
{
NvAPI_Call(Initialize);
std::cout << "NvAPI initialized (2nd time)." << std::endl;
NvAPI_Call(Unload);
std::cout << "NvAPI unloaded (1 unload left)." << std::endl;
}
std::array<NvPhysicalGpuHandle, NVAPI_MAX_PHYSICAL_GPUS> nvGPUHandles;
NvU32 gpuCount;
NvAPI_Call(EnumPhysicalGPUs, nvGPUHandles.data(), &gpuCount);
std::cout << "Found " << gpuCount << " physical GPUs." << std::endl;
for (NvU32 i = 0; i < gpuCount; ++i)
{
NvAPI_ShortString gpuFullName;
NvAPI_Call(GPU_GetFullName, nvGPUHandles[i], gpuFullName);
std::cout << "GPU " << i << ": " << gpuFullName << std::endl;
NV_GPU_THERMAL_SETTINGS_V1 thermals = {};
thermals.version = NV_GPU_THERMAL_SETTINGS_VER_1;
NvAPI_Call(GPU_GetThermalSettings, nvGPUHandles[i], NVAPI_THERMAL_TARGET_ALL, reinterpret_cast<NV_GPU_THERMAL_SETTINGS*>(&thermals));
std::cout << "Sensors: " << thermals.count << std::endl;
for (NvU32 s = 0; s < thermals.count; ++s)
{
std::cout << " Controller: " << thermals.sensor[s].controller << std::endl;
std::cout << " CurrentTemp: " << thermals.sensor[s].currentTemp << std::endl;
std::cout << " DefMaxTemp: " << thermals.sensor[s].defaultMaxTemp << std::endl;
std::cout << " DefMinTemp: " << thermals.sensor[s].defaultMinTemp << std::endl;
std::cout << " Target: " << thermals.sensor[s].target << std::endl;
}
NV_GPU_DYNAMIC_PSTATES_INFO_EX pstates = {};
pstates.version = NV_GPU_DYNAMIC_PSTATES_INFO_EX_VER;
NvAPI_Call(GPU_GetDynamicPstatesInfoEx, nvGPUHandles[i], &pstates);
std::cout << "Pstates flags: " << pstates.flags << std::endl;
for (NvU32 d = 0; d < NVAPI_MAX_GPU_UTILIZATIONS; ++d)
{
if (pstates.utilization[d].bIsPresent)
std::cout << "Domain " << d << " is present, utilization: " << pstates.utilization[d].percentage << "%" << std::endl;
else
std::cout << "Domain " << d << " not present" << std::endl;
}
}
NvAPI_Call(Unload);
std::cout << "NvAPI unloaded." << std::endl;
}
The text was updated successfully, but these errors were encountered:
Hi @Saancreed as discussed on discord, thanks a lot for identifying this issue and for providing an easy way to reproduce this. Yeah, this is a valid issue, we should pick this up, together with guarding nvapi-initialize against concurrency issues when building the registry.
As mentioned in #15, NvAPI should be unloaded only after
Unload
has been called for each previous call toInitialize
, otherwise call chains likeInitialize
,Initialize
,Unload
,$SomeFunction
will lead to an error. Code sample below can be used to reproduce the issue (while it works fine on Windows), caused by the block that starts at line 74:nvapi_test.cpp
The text was updated successfully, but these errors were encountered: