diff --git a/src/gpu_metrics_util.h b/src/gpu_metrics_util.h index a36411d73f..e1a8ad1bcd 100644 --- a/src/gpu_metrics_util.h +++ b/src/gpu_metrics_util.h @@ -36,6 +36,7 @@ struct gpu_metrics { #define METRICS_UPDATE_PERIOD_MS 500 #define METRICS_POLLING_PERIOD_MS 25 #define METRICS_SAMPLE_COUNT (METRICS_UPDATE_PERIOD_MS/METRICS_POLLING_PERIOD_MS) +#define NVML_SLOW_POLL_PERIOD_MS METRICS_UPDATE_PERIOD_MS #define GPU_UPDATE_METRIC_AVERAGE(FIELD) do { int value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0) #define GPU_UPDATE_METRIC_AVERAGE_FLOAT(FIELD) do { float value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0) diff --git a/src/loaders/loader_nvml.cpp b/src/loaders/loader_nvml.cpp index 484e15b5fa..ebb9fe34e6 100644 --- a/src/loaders/loader_nvml.cpp +++ b/src/loaders/loader_nvml.cpp @@ -161,6 +161,12 @@ bool libnvml_loader::Load(const std::string& library_name) { return false; } +#if defined(LIBRARY_LOADER_NVML_H_DLOPEN) + nvmlDeviceGetMemoryInfo_v2 = + reinterpret_castnvmlDeviceGetMemoryInfo_v2)>( + dlsym(library_, "nvmlDeviceGetMemoryInfo_v2")); +#endif + #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetClockInfo = reinterpret_castnvmlDeviceGetClockInfo)>( @@ -265,6 +271,12 @@ bool libnvml_loader::Load(const std::string& library_name) { return false; } +#if defined(LIBRARY_LOADER_NVML_H_DLOPEN) + nvmlDeviceGetFanSpeed_v2 = + reinterpret_castnvmlDeviceGetFanSpeed_v2)>( + dlsym(library_, "nvmlDeviceGetFanSpeed_v2")); +#endif + #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetGraphicsRunningProcesses = reinterpret_castnvmlDeviceGetGraphicsRunningProcesses)>( @@ -303,5 +315,7 @@ void libnvml_loader::CleanUp(bool unload) { nvmlUnitGetFanSpeedInfo = NULL; nvmlUnitGetHandleByIndex = NULL; nvmlDeviceGetFanSpeed = NULL; + nvmlDeviceGetFanSpeed_v2 = NULL; + nvmlDeviceGetMemoryInfo_v2 = NULL; nvmlDeviceGetGraphicsRunningProcesses = NULL; } diff --git a/src/loaders/loader_nvml.h b/src/loaders/loader_nvml.h index 6cecc25be8..39a0547459 100644 --- a/src/loaders/loader_nvml.h +++ b/src/loaders/loader_nvml.h @@ -12,6 +12,17 @@ typedef nvmlProcessInfo_t nvmlProcessInfo_v1_t; #endif #define LIBRARY_LOADER_NVML_H_DLOPEN +#ifndef nvmlMemory_v2 +typedef struct nvmlMemory_v2_st { + unsigned int version; + unsigned long long total; + unsigned long long reserved; + unsigned long long free; + unsigned long long used; +} nvmlMemory_v2_t; +#define nvmlMemory_v2 (unsigned int)(sizeof(nvmlMemory_v2_t) | (2 << 24U)) +#endif + #include #include #include @@ -36,6 +47,7 @@ class libnvml_loader { decltype(&::nvmlDeviceGetHandleByIndex_v2) nvmlDeviceGetHandleByIndex_v2; decltype(&::nvmlDeviceGetHandleByPciBusId_v2) nvmlDeviceGetHandleByPciBusId_v2; decltype(&::nvmlDeviceGetMemoryInfo) nvmlDeviceGetMemoryInfo; + nvmlReturn_t (*nvmlDeviceGetMemoryInfo_v2)(nvmlDevice_t, nvmlMemory_v2_t*); decltype(&::nvmlDeviceGetClockInfo) nvmlDeviceGetClockInfo; decltype(&::nvmlErrorString) nvmlErrorString; decltype(&::nvmlDeviceGetPowerUsage) nvmlDeviceGetPowerUsage; @@ -44,6 +56,7 @@ class libnvml_loader { decltype(&::nvmlUnitGetFanSpeedInfo) nvmlUnitGetFanSpeedInfo; decltype(&::nvmlUnitGetHandleByIndex) nvmlUnitGetHandleByIndex; decltype(&::nvmlDeviceGetFanSpeed) nvmlDeviceGetFanSpeed; + nvmlReturn_t (*nvmlDeviceGetFanSpeed_v2)(nvmlDevice_t, unsigned int, unsigned int*); decltype(&::nvmlDeviceGetGraphicsRunningProcesses) nvmlDeviceGetGraphicsRunningProcesses; private: diff --git a/src/nvidia.cpp b/src/nvidia.cpp index 1c472dda20..a1a2355604 100644 --- a/src/nvidia.cpp +++ b/src/nvidia.cpp @@ -79,7 +79,12 @@ void NVIDIA::get_instant_metrics_nvml(struct gpu_metrics *metrics, struct overla nvmlReturn_t response; if (nvml && nvml_available) { - nvml_get_process_info(); + static const unsigned int slow_poll_divisor = + MAX(1u, (unsigned int)(NVML_SLOW_POLL_PERIOD_MS / METRICS_POLLING_PERIOD_MS)); + const bool slow_tick = (slow_sample_counter == 0); + const bool log_active = (logger && logger->is_active()); + + slow_sample_counter = (slow_sample_counter + 1) % slow_poll_divisor; struct nvmlUtilization_st nvml_utilization; response = nvml->nvmlDeviceGetUtilizationRates(device, &nvml_utilization); @@ -92,58 +97,98 @@ void NVIDIA::get_instant_metrics_nvml(struct gpu_metrics *metrics, struct overla metrics->load = nvml_utilization.gpu; - if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] || (logger && logger->is_active())) { - unsigned int temp; - nvml->nvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &temp); - metrics->temp = temp; - } + if (slow_tick) { + if (params->enabled[OVERLAY_PARAM_ENABLED_proc_vram] || log_active) { + nvml_get_process_info(); + cached_slow_metrics.proc_vram_used = get_proc_vram() / (1024.f * 1024.f * 1024.f); + } - if (params->enabled[OVERLAY_PARAM_ENABLED_vram] || (logger && logger->is_active())) { - struct nvmlMemory_st nvml_memory; - nvml->nvmlDeviceGetMemoryInfo(device, &nvml_memory); - metrics->memoryTotal = nvml_memory.total / (1024.f * 1024.f * 1024.f); - metrics->sys_vram_used = nvml_memory.used / (1024.f * 1024.f * 1024.f); - } + if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] || log_active) { + unsigned int temp; + nvml->nvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &temp); + cached_slow_metrics.temp = temp; + } - if (params->enabled[OVERLAY_PARAM_ENABLED_proc_vram]) - metrics->proc_vram_used = get_proc_vram() / (1024.f * 1024.f * 1024.f); + if (params->enabled[OVERLAY_PARAM_ENABLED_vram] || log_active) { + const float to_gib = 1024.f * 1024.f * 1024.f; - if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock] || (logger && logger->is_active())) { - unsigned int core_clock; - nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_GRAPHICS, &core_clock); - metrics->CoreClock = core_clock; - } + if (nvml->nvmlDeviceGetMemoryInfo_v2) { + nvmlMemory_v2_t nvml_memory_v2 {}; + nvml_memory_v2.version = nvmlMemory_v2; - if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock] || (logger && logger->is_active())) { - unsigned int memory_clock; - nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_MEM, &memory_clock); - metrics->MemClock = memory_clock; - } + if (nvml->nvmlDeviceGetMemoryInfo_v2(device, &nvml_memory_v2) == NVML_SUCCESS) { + cached_slow_metrics.memoryTotal = nvml_memory_v2.total / to_gib; + cached_slow_metrics.sys_vram_used = nvml_memory_v2.used / to_gib; + } + } else { + struct nvmlMemory_st nvml_memory; - if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_power] || (logger && logger->is_active())) { - unsigned int power, limit; - nvml->nvmlDeviceGetPowerUsage(device, &power); - nvml->nvmlDeviceGetPowerManagementLimit(device, &limit); - metrics->powerUsage = power / 1000; - metrics->powerLimit = limit / 1000; - } + if (nvml->nvmlDeviceGetMemoryInfo(device, &nvml_memory) == NVML_SUCCESS) { + cached_slow_metrics.memoryTotal = nvml_memory.total / to_gib; + cached_slow_metrics.sys_vram_used = nvml_memory.used / to_gib; + } + } + } - if (params->enabled[OVERLAY_PARAM_ENABLED_throttling_status]) { - unsigned long long nvml_throttle_reasons; - nvml->nvmlDeviceGetCurrentClocksThrottleReasons(device, &nvml_throttle_reasons); - metrics->is_temp_throttled = (nvml_throttle_reasons & 0x0000000000000060LL) != 0; - metrics->is_power_throttled = (nvml_throttle_reasons & 0x000000000000008CLL) != 0; - metrics->is_other_throttled = (nvml_throttle_reasons & 0x0000000000000112LL) != 0; - if (throttling) - throttling->indep_throttle_status = nvml_throttle_reasons; - } + if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock] || log_active) { + unsigned int core_clock; + nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_GRAPHICS, &core_clock); + cached_slow_metrics.CoreClock = core_clock; + } - if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] || (logger && logger->is_active())){ - unsigned int fan_speed; - nvml->nvmlDeviceGetFanSpeed(device, &fan_speed); - metrics->fan_speed = fan_speed; - metrics->fan_rpm = false; + if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock] || log_active) { + unsigned int memory_clock; + nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_MEM, &memory_clock); + cached_slow_metrics.MemClock = memory_clock; + } + + if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_power] || log_active) { + unsigned int power, limit; + nvml->nvmlDeviceGetPowerUsage(device, &power); + nvml->nvmlDeviceGetPowerManagementLimit(device, &limit); + cached_slow_metrics.powerUsage = power / 1000; + cached_slow_metrics.powerLimit = limit / 1000; + } + + if (params->enabled[OVERLAY_PARAM_ENABLED_throttling_status]) { + unsigned long long nvml_throttle_reasons; + nvml->nvmlDeviceGetCurrentClocksThrottleReasons(device, &nvml_throttle_reasons); + cached_slow_metrics.is_temp_throttled = (nvml_throttle_reasons & 0x0000000000000060LL) != 0; + cached_slow_metrics.is_power_throttled = (nvml_throttle_reasons & 0x000000000000008CLL) != 0; + cached_slow_metrics.is_other_throttled = (nvml_throttle_reasons & 0x0000000000000112LL) != 0; + if (throttling) + throttling->indep_throttle_status = nvml_throttle_reasons; + } + + if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] || log_active) { + unsigned int fan_speed; + nvmlReturn_t fan_response; + + if (nvml->nvmlDeviceGetFanSpeed_v2) + fan_response = nvml->nvmlDeviceGetFanSpeed_v2(device, 0, &fan_speed); + else + fan_response = nvml->nvmlDeviceGetFanSpeed(device, &fan_speed); + + if (fan_response == NVML_SUCCESS) + cached_slow_metrics.fan_speed = fan_speed; + + cached_slow_metrics.fan_rpm = false; + } } + + metrics->proc_vram_used = cached_slow_metrics.proc_vram_used; + metrics->temp = cached_slow_metrics.temp; + metrics->memoryTotal = cached_slow_metrics.memoryTotal; + metrics->sys_vram_used = cached_slow_metrics.sys_vram_used; + metrics->CoreClock = cached_slow_metrics.CoreClock; + metrics->MemClock = cached_slow_metrics.MemClock; + metrics->powerUsage = cached_slow_metrics.powerUsage; + metrics->powerLimit = cached_slow_metrics.powerLimit; + metrics->is_temp_throttled = cached_slow_metrics.is_temp_throttled; + metrics->is_power_throttled = cached_slow_metrics.is_power_throttled; + metrics->is_other_throttled = cached_slow_metrics.is_other_throttled; + metrics->fan_speed = cached_slow_metrics.fan_speed; + metrics->fan_rpm = cached_slow_metrics.fan_rpm; #ifdef HAVE_XNVCTRL if (nvctrl_available) { metrics->fan_rpm = true; diff --git a/src/nvidia.h b/src/nvidia.h index 5e3340dc05..d33d75eca9 100644 --- a/src/nvidia.h +++ b/src/nvidia.h @@ -94,6 +94,9 @@ class NVIDIA { #ifdef HAVE_NVML nvmlDevice_t device; + unsigned int slow_sample_counter = 0; + gpu_metrics cached_slow_metrics {}; + std::vector process_info = {}; void get_instant_metrics_nvml(struct gpu_metrics *metrics, struct overlay_params *params);