Fixed Issue 651.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
8 Copyright (C) 2011 Christian Vallières
13 using System.Globalization;
16 namespace OpenHardwareMonitor.Hardware.Nvidia {
17 internal class NvidiaGPU : Hardware {
19 private readonly int adapterIndex;
20 private readonly NvPhysicalGpuHandle handle;
21 private readonly NvDisplayHandle? displayHandle;
23 private readonly Sensor[] temperatures;
24 private readonly Sensor fan;
25 private readonly Sensor[] clocks;
26 private readonly Sensor[] loads;
27 private readonly Sensor control;
28 private readonly Sensor memoryLoad;
29 private readonly Control fanControl;
31 public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
32 NvDisplayHandle? displayHandle, ISettings settings)
33 : base(GetName(handle), new Identifier("nvidiagpu",
34 adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) {
35 this.adapterIndex = adapterIndex;
37 this.displayHandle = displayHandle;
39 NvGPUThermalSettings thermalSettings = GetThermalSettings();
40 temperatures = new Sensor[thermalSettings.Count];
41 for (int i = 0; i < temperatures.Length; i++) {
42 NvSensor sensor = thermalSettings.Sensor[i];
44 switch (sensor.Target) {
45 case NvThermalTarget.BOARD: name = "GPU Board"; break;
46 case NvThermalTarget.GPU: name = "GPU Core"; break;
47 case NvThermalTarget.MEMORY: name = "GPU Memory"; break;
48 case NvThermalTarget.POWER_SUPPLY: name = "GPU Power Supply"; break;
49 case NvThermalTarget.UNKNOWN: name = "GPU Unknown"; break;
50 default: name = "GPU"; break;
52 temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
53 new ParameterDescription[0], settings);
54 ActivateSensor(temperatures[i]);
58 if (NVAPI.NvAPI_GPU_GetTachReading != null &&
59 NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
61 fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
66 clocks = new Sensor[3];
67 clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings);
68 clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings);
69 clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this, settings);
70 for (int i = 0; i < clocks.Length; i++)
71 ActivateSensor(clocks[i]);
73 loads = new Sensor[3];
74 loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings);
75 loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings);
76 loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings);
77 memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
79 control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
81 NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
82 if (coolerSettings.Count > 0) {
83 fanControl = new Control(control, settings,
84 coolerSettings.Cooler[0].DefaultMin,
85 coolerSettings.Cooler[0].DefaultMax);
86 fanControl.ControlModeChanged += ControlModeChanged;
87 fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged;
88 ControlModeChanged(fanControl);
89 control.Control = fanControl;
94 private static string GetName(NvPhysicalGpuHandle handle) {
96 if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
97 return "NVIDIA " + gpuName.Trim();
103 public override HardwareType HardwareType {
104 get { return HardwareType.GpuNvidia; }
107 private NvGPUThermalSettings GetThermalSettings() {
108 NvGPUThermalSettings settings = new NvGPUThermalSettings();
109 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
110 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
111 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
112 if (!(NVAPI.NvAPI_GPU_GetThermalSettings != null &&
113 NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
114 ref settings) == NvStatus.OK))
121 private NvGPUCoolerSettings GetCoolerSettings() {
122 NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
123 settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
124 settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
125 if (!(NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
126 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0,
127 ref settings) == NvStatus.OK))
134 private uint[] GetClocks() {
135 NvClocks allClocks = new NvClocks();
136 allClocks.Version = NVAPI.GPU_CLOCKS_VER;
137 allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
138 if (NVAPI.NvAPI_GPU_GetAllClocks != null &&
139 NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks) == NvStatus.OK) {
140 return allClocks.Clock;
145 public override void Update() {
146 NvGPUThermalSettings settings = GetThermalSettings();
147 foreach (Sensor sensor in temperatures)
148 sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
152 NVAPI.NvAPI_GPU_GetTachReading(handle, out value);
156 uint[] values = GetClocks();
157 if (values != null) {
158 clocks[0].Value = 0.001f * values[0];
159 clocks[1].Value = 0.001f * values[8];
160 clocks[2].Value = 0.001f * values[14];
161 if (values[30] != 0) {
162 clocks[0].Value = 0.0005f * values[30];
163 clocks[2].Value = 0.001f * values[30];
167 NvPStates states = new NvPStates();
168 states.Version = NVAPI.GPU_PSTATES_VER;
169 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
170 if (NVAPI.NvAPI_GPU_GetPStates != null &&
171 NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) {
172 for (int i = 0; i < 3; i++)
173 if (states.PStates[i].Present) {
174 loads[i].Value = states.PStates[i].Percentage;
175 ActivateSensor(loads[i]);
178 NvUsages usages = new NvUsages();
179 usages.Version = NVAPI.GPU_USAGES_VER;
180 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
181 if (NVAPI.NvAPI_GPU_GetUsages != null &&
182 NVAPI.NvAPI_GPU_GetUsages(handle, ref usages) == NvStatus.OK) {
183 loads[0].Value = usages.Usage[2];
184 loads[1].Value = usages.Usage[6];
185 loads[2].Value = usages.Usage[10];
186 for (int i = 0; i < 3; i++)
187 ActivateSensor(loads[i]);
192 NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
193 if (coolerSettings.Count > 0) {
194 control.Value = coolerSettings.Cooler[0].CurrentLevel;
195 ActivateSensor(control);
198 NvMemoryInfo memoryInfo = new NvMemoryInfo();
199 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
200 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
201 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue &&
202 NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) ==
204 uint totalMemory = memoryInfo.Values[0];
205 uint freeMemory = memoryInfo.Values[4];
206 float usedMemory = Math.Max(totalMemory - freeMemory, 0);
207 memoryLoad.Value = 100f * usedMemory / totalMemory;
208 ActivateSensor(memoryLoad);
212 public override string GetReport() {
213 StringBuilder r = new StringBuilder();
215 r.AppendLine("Nvidia GPU");
218 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
219 r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
221 if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) {
222 NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion();
223 driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
224 if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value,
225 ref driverVersion) == NvStatus.OK) {
226 r.Append("Driver Version: ");
227 r.Append(driverVersion.DriverVersion / 100);
229 r.Append((driverVersion.DriverVersion % 100).ToString("00",
230 CultureInfo.InvariantCulture));
232 r.Append("Driver Branch: ");
233 r.AppendLine(driverVersion.BuildBranch);
238 if (NVAPI.NvAPI_GPU_GetPCIIdentifiers != null) {
239 uint deviceId, subSystemId, revisionId, extDeviceId;
241 NvStatus status = NVAPI.NvAPI_GPU_GetPCIIdentifiers(handle,
242 out deviceId, out subSystemId, out revisionId, out extDeviceId);
244 if (status == NvStatus.OK) {
245 r.Append("DeviceID: 0x");
246 r.AppendLine(deviceId.ToString("X", CultureInfo.InvariantCulture));
247 r.Append("SubSystemID: 0x");
248 r.AppendLine(subSystemId.ToString("X", CultureInfo.InvariantCulture));
249 r.Append("RevisionID: 0x");
250 r.AppendLine(revisionId.ToString("X", CultureInfo.InvariantCulture));
251 r.Append("ExtDeviceID: 0x");
252 r.AppendLine(extDeviceId.ToString("X", CultureInfo.InvariantCulture));
257 if (NVAPI.NvAPI_GPU_GetThermalSettings != null) {
258 NvGPUThermalSettings settings = new NvGPUThermalSettings();
259 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
260 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
261 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
263 NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
264 (int)NvThermalTarget.ALL, ref settings);
266 r.AppendLine("Thermal Settings");
268 if (status == NvStatus.OK) {
269 for (int i = 0; i < settings.Count; i++) {
270 r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i,
271 settings.Sensor[i].Controller, Environment.NewLine);
272 r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i,
273 settings.Sensor[i].DefaultMinTemp, Environment.NewLine);
274 r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i,
275 settings.Sensor[i].DefaultMaxTemp, Environment.NewLine);
276 r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i,
277 settings.Sensor[i].CurrentTemp, Environment.NewLine);
278 r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i,
279 settings.Sensor[i].Target, Environment.NewLine);
282 r.Append(" Status: ");
283 r.AppendLine(status.ToString());
288 if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
289 NvClocks allClocks = new NvClocks();
290 allClocks.Version = NVAPI.GPU_CLOCKS_VER;
291 allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
292 NvStatus status = NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks);
294 r.AppendLine("Clocks");
296 if (status == NvStatus.OK) {
297 for (int i = 0; i < allClocks.Clock.Length; i++)
298 if (allClocks.Clock[i] > 0) {
299 r.AppendFormat(" Clock[{0}]: {1}{2}", i, allClocks.Clock[i],
300 Environment.NewLine);
303 r.Append(" Status: ");
304 r.AppendLine(status.ToString());
309 if (NVAPI.NvAPI_GPU_GetTachReading != null) {
311 NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
313 r.AppendLine("Tachometer");
315 if (status == NvStatus.OK) {
316 r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
318 r.Append(" Status: ");
319 r.AppendLine(status.ToString());
324 if (NVAPI.NvAPI_GPU_GetPStates != null) {
325 NvPStates states = new NvPStates();
326 states.Version = NVAPI.GPU_PSTATES_VER;
327 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
328 NvStatus status = NVAPI.NvAPI_GPU_GetPStates(handle, ref states);
330 r.AppendLine("P-States");
332 if (status == NvStatus.OK) {
333 for (int i = 0; i < states.PStates.Length; i++)
334 if (states.PStates[i].Present)
335 r.AppendFormat(" Percentage[{0}]: {1}{2}", i,
336 states.PStates[i].Percentage, Environment.NewLine);
338 r.Append(" Status: ");
339 r.AppendLine(status.ToString());
344 if (NVAPI.NvAPI_GPU_GetUsages != null) {
345 NvUsages usages = new NvUsages();
346 usages.Version = NVAPI.GPU_USAGES_VER;
347 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
348 NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
350 r.AppendLine("Usages");
352 if (status == NvStatus.OK) {
353 for (int i = 0; i < usages.Usage.Length; i++)
354 if (usages.Usage[i] > 0)
355 r.AppendFormat(" Usage[{0}]: {1}{2}", i,
356 usages.Usage[i], Environment.NewLine);
358 r.Append(" Status: ");
359 r.AppendLine(status.ToString());
364 if (NVAPI.NvAPI_GPU_GetCoolerSettings != null) {
365 NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
366 settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
367 settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
369 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
371 r.AppendLine("Cooler Settings");
373 if (status == NvStatus.OK) {
374 for (int i = 0; i < settings.Count; i++) {
375 r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i,
376 settings.Cooler[i].Type, Environment.NewLine);
377 r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i,
378 settings.Cooler[i].Controller, Environment.NewLine);
379 r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i,
380 settings.Cooler[i].DefaultMin, Environment.NewLine);
381 r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i,
382 settings.Cooler[i].DefaultMax, Environment.NewLine);
383 r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i,
384 settings.Cooler[i].CurrentMin, Environment.NewLine);
385 r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i,
386 settings.Cooler[i].CurrentMax, Environment.NewLine);
387 r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i,
388 settings.Cooler[i].CurrentLevel, Environment.NewLine);
389 r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i,
390 settings.Cooler[i].DefaultPolicy, Environment.NewLine);
391 r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i,
392 settings.Cooler[i].CurrentPolicy, Environment.NewLine);
393 r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i,
394 settings.Cooler[i].Target, Environment.NewLine);
395 r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i,
396 settings.Cooler[i].ControlType, Environment.NewLine);
397 r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i,
398 settings.Cooler[i].Active, Environment.NewLine);
401 r.Append(" Status: ");
402 r.AppendLine(status.ToString());
407 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue) {
408 NvMemoryInfo memoryInfo = new NvMemoryInfo();
409 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
410 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
411 NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
414 r.AppendLine("Memory Info");
416 if (status == NvStatus.OK) {
417 for (int i = 0; i < memoryInfo.Values.Length; i++)
418 r.AppendFormat(" Value[{0}]: {1}{2}", i,
419 memoryInfo.Values[i], Environment.NewLine);
421 r.Append(" Status: ");
422 r.AppendLine(status.ToString());
430 private void SoftwareControlValueChanged(IControl control) {
431 NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
432 coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
433 coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
434 coolerLevels.Levels[0].Level = (int)control.SoftwareValue;
435 coolerLevels.Levels[0].Policy = 1;
436 NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
439 private void ControlModeChanged(IControl control) {
440 switch (control.ControlMode) {
441 case ControlMode.Undefined:
443 case ControlMode.Default:
444 SetDefaultFanSpeed();
446 case ControlMode.Software:
447 SoftwareControlValueChanged(control);
454 private void SetDefaultFanSpeed() {
455 NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
456 coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
457 coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
458 coolerLevels.Levels[0].Policy = 0x20;
459 NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
462 public override void Close() {
463 if (this.fanControl != null) {
464 this.fanControl.ControlModeChanged -= ControlModeChanged;
465 this.fanControl.SoftwareControlValueChanged -=
466 SoftwareControlValueChanged;
468 if (this.fanControl.ControlMode != ControlMode.Undefined)
469 SetDefaultFanSpeed();