moel@1: /* moel@1: moel@1: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@1: moel@1: The contents of this file are subject to the Mozilla Public License Version moel@1: 1.1 (the "License"); you may not use this file except in compliance with moel@1: the License. You may obtain a copy of the License at moel@1: moel@1: http://www.mozilla.org/MPL/ moel@1: moel@1: Software distributed under the License is distributed on an "AS IS" basis, moel@1: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@1: for the specific language governing rights and limitations under the License. moel@1: moel@1: The Original Code is the Open Hardware Monitor code. moel@1: moel@1: The Initial Developer of the Original Code is moel@1: Michael Möller . moel@1: Portions created by the Initial Developer are Copyright (C) 2009-2010 moel@1: the Initial Developer. All Rights Reserved. moel@1: moel@1: Contributor(s): moel@1: moel@1: Alternatively, the contents of this file may be used under the terms of moel@1: either the GNU General Public License Version 2 or later (the "GPL"), or moel@1: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@1: in which case the provisions of the GPL or the LGPL are applicable instead moel@1: of those above. If you wish to allow use of your version of this file only moel@1: under the terms of either the GPL or the LGPL, and not to allow others to moel@1: use your version of this file under the terms of the MPL, indicate your moel@1: decision by deleting the provisions above and replace them with the notice moel@1: and other provisions required by the GPL or the LGPL. If you do not delete moel@1: the provisions above, a recipient may use your version of this file under moel@1: the terms of any one of the MPL, the GPL or the LGPL. moel@1: moel@1: */ moel@1: moel@1: using System; moel@166: using System.Globalization; moel@140: using System.Text; moel@1: moel@1: namespace OpenHardwareMonitor.Hardware.Nvidia { moel@195: internal class NvidiaGPU : Hardware { moel@1: moel@195: private readonly string name; moel@195: private readonly int adapterIndex; moel@195: private readonly NvPhysicalGpuHandle handle; moel@195: private readonly NvDisplayHandle? displayHandle; moel@1: moel@195: private readonly Sensor[] temperatures; moel@195: private readonly Sensor fan; moel@195: private readonly Sensor[] clocks; moel@195: private readonly Sensor[] loads; moel@195: private readonly Sensor control; moel@195: private readonly Sensor memoryLoad; moel@38: moel@140: public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle, moel@165: NvDisplayHandle? displayHandle, ISettings settings) moel@140: { moel@56: string gpuName; moel@56: if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) { moel@56: this.name = "NVIDIA " + gpuName.Trim(); moel@56: } else { moel@56: this.name = "NVIDIA"; moel@56: } moel@56: this.adapterIndex = adapterIndex; moel@56: this.handle = handle; moel@140: this.displayHandle = displayHandle; moel@1: moel@165: NvGPUThermalSettings thermalSettings = GetThermalSettings(); moel@165: temperatures = new Sensor[thermalSettings.Count]; moel@56: for (int i = 0; i < temperatures.Length; i++) { moel@165: NvSensor sensor = thermalSettings.Sensor[i]; moel@56: string name; moel@56: switch (sensor.Target) { moel@56: case NvThermalTarget.BOARD: name = "GPU Board"; break; moel@56: case NvThermalTarget.GPU: name = "GPU Core"; break; moel@56: case NvThermalTarget.MEMORY: name = "GPU Memory"; break; moel@56: case NvThermalTarget.POWER_SUPPLY: name = "GPU Power Supply"; break; moel@56: case NvThermalTarget.UNKNOWN: name = "GPU Unknown"; break; moel@56: default: name = "GPU"; break; moel@38: } moel@165: temperatures[i] = new Sensor(name, i, SensorType.Temperature, this, moel@165: new ParameterDescription[0], settings); moel@56: ActivateSensor(temperatures[i]); moel@56: } moel@1: moel@56: int value; moel@56: if (NVAPI.NvAPI_GPU_GetTachReading != null && moel@56: NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) { moel@56: if (value > 0) { moel@165: fan = new Sensor("GPU", 0, SensorType.Fan, this, settings); moel@56: ActivateSensor(fan); moel@1: } moel@1: } moel@140: moel@140: clocks = new Sensor[3]; moel@165: clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings); moel@165: clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings); moel@165: clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this, settings); moel@140: for (int i = 0; i < clocks.Length; i++) moel@140: ActivateSensor(clocks[i]); moel@140: moel@140: loads = new Sensor[3]; moel@165: loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings); moel@165: loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings); moel@165: loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings); moel@165: memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings); moel@140: moel@165: control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings); moel@1: } moel@1: moel@110: public override string Name { moel@1: get { return name; } moel@1: } moel@1: moel@110: public override Identifier Identifier { moel@166: get { moel@166: return new Identifier("nvidiagpu", moel@166: adapterIndex.ToString(CultureInfo.InvariantCulture)); moel@166: } moel@1: } moel@1: moel@165: public override HardwareType HardwareType { moel@176: get { return HardwareType.GpuNvidia; } moel@1: } moel@1: moel@1: private NvGPUThermalSettings GetThermalSettings() { moel@1: NvGPUThermalSettings settings = new NvGPUThermalSettings(); moel@1: settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER; moel@1: settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU; moel@1: settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU]; moel@140: if (NVAPI.NvAPI_GPU_GetThermalSettings != null && moel@140: NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL, moel@38: ref settings) != NvStatus.OK) { moel@38: settings.Count = 0; moel@38: } moel@1: return settings; moel@1: } moel@1: moel@140: private uint[] GetClocks() { moel@166: NvClocks allClocks = new NvClocks(); moel@166: allClocks.Version = NVAPI.GPU_CLOCKS_VER; moel@166: allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU]; moel@140: if (NVAPI.NvAPI_GPU_GetAllClocks != null && moel@166: NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks) == NvStatus.OK) { moel@166: return allClocks.Clock; moel@140: } moel@140: return null; moel@140: } moel@140: moel@110: public override void Update() { moel@1: NvGPUThermalSettings settings = GetThermalSettings(); moel@1: foreach (Sensor sensor in temperatures) moel@38: sensor.Value = settings.Sensor[sensor.Index].CurrentTemp; moel@38: moel@38: if (fan != null) { moel@38: int value = 0; moel@38: NVAPI.NvAPI_GPU_GetTachReading(handle, out value); moel@38: fan.Value = value; moel@38: } moel@140: moel@140: uint[] values = GetClocks(); moel@140: if (values != null) { moel@140: clocks[0].Value = 0.001f * values[0]; moel@140: clocks[1].Value = 0.001f * values[8]; moel@140: clocks[2].Value = 0.001f * values[14]; moel@140: if (values[30] != 0) { moel@140: clocks[0].Value = 0.0005f * values[30]; moel@140: clocks[2].Value = 0.001f * values[30]; moel@140: } moel@140: } moel@140: moel@140: NvPStates states = new NvPStates(); moel@140: states.Version = NVAPI.GPU_PSTATES_VER; moel@140: states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU]; moel@140: if (NVAPI.NvAPI_GPU_GetPStates != null && moel@140: NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) { moel@140: for (int i = 0; i < 3; i++) moel@140: if (states.PStates[i].Present) { moel@140: loads[i].Value = states.PStates[i].Percentage; moel@140: ActivateSensor(loads[i]); moel@140: } moel@140: } else { moel@140: NvUsages usages = new NvUsages(); moel@140: usages.Version = NVAPI.GPU_USAGES_VER; moel@140: usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU]; moel@140: if (NVAPI.NvAPI_GPU_GetUsages != null && moel@140: NVAPI.NvAPI_GPU_GetUsages(handle, ref usages) == NvStatus.OK) { moel@140: loads[0].Value = usages.Usage[2]; moel@140: loads[1].Value = usages.Usage[6]; moel@140: loads[2].Value = usages.Usage[10]; moel@140: for (int i = 0; i < 3; i++) moel@140: ActivateSensor(loads[i]); moel@140: } moel@140: } moel@140: moel@140: NvGPUCoolerSettings coolerSettings = new NvGPUCoolerSettings(); moel@140: coolerSettings.Version = NVAPI.GPU_COOLER_SETTINGS_VER; moel@140: coolerSettings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU]; moel@140: if (NVAPI.NvAPI_GPU_GetCoolerSettings != null && moel@140: NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref coolerSettings) == moel@140: NvStatus.OK && coolerSettings.Count > 0) { moel@140: control.Value = coolerSettings.Cooler[0].CurrentLevel; moel@140: ActivateSensor(control); moel@140: } moel@140: moel@140: NvMemoryInfo memoryInfo = new NvMemoryInfo(); moel@140: memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER; moel@140: memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU]; moel@140: if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue && moel@140: NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) == moel@140: NvStatus.OK) moel@140: { moel@140: uint totalMemory = memoryInfo.Values[0]; moel@140: uint freeMemory = memoryInfo.Values[4]; moel@140: float usedMemory = Math.Max(totalMemory - freeMemory, 0); moel@140: memoryLoad.Value = 100f * usedMemory / totalMemory; moel@140: ActivateSensor(memoryLoad); moel@140: } moel@140: } moel@140: moel@140: public override string GetReport() { moel@140: StringBuilder r = new StringBuilder(); moel@140: moel@140: r.AppendLine("Nvidia GPU"); moel@140: r.AppendLine(); moel@140: moel@140: r.AppendFormat("Name: {0}{1}", name, Environment.NewLine); moel@140: r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine); moel@140: moel@140: if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) moel@140: { moel@140: NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion(); moel@140: driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER; moel@140: if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value, moel@140: ref driverVersion) == NvStatus.OK) { moel@140: r.Append("Driver Version: "); moel@140: r.Append(driverVersion.DriverVersion / 100); moel@140: r.Append("."); moel@167: r.Append((driverVersion.DriverVersion % 100).ToString("00", moel@167: CultureInfo.InvariantCulture)); moel@140: r.AppendLine(); moel@140: r.Append("Driver Branch: "); moel@140: r.AppendLine(driverVersion.BuildBranch); moel@140: } moel@140: } moel@140: r.AppendLine(); moel@140: moel@140: if (NVAPI.NvAPI_GPU_GetThermalSettings != null) { moel@140: NvGPUThermalSettings settings = new NvGPUThermalSettings(); moel@140: settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER; moel@140: settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU; moel@140: settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU]; moel@140: moel@140: NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle, moel@140: (int)NvThermalTarget.ALL, ref settings); moel@140: moel@140: r.AppendLine("Thermal Settings"); moel@140: r.AppendLine(); moel@140: if (status == NvStatus.OK) { moel@140: for (int i = 0; i < settings.Count; i++) { moel@140: r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i, moel@140: settings.Sensor[i].Controller, Environment.NewLine); moel@140: r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i, moel@140: settings.Sensor[i].DefaultMinTemp, Environment.NewLine); moel@140: r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i, moel@140: settings.Sensor[i].DefaultMaxTemp, Environment.NewLine); moel@140: r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i, moel@140: settings.Sensor[i].CurrentTemp, Environment.NewLine); moel@140: r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i, moel@140: settings.Sensor[i].Target, Environment.NewLine); moel@140: } moel@140: } else { moel@140: r.Append(" Status: "); moel@140: r.AppendLine(status.ToString()); moel@140: } moel@140: r.AppendLine(); moel@140: } moel@140: moel@140: if (NVAPI.NvAPI_GPU_GetAllClocks != null) { moel@166: NvClocks allClocks = new NvClocks(); moel@166: allClocks.Version = NVAPI.GPU_CLOCKS_VER; moel@166: allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU]; moel@166: NvStatus status = NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks); moel@140: moel@140: r.AppendLine("Clocks"); moel@140: r.AppendLine(); moel@140: if (status == NvStatus.OK) { moel@166: for (int i = 0; i < allClocks.Clock.Length; i++) moel@166: if (allClocks.Clock[i] > 0) { moel@166: r.AppendFormat(" Clock[{0}]: {1}{2}", i, allClocks.Clock[i], moel@140: Environment.NewLine); moel@140: } moel@140: } else { moel@140: r.Append(" Status: "); moel@140: r.AppendLine(status.ToString()); moel@140: } moel@140: r.AppendLine(); moel@140: } moel@140: moel@140: if (NVAPI.NvAPI_GPU_GetTachReading != null) { moel@140: int tachValue; moel@140: NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue); moel@140: moel@140: r.AppendLine("Tachometer"); moel@140: r.AppendLine(); moel@140: if (status == NvStatus.OK) { moel@140: r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine); moel@140: } else { moel@140: r.Append(" Status: "); moel@140: r.AppendLine(status.ToString()); moel@140: } moel@140: r.AppendLine(); moel@140: } moel@140: moel@140: if (NVAPI.NvAPI_GPU_GetPStates != null) { moel@140: NvPStates states = new NvPStates(); moel@140: states.Version = NVAPI.GPU_PSTATES_VER; moel@140: states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU]; moel@140: NvStatus status = NVAPI.NvAPI_GPU_GetPStates(handle, ref states); moel@140: moel@140: r.AppendLine("P-States"); moel@140: r.AppendLine(); moel@140: if (status == NvStatus.OK) { moel@140: for (int i = 0; i < states.PStates.Length; i++) moel@140: if (states.PStates[i].Present) moel@140: r.AppendFormat(" Percentage[{0}]: {1}{2}", i, moel@140: states.PStates[i].Percentage, Environment.NewLine); moel@140: } else { moel@140: r.Append(" Status: "); moel@140: r.AppendLine(status.ToString()); moel@140: } moel@140: r.AppendLine(); moel@140: } moel@140: moel@140: if (NVAPI.NvAPI_GPU_GetUsages != null) { moel@140: NvUsages usages = new NvUsages(); moel@140: usages.Version = NVAPI.GPU_USAGES_VER; moel@140: usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU]; moel@140: NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages); moel@140: moel@140: r.AppendLine("Usages"); moel@140: r.AppendLine(); moel@140: if (status == NvStatus.OK) { moel@140: for (int i = 0; i < usages.Usage.Length; i++) moel@140: if (usages.Usage[i] > 0) moel@140: r.AppendFormat(" Usage[{0}]: {1}{2}", i, moel@140: usages.Usage[i], Environment.NewLine); moel@140: } else { moel@140: r.Append(" Status: "); moel@140: r.AppendLine(status.ToString()); moel@140: } moel@140: r.AppendLine(); moel@140: } moel@140: moel@140: if (NVAPI.NvAPI_GPU_GetCoolerSettings != null) { moel@140: NvGPUCoolerSettings settings = new NvGPUCoolerSettings(); moel@140: settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER; moel@140: settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU]; moel@140: NvStatus status = moel@140: NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings); moel@140: moel@140: r.AppendLine("Cooler Settings"); moel@140: r.AppendLine(); moel@140: if (status == NvStatus.OK) { moel@140: for (int i = 0; i < settings.Count; i++) { moel@140: r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i, moel@140: settings.Cooler[i].Type, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i, moel@140: settings.Cooler[i].Controller, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i, moel@140: settings.Cooler[i].DefaultMin, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i, moel@140: settings.Cooler[i].DefaultMax, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i, moel@140: settings.Cooler[i].CurrentMin, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i, moel@140: settings.Cooler[i].CurrentMax, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i, moel@140: settings.Cooler[i].CurrentLevel, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i, moel@140: settings.Cooler[i].DefaultPolicy, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i, moel@140: settings.Cooler[i].CurrentPolicy, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i, moel@140: settings.Cooler[i].Target, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i, moel@140: settings.Cooler[i].ControlType, Environment.NewLine); moel@140: r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i, moel@140: settings.Cooler[i].Active, Environment.NewLine); moel@140: } moel@140: } else { moel@140: r.Append(" Status: "); moel@140: r.AppendLine(status.ToString()); moel@140: } moel@140: r.AppendLine(); moel@140: } moel@140: moel@140: if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue) { moel@140: NvMemoryInfo memoryInfo = new NvMemoryInfo(); moel@140: memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER; moel@140: memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU]; moel@140: NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, moel@140: ref memoryInfo); moel@140: moel@140: r.AppendLine("Memory Info"); moel@140: r.AppendLine(); moel@140: if (status == NvStatus.OK) { moel@140: for (int i = 0; i < memoryInfo.Values.Length; i++) moel@140: r.AppendFormat(" Value[{0}]: {1}{2}", i, moel@140: memoryInfo.Values[i], Environment.NewLine); moel@140: } else { moel@140: r.Append(" Status: "); moel@140: r.AppendLine(status.ToString()); moel@140: } moel@140: r.AppendLine(); moel@140: } moel@140: moel@140: return r.ToString(); moel@1: } moel@1: } moel@1: }