@@ -7,6 +7,7 @@ Nvidia::Nvidia(
77 GPU(drm_node, pci_dev, vendor_id, device_id, " gpu-nvidia"
88) {
99 nvml_available = init_nvml (pci_dev);
10+ nvapi_available = init_nvapi (pci_dev);
1011}
1112
1213bool Nvidia::init_nvml (const std::string& pci_dev) {
@@ -35,6 +36,67 @@ bool Nvidia::init_nvml(const std::string& pci_dev) {
3536 return true ;
3637}
3738
39+ bool Nvidia::init_nvapi (const std::string& pci_dev) {
40+ nvapi = get_libnvapi_loader ();
41+
42+ unsigned int pciBusId = 0 ;
43+
44+ {
45+ unsigned int domain, bus, slot, func;
46+
47+ if (sscanf (pci_dev.c_str (), " %x:%02x:%02x.%x" , &domain, &bus, &slot, &func) != 4 ) {
48+ SPDLOG_ERROR (" nvapi: Failed to parse PCI device ID: '{}'" , pci_dev);
49+ return false ;
50+ }
51+
52+ pciBusId = bus;
53+ }
54+
55+ if (!nvapi)
56+ return false ;
57+
58+ if (!nvapi->is_loaded ())
59+ return false ;
60+
61+ int result = nvapi->nvapi_Initialize ();
62+
63+ if (result != 0 ) {
64+ char msg[64 ] = {};
65+ nvapi->nvapi_GetErrorMessage (result, &msg);
66+ SPDLOG_ERROR (" nvapi_Initialize() failed: {}" , msg);
67+ return false ;
68+ }
69+
70+ long nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS] = {};
71+ unsigned int numOfGPUs = 0 ;
72+
73+ result = nvapi->nvapi_EnumPhysicalGPUs (&nvGPUHandle, &numOfGPUs);
74+
75+ if (result != 0 ) {
76+ char msg[64 ] = {};
77+ nvapi->nvapi_GetErrorMessage (result, &msg);
78+ SPDLOG_ERROR (" nvapi_EnumPhysicalGPUs() failed: {}" , msg);
79+ return false ;
80+ }
81+
82+ for (unsigned int i = 0 ; i < numOfGPUs; i++) {
83+ unsigned int busId = 0 ;
84+ result = nvapi->nvapi_GPU_GetBusId (nvGPUHandle[i], &busId);
85+
86+ if (result == 0 && busId == pciBusId) {
87+ nvapi_device = nvGPUHandle[i];
88+ break ;
89+ }
90+ }
91+
92+ if (nvapi_device == 0 ) {
93+ SPDLOG_ERROR (" nvapi: Failed to find gpu with {}" , pci_dev);
94+ return false ;
95+ }
96+
97+ return true ;
98+ }
99+
38100const std::vector<nvmlProcessInfo_v1_t> Nvidia::get_processes () {
39101 unsigned int info_count = 0 ;
40102
@@ -121,15 +183,27 @@ int Nvidia::get_core_clock() {
121183
122184int Nvidia::get_voltage () {
123185 uint32_t voltage = 0 ;
186+ bool try_nvapi = false ;
124187
125- if (nvml->nvmlInternalGetVoltage == nullptr ) {
126- return 0 ;
188+ if (nvml->nvmlInternalGetVoltage != nullptr ) {
189+ nvmlReturn_t ret = nvml->nvmlInternalGetVoltage (device, &voltage);
190+
191+ if (ret != NVML_SUCCESS) {
192+ try_nvapi = true ;
193+ }
194+ } else {
195+ try_nvapi = true ;
127196 }
128197
129- nvmlReturn_t ret = nvml->nvmlInternalGetVoltage (device, &voltage);
198+ if (try_nvapi) {
199+ libnvapi_loader::NvApiVoltage voltage_info = {};
130200
131- if (ret != NVML_SUCCESS)
132- return 0 ;
201+ int nv_ret = nvapi->nvapi_GetVoltage (nvapi_device, &voltage_info);
202+
203+ if (nv_ret == 0 ) {
204+ voltage = voltage_info.value_microvolts ;
205+ }
206+ }
133207
134208 return voltage / 1000 .f ;
135209}
0 commit comments