Fixed Issue 172.
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.Globalization;
42 namespace OpenHardwareMonitor.Hardware.Nvidia {
43 internal class NvidiaGPU : Hardware {
45 private readonly string name;
46 private readonly int adapterIndex;
47 private readonly NvPhysicalGpuHandle handle;
48 private readonly NvDisplayHandle? displayHandle;
50 private readonly Sensor[] temperatures;
51 private readonly Sensor fan;
52 private readonly Sensor[] clocks;
53 private readonly Sensor[] loads;
54 private readonly Sensor control;
55 private readonly Sensor memoryLoad;
57 public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
58 NvDisplayHandle? displayHandle, ISettings settings)
61 if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
62 this.name = "NVIDIA " + gpuName.Trim();
66 this.adapterIndex = adapterIndex;
68 this.displayHandle = displayHandle;
70 NvGPUThermalSettings thermalSettings = GetThermalSettings();
71 temperatures = new Sensor[thermalSettings.Count];
72 for (int i = 0; i < temperatures.Length; i++) {
73 NvSensor sensor = thermalSettings.Sensor[i];
75 switch (sensor.Target) {
76 case NvThermalTarget.BOARD: name = "GPU Board"; break;
77 case NvThermalTarget.GPU: name = "GPU Core"; break;
78 case NvThermalTarget.MEMORY: name = "GPU Memory"; break;
79 case NvThermalTarget.POWER_SUPPLY: name = "GPU Power Supply"; break;
80 case NvThermalTarget.UNKNOWN: name = "GPU Unknown"; break;
81 default: name = "GPU"; break;
83 temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
84 new ParameterDescription[0], settings);
85 ActivateSensor(temperatures[i]);
89 if (NVAPI.NvAPI_GPU_GetTachReading != null &&
90 NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
92 fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
97 clocks = new Sensor[3];
98 clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings);
99 clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings);
100 clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this, settings);
101 for (int i = 0; i < clocks.Length; i++)
102 ActivateSensor(clocks[i]);
104 loads = new Sensor[3];
105 loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings);
106 loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings);
107 loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings);
108 memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
110 control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
113 public override string Name {
117 public override Identifier Identifier {
119 return new Identifier("nvidiagpu",
120 adapterIndex.ToString(CultureInfo.InvariantCulture));
124 public override HardwareType HardwareType {
125 get { return HardwareType.GpuNvidia; }
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 allClocks = new NvClocks();
143 allClocks.Version = NVAPI.GPU_CLOCKS_VER;
144 allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
145 if (NVAPI.NvAPI_GPU_GetAllClocks != null &&
146 NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks) == NvStatus.OK) {
147 return allClocks.Clock;
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",
242 CultureInfo.InvariantCulture));
244 r.Append("Driver Branch: ");
245 r.AppendLine(driverVersion.BuildBranch);
250 if (NVAPI.NvAPI_GPU_GetThermalSettings != null) {
251 NvGPUThermalSettings settings = new NvGPUThermalSettings();
252 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
253 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
254 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
256 NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
257 (int)NvThermalTarget.ALL, ref settings);
259 r.AppendLine("Thermal Settings");
261 if (status == NvStatus.OK) {
262 for (int i = 0; i < settings.Count; i++) {
263 r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i,
264 settings.Sensor[i].Controller, Environment.NewLine);
265 r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i,
266 settings.Sensor[i].DefaultMinTemp, Environment.NewLine);
267 r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i,
268 settings.Sensor[i].DefaultMaxTemp, Environment.NewLine);
269 r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i,
270 settings.Sensor[i].CurrentTemp, Environment.NewLine);
271 r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i,
272 settings.Sensor[i].Target, Environment.NewLine);
275 r.Append(" Status: ");
276 r.AppendLine(status.ToString());
281 if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
282 NvClocks allClocks = new NvClocks();
283 allClocks.Version = NVAPI.GPU_CLOCKS_VER;
284 allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
285 NvStatus status = NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks);
287 r.AppendLine("Clocks");
289 if (status == NvStatus.OK) {
290 for (int i = 0; i < allClocks.Clock.Length; i++)
291 if (allClocks.Clock[i] > 0) {
292 r.AppendFormat(" Clock[{0}]: {1}{2}", i, allClocks.Clock[i],
293 Environment.NewLine);
296 r.Append(" Status: ");
297 r.AppendLine(status.ToString());
302 if (NVAPI.NvAPI_GPU_GetTachReading != null) {
304 NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
306 r.AppendLine("Tachometer");
308 if (status == NvStatus.OK) {
309 r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
311 r.Append(" Status: ");
312 r.AppendLine(status.ToString());
317 if (NVAPI.NvAPI_GPU_GetPStates != null) {
318 NvPStates states = new NvPStates();
319 states.Version = NVAPI.GPU_PSTATES_VER;
320 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
321 NvStatus status = NVAPI.NvAPI_GPU_GetPStates(handle, ref states);
323 r.AppendLine("P-States");
325 if (status == NvStatus.OK) {
326 for (int i = 0; i < states.PStates.Length; i++)
327 if (states.PStates[i].Present)
328 r.AppendFormat(" Percentage[{0}]: {1}{2}", i,
329 states.PStates[i].Percentage, Environment.NewLine);
331 r.Append(" Status: ");
332 r.AppendLine(status.ToString());
337 if (NVAPI.NvAPI_GPU_GetUsages != null) {
338 NvUsages usages = new NvUsages();
339 usages.Version = NVAPI.GPU_USAGES_VER;
340 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
341 NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
343 r.AppendLine("Usages");
345 if (status == NvStatus.OK) {
346 for (int i = 0; i < usages.Usage.Length; i++)
347 if (usages.Usage[i] > 0)
348 r.AppendFormat(" Usage[{0}]: {1}{2}", i,
349 usages.Usage[i], Environment.NewLine);
351 r.Append(" Status: ");
352 r.AppendLine(status.ToString());
357 if (NVAPI.NvAPI_GPU_GetCoolerSettings != null) {
358 NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
359 settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
360 settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
362 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
364 r.AppendLine("Cooler Settings");
366 if (status == NvStatus.OK) {
367 for (int i = 0; i < settings.Count; i++) {
368 r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i,
369 settings.Cooler[i].Type, Environment.NewLine);
370 r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i,
371 settings.Cooler[i].Controller, Environment.NewLine);
372 r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i,
373 settings.Cooler[i].DefaultMin, Environment.NewLine);
374 r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i,
375 settings.Cooler[i].DefaultMax, Environment.NewLine);
376 r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i,
377 settings.Cooler[i].CurrentMin, Environment.NewLine);
378 r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i,
379 settings.Cooler[i].CurrentMax, Environment.NewLine);
380 r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i,
381 settings.Cooler[i].CurrentLevel, Environment.NewLine);
382 r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i,
383 settings.Cooler[i].DefaultPolicy, Environment.NewLine);
384 r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i,
385 settings.Cooler[i].CurrentPolicy, Environment.NewLine);
386 r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i,
387 settings.Cooler[i].Target, Environment.NewLine);
388 r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i,
389 settings.Cooler[i].ControlType, Environment.NewLine);
390 r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i,
391 settings.Cooler[i].Active, Environment.NewLine);
394 r.Append(" Status: ");
395 r.AppendLine(status.ToString());
400 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue) {
401 NvMemoryInfo memoryInfo = new NvMemoryInfo();
402 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
403 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
404 NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
407 r.AppendLine("Memory Info");
409 if (status == NvStatus.OK) {
410 for (int i = 0; i < memoryInfo.Values.Length; i++)
411 r.AppendFormat(" Value[{0}]: {1}{2}", i,
412 memoryInfo.Values[i], Environment.NewLine);
414 r.Append(" Status: ");
415 r.AppendLine(status.ToString());