Improved the support for Nvidia GPUs.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 The contents of this file are subject to the Mozilla Public License Version
6 1.1 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 for the specific language governing rights and limitations under the License.
15 The Original Code is the Open Hardware Monitor code.
17 The Initial Developer of the Original Code is
18 Michael Möller <m.moeller@gmx.ch>.
19 Portions created by the Initial Developer are Copyright (C) 2009-2010
20 the Initial Developer. All Rights Reserved.
24 Alternatively, the contents of this file may be used under the terms of
25 either the GNU General Public License Version 2 or later (the "GPL"), or
26 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 in which case the provisions of the GPL or the LGPL are applicable instead
28 of those above. If you wish to allow use of your version of this file only
29 under the terms of either the GPL or the LGPL, and not to allow others to
30 use your version of this file under the terms of the MPL, indicate your
31 decision by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL or the LGPL. If you do not delete
33 the provisions above, a recipient may use your version of this file under
34 the terms of any one of the MPL, the GPL or the LGPL.
39 using System.Collections.Generic;
43 namespace OpenHardwareMonitor.Hardware.Nvidia {
44 public class NvidiaGPU : Hardware, IHardware {
48 private int adapterIndex;
49 private NvPhysicalGpuHandle handle;
50 private NvDisplayHandle? displayHandle;
52 private Sensor[] temperatures;
53 private Sensor fan = null;
54 private Sensor[] clocks;
55 private Sensor[] loads;
56 private Sensor control;
57 private Sensor memoryLoad;
59 public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
60 NvDisplayHandle? displayHandle)
63 if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
64 this.name = "NVIDIA " + gpuName.Trim();
68 this.icon = Utilities.EmbeddedResources.GetImage("nvidia.png");
69 this.adapterIndex = adapterIndex;
71 this.displayHandle = displayHandle;
73 NvGPUThermalSettings settings = GetThermalSettings();
74 temperatures = new Sensor[settings.Count];
75 for (int i = 0; i < temperatures.Length; i++) {
76 NvSensor sensor = settings.Sensor[i];
78 switch (sensor.Target) {
79 case NvThermalTarget.BOARD: name = "GPU Board"; break;
80 case NvThermalTarget.GPU: name = "GPU Core"; break;
81 case NvThermalTarget.MEMORY: name = "GPU Memory"; break;
82 case NvThermalTarget.POWER_SUPPLY: name = "GPU Power Supply"; break;
83 case NvThermalTarget.UNKNOWN: name = "GPU Unknown"; break;
84 default: name = "GPU"; break;
86 temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
87 new ParameterDescription[0]);
88 ActivateSensor(temperatures[i]);
92 if (NVAPI.NvAPI_GPU_GetTachReading != null &&
93 NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
95 fan = new Sensor("GPU", 0, SensorType.Fan, this);
100 clocks = new Sensor[3];
101 clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this);
102 clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this);
103 clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this);
104 for (int i = 0; i < clocks.Length; i++)
105 ActivateSensor(clocks[i]);
107 loads = new Sensor[3];
108 loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this);
109 loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this);
110 loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this);
111 memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this);
113 control = new Sensor("GPU Fan", 0, SensorType.Control, this);
116 public override string Name {
120 public override Identifier Identifier {
121 get { return new Identifier("nvidiagpu", adapterIndex.ToString()); }
124 public override Image Icon {
128 private NvGPUThermalSettings GetThermalSettings() {
129 NvGPUThermalSettings settings = new NvGPUThermalSettings();
130 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
131 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
132 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
133 if (NVAPI.NvAPI_GPU_GetThermalSettings != null &&
134 NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
135 ref settings) != NvStatus.OK) {
141 private uint[] GetClocks() {
142 NvClocks clocks = new NvClocks();
143 clocks.Version = NVAPI.GPU_CLOCKS_VER;
144 clocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
145 if (NVAPI.NvAPI_GPU_GetAllClocks != null &&
146 NVAPI.NvAPI_GPU_GetAllClocks(handle, ref clocks) == NvStatus.OK) {
152 public override void Update() {
153 NvGPUThermalSettings settings = GetThermalSettings();
154 foreach (Sensor sensor in temperatures)
155 sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
159 NVAPI.NvAPI_GPU_GetTachReading(handle, out value);
163 uint[] values = GetClocks();
164 if (values != null) {
165 clocks[0].Value = 0.001f * values[0];
166 clocks[1].Value = 0.001f * values[8];
167 clocks[2].Value = 0.001f * values[14];
168 if (values[30] != 0) {
169 clocks[0].Value = 0.0005f * values[30];
170 clocks[2].Value = 0.001f * values[30];
174 NvPStates states = new NvPStates();
175 states.Version = NVAPI.GPU_PSTATES_VER;
176 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
177 if (NVAPI.NvAPI_GPU_GetPStates != null &&
178 NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) {
179 for (int i = 0; i < 3; i++)
180 if (states.PStates[i].Present) {
181 loads[i].Value = states.PStates[i].Percentage;
182 ActivateSensor(loads[i]);
185 NvUsages usages = new NvUsages();
186 usages.Version = NVAPI.GPU_USAGES_VER;
187 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
188 if (NVAPI.NvAPI_GPU_GetUsages != null &&
189 NVAPI.NvAPI_GPU_GetUsages(handle, ref usages) == NvStatus.OK) {
190 loads[0].Value = usages.Usage[2];
191 loads[1].Value = usages.Usage[6];
192 loads[2].Value = usages.Usage[10];
193 for (int i = 0; i < 3; i++)
194 ActivateSensor(loads[i]);
198 NvGPUCoolerSettings coolerSettings = new NvGPUCoolerSettings();
199 coolerSettings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
200 coolerSettings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
201 if (NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
202 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref coolerSettings) ==
203 NvStatus.OK && coolerSettings.Count > 0) {
204 control.Value = coolerSettings.Cooler[0].CurrentLevel;
205 ActivateSensor(control);
208 NvMemoryInfo memoryInfo = new NvMemoryInfo();
209 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
210 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
211 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue &&
212 NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) ==
215 uint totalMemory = memoryInfo.Values[0];
216 uint freeMemory = memoryInfo.Values[4];
217 float usedMemory = Math.Max(totalMemory - freeMemory, 0);
218 memoryLoad.Value = 100f * usedMemory / totalMemory;
219 ActivateSensor(memoryLoad);
223 public override string GetReport() {
224 StringBuilder r = new StringBuilder();
226 r.AppendLine("Nvidia GPU");
229 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
230 r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
232 if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null)
234 NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion();
235 driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
236 if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value,
237 ref driverVersion) == NvStatus.OK) {
238 r.Append("Driver Version: ");
239 r.Append(driverVersion.DriverVersion / 100);
241 r.Append((driverVersion.DriverVersion % 100).ToString("00"));
243 r.Append("Driver Branch: ");
244 r.AppendLine(driverVersion.BuildBranch);
249 if (NVAPI.NvAPI_GPU_GetThermalSettings != null) {
250 NvGPUThermalSettings settings = new NvGPUThermalSettings();
251 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
252 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
253 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
255 NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
256 (int)NvThermalTarget.ALL, ref settings);
258 r.AppendLine("Thermal Settings");
260 if (status == NvStatus.OK) {
261 for (int i = 0; i < settings.Count; i++) {
262 r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i,
263 settings.Sensor[i].Controller, Environment.NewLine);
264 r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i,
265 settings.Sensor[i].DefaultMinTemp, Environment.NewLine);
266 r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i,
267 settings.Sensor[i].DefaultMaxTemp, Environment.NewLine);
268 r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i,
269 settings.Sensor[i].CurrentTemp, Environment.NewLine);
270 r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i,
271 settings.Sensor[i].Target, Environment.NewLine);
274 r.Append(" Status: ");
275 r.AppendLine(status.ToString());
280 if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
281 NvClocks clocks = new NvClocks();
282 clocks.Version = NVAPI.GPU_CLOCKS_VER;
283 clocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
284 NvStatus status = NVAPI.NvAPI_GPU_GetAllClocks(handle, ref clocks);
286 r.AppendLine("Clocks");
288 if (status == NvStatus.OK) {
289 for (int i = 0; i < clocks.Clock.Length; i++)
290 if (clocks.Clock[i] > 0) {
291 r.AppendFormat(" Clock[{0}]: {1}{2}", i, clocks.Clock[i],
292 Environment.NewLine);
295 r.Append(" Status: ");
296 r.AppendLine(status.ToString());
301 if (NVAPI.NvAPI_GPU_GetTachReading != null) {
303 NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
305 r.AppendLine("Tachometer");
307 if (status == NvStatus.OK) {
308 r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
310 r.Append(" Status: ");
311 r.AppendLine(status.ToString());
316 if (NVAPI.NvAPI_GPU_GetPStates != null) {
317 NvPStates states = new NvPStates();
318 states.Version = NVAPI.GPU_PSTATES_VER;
319 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
320 NvStatus status = NVAPI.NvAPI_GPU_GetPStates(handle, ref states);
322 r.AppendLine("P-States");
324 if (status == NvStatus.OK) {
325 for (int i = 0; i < states.PStates.Length; i++)
326 if (states.PStates[i].Present)
327 r.AppendFormat(" Percentage[{0}]: {1}{2}", i,
328 states.PStates[i].Percentage, Environment.NewLine);
330 r.Append(" Status: ");
331 r.AppendLine(status.ToString());
336 if (NVAPI.NvAPI_GPU_GetUsages != null) {
337 NvUsages usages = new NvUsages();
338 usages.Version = NVAPI.GPU_USAGES_VER;
339 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
340 NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
342 r.AppendLine("Usages");
344 if (status == NvStatus.OK) {
345 for (int i = 0; i < usages.Usage.Length; i++)
346 if (usages.Usage[i] > 0)
347 r.AppendFormat(" Usage[{0}]: {1}{2}", i,
348 usages.Usage[i], Environment.NewLine);
350 r.Append(" Status: ");
351 r.AppendLine(status.ToString());
356 if (NVAPI.NvAPI_GPU_GetCoolerSettings != null) {
357 NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
358 settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
359 settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
361 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
363 r.AppendLine("Cooler Settings");
365 if (status == NvStatus.OK) {
366 for (int i = 0; i < settings.Count; i++) {
367 r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i,
368 settings.Cooler[i].Type, Environment.NewLine);
369 r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i,
370 settings.Cooler[i].Controller, Environment.NewLine);
371 r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i,
372 settings.Cooler[i].DefaultMin, Environment.NewLine);
373 r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i,
374 settings.Cooler[i].DefaultMax, Environment.NewLine);
375 r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i,
376 settings.Cooler[i].CurrentMin, Environment.NewLine);
377 r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i,
378 settings.Cooler[i].CurrentMax, Environment.NewLine);
379 r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i,
380 settings.Cooler[i].CurrentLevel, Environment.NewLine);
381 r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i,
382 settings.Cooler[i].DefaultPolicy, Environment.NewLine);
383 r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i,
384 settings.Cooler[i].CurrentPolicy, Environment.NewLine);
385 r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i,
386 settings.Cooler[i].Target, Environment.NewLine);
387 r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i,
388 settings.Cooler[i].ControlType, Environment.NewLine);
389 r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i,
390 settings.Cooler[i].Active, Environment.NewLine);
393 r.Append(" Status: ");
394 r.AppendLine(status.ToString());
399 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue) {
400 NvMemoryInfo memoryInfo = new NvMemoryInfo();
401 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
402 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
403 NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
406 r.AppendLine("Memory Info");
408 if (status == NvStatus.OK) {
409 for (int i = 0; i < memoryInfo.Values.Length; i++)
410 r.AppendFormat(" Value[{0}]: {1}{2}", i,
411 memoryInfo.Values[i], Environment.NewLine);
413 r.Append(" Status: ");
414 r.AppendLine(status.ToString());