From 1701eb91b2e11d8ccefa31fca27d490134e9df8e Mon Sep 17 00:00:00 2001 From: Tim Sirmovics Date: Thu, 28 Oct 2021 01:34:07 +1100 Subject: [PATCH] Nvidia Hotspot / VRAM temps (#583) Thanks to @TimSirmovics --- .../Hardware/Gpu/NvidiaGpu.cs | 75 ++++++++++++++++++- LibreHardwareMonitorLib/Interop/NvApi.cs | 20 +++++ 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs index ae9d603..2505c44 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs @@ -40,6 +40,9 @@ namespace LibreHardwareMonitor.Hardware.Gpu private readonly Sensor[] _powers; private readonly Sensor _powerUsage; private readonly Sensor[] _temperatures; + private uint _thermalSensorsMask; + private readonly Sensor _hotSpotTemperature; + private readonly Sensor _memoryJunctionTemperature; public NvidiaGpu(int adapterIndex, NvApi.NvPhysicalGpuHandle handle, NvApi.NvDisplayHandle? displayHandle, ISettings settings) : base(GetName(handle), @@ -79,6 +82,32 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } + // Thermal sensors. + _hotSpotTemperature = new Sensor("GPU Hot Spot", (int)thermalSettings.Count + 1, SensorType.Temperature, this, settings); + _memoryJunctionTemperature = new Sensor("GPU Memory Junction", (int)thermalSettings.Count + 2, SensorType.Temperature, this, settings); + bool hasAnyThermalSensor = false; + + for (int thermalSensorsMaxBit = 0; thermalSensorsMaxBit < 32; thermalSensorsMaxBit++) + { + // Find the maximum thermal sensor mask value. + _thermalSensorsMask = 1u << thermalSensorsMaxBit; + + GetThermalSensors(_thermalSensorsMask, out NvApi.NvStatus thermalSensorsStatus); + if (thermalSensorsStatus == NvApi.NvStatus.OK) + { + hasAnyThermalSensor = true; + continue; + } + + _thermalSensorsMask--; + break; + } + + if (!hasAnyThermalSensor) + { + _thermalSensorsMask = 0; + } + // Clock frequencies. for (int clockVersion = 1; clockVersion <= 3; clockVersion++) { @@ -434,6 +463,28 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } + if (_thermalSensorsMask > 0) + { + NvApi.NvThermalSensors thermalSensors = GetThermalSensors(_thermalSensorsMask, out status); + + if (status == NvApi.NvStatus.OK) + { + _hotSpotTemperature.Value = thermalSensors.Temperatures[1] / 256.0f; + _memoryJunctionTemperature.Value = thermalSensors.Temperatures[9] / 256.0f; + } + + if (_hotSpotTemperature.Value != 0) + ActivateSensor(_hotSpotTemperature); + + if (_memoryJunctionTemperature.Value != 0) + ActivateSensor(_memoryJunctionTemperature); + } + else + { + _hotSpotTemperature.Value = null; + _memoryJunctionTemperature.Value = null; + } + if (_clocks is { Length: > 0 }) { NvApi.NvGpuClockFrequencies clockFrequencies = GetClockFrequencies(out status); @@ -928,6 +979,24 @@ namespace LibreHardwareMonitor.Hardware.Gpu return status == NvApi.NvStatus.OK ? settings : default; } + private NvApi.NvThermalSensors GetThermalSensors(uint mask, out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_ThermalGetSensors == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + var thermalSensors = new NvApi.NvThermalSensors() + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(2), + Mask = mask + }; + + status = NvApi.NvAPI_GPU_ThermalGetSensors(_handle, ref thermalSensors); + return status == NvApi.NvStatus.OK ? thermalSensors : default; + } + private NvApi.NvFanCoolersStatus GetFanCoolersStatus(out NvApi.NvStatus status) { if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus == null) @@ -938,7 +1007,8 @@ namespace LibreHardwareMonitor.Hardware.Gpu var coolers = new NvApi.NvFanCoolersStatus { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), + Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] }; status = NvApi.NvAPI_GPU_ClientFanCoolersGetStatus(_handle, ref coolers); @@ -983,7 +1053,8 @@ namespace LibreHardwareMonitor.Hardware.Gpu NvApi.NvDynamicPStatesInfo pStatesInfo = new() { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), Utilizations = new NvApi.NvDynamicPState[NvApi.MAX_GPU_UTILIZATIONS] + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), + Utilizations = new NvApi.NvDynamicPState[NvApi.MAX_GPU_UTILIZATIONS] }; status = NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx(_handle, ref pStatesInfo); diff --git a/LibreHardwareMonitorLib/Interop/NvApi.cs b/LibreHardwareMonitorLib/Interop/NvApi.cs index ab55860..6aa3146 100644 --- a/LibreHardwareMonitorLib/Interop/NvApi.cs +++ b/LibreHardwareMonitorLib/Interop/NvApi.cs @@ -17,6 +17,8 @@ namespace LibreHardwareMonitor.Interop public const int MAX_POWER_TOPOLOGIES = 4; public const int MAX_THERMAL_SENSORS_PER_GPU = 3; public const int MAX_USAGES_PER_GPU = 8; + public const int THERMAL_SENSOR_RESERVED_COUNT = 8; + public const int THERMAL_SENSOR_TEMPERATURE_COUNT = 32; public const int SHORT_STRING_MAX = 64; @@ -39,6 +41,7 @@ namespace LibreHardwareMonitor.Interop public static readonly NvAPI_GPU_GetThermalSettingsDelegate NvAPI_GPU_GetThermalSettings; public static readonly NvAPI_GPU_GetUsagesDelegate NvAPI_GPU_GetUsages; public static readonly NvAPI_GPU_SetCoolerLevelsDelegate NvAPI_GPU_SetCoolerLevels; + public static readonly NvAPI_GPU_GetThermalSensorsDelegate NvAPI_GPU_ThermalGetSensors; private static readonly NvAPI_GetInterfaceVersionStringDelegate _nvAPI_GetInterfaceVersionString; private static readonly NvAPI_GPU_GetFullNameDelegate _nvAPI_GPU_GetFullName; @@ -87,6 +90,7 @@ namespace LibreHardwareMonitor.Interop GetDelegate(0x814B209F, out NvAPI_GPU_ClientFanCoolersGetControl); GetDelegate(0xA58971A5, out NvAPI_GPU_ClientFanCoolersSetControl); GetDelegate(0x0EDCF624E, out NvAPI_GPU_ClientPowerTopologyGetStatus); + GetDelegate(0x65FE3AAD, out NvAPI_GPU_ThermalGetSensors); IsAvailable = true; } @@ -152,6 +156,9 @@ namespace LibreHardwareMonitor.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvCoolerLevels NvCoolerLevels); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetThermalSensorsDelegate(NvPhysicalGpuHandle gpuHandle, ref NvThermalSensors nvThermalSensors); + public enum NvFanControlMode : uint { Auto = 0, @@ -502,6 +509,19 @@ namespace LibreHardwareMonitor.Interop public NvLevel[] Levels; } + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct NvThermalSensors + { + internal uint Version; + internal uint Mask; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = THERMAL_SENSOR_RESERVED_COUNT)] + internal int[] Reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = THERMAL_SENSOR_TEMPERATURE_COUNT)] + internal int[] Temperatures; + } + [StructLayout(LayoutKind.Sequential, Pack = 8)] internal struct NvMemoryInfo {