Small corrections for AMD family 15h CPUs (based on documentation).
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-2011
20 the Initial Developer. All Rights Reserved.
25 Alternatively, the contents of this file may be used under the terms of
26 either the GNU General Public License Version 2 or later (the "GPL"), or
27 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 in which case the provisions of the GPL or the LGPL are applicable instead
29 of those above. If you wish to allow use of your version of this file only
30 under the terms of either the GPL or the LGPL, and not to allow others to
31 use your version of this file under the terms of the MPL, indicate your
32 decision by deleting the provisions above and replace them with the notice
33 and other provisions required by the GPL or the LGPL. If you do not delete
34 the provisions above, a recipient may use your version of this file under
35 the terms of any one of the MPL, the GPL or the LGPL.
40 using System.Globalization;
43 namespace OpenHardwareMonitor.Hardware.Nvidia {
44 internal class NvidiaGPU : Hardware {
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;
56 private readonly Control fanControl;
58 private bool restoreDefaultFanSpeedRequired;
59 private NvLevel initialFanSpeedValue;
61 public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
62 NvDisplayHandle? displayHandle, ISettings settings)
63 : base(GetName(handle), new Identifier("nvidiagpu",
64 adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) {
65 this.adapterIndex = adapterIndex;
67 this.displayHandle = displayHandle;
69 NvGPUThermalSettings thermalSettings = GetThermalSettings();
70 temperatures = new Sensor[thermalSettings.Count];
71 for (int i = 0; i < temperatures.Length; i++) {
72 NvSensor sensor = thermalSettings.Sensor[i];
74 switch (sensor.Target) {
75 case NvThermalTarget.BOARD: name = "GPU Board"; break;
76 case NvThermalTarget.GPU: name = "GPU Core"; break;
77 case NvThermalTarget.MEMORY: name = "GPU Memory"; break;
78 case NvThermalTarget.POWER_SUPPLY: name = "GPU Power Supply"; break;
79 case NvThermalTarget.UNKNOWN: name = "GPU Unknown"; break;
80 default: name = "GPU"; break;
82 temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
83 new ParameterDescription[0], settings);
84 ActivateSensor(temperatures[i]);
88 if (NVAPI.NvAPI_GPU_GetTachReading != null &&
89 NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
91 fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
96 clocks = new Sensor[3];
97 clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings);
98 clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings);
99 clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this, settings);
100 for (int i = 0; i < clocks.Length; i++)
101 ActivateSensor(clocks[i]);
103 loads = new Sensor[3];
104 loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings);
105 loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings);
106 loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings);
107 memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
109 control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
111 NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
112 if (coolerSettings.Count > 0) {
113 fanControl = new Control(control, settings,
114 coolerSettings.Cooler[0].DefaultMin,
115 coolerSettings.Cooler[0].DefaultMax);
116 fanControl.ControlModeChanged += ControlModeChanged;
117 fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged;
118 ControlModeChanged(fanControl);
119 control.Control = fanControl;
124 private static string GetName(NvPhysicalGpuHandle handle) {
126 if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
127 return "NVIDIA " + gpuName.Trim();
133 public override HardwareType HardwareType {
134 get { return HardwareType.GpuNvidia; }
137 private NvGPUThermalSettings GetThermalSettings() {
138 NvGPUThermalSettings settings = new NvGPUThermalSettings();
139 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
140 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
141 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
142 if (!(NVAPI.NvAPI_GPU_GetThermalSettings != null &&
143 NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
144 ref settings) == NvStatus.OK))
151 private NvGPUCoolerSettings GetCoolerSettings() {
152 NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
153 settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
154 settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
155 if (!(NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
156 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0,
157 ref settings) == NvStatus.OK))
164 private uint[] GetClocks() {
165 NvClocks allClocks = new NvClocks();
166 allClocks.Version = NVAPI.GPU_CLOCKS_VER;
167 allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
168 if (NVAPI.NvAPI_GPU_GetAllClocks != null &&
169 NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks) == NvStatus.OK) {
170 return allClocks.Clock;
175 public override void Update() {
176 NvGPUThermalSettings settings = GetThermalSettings();
177 foreach (Sensor sensor in temperatures)
178 sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
182 NVAPI.NvAPI_GPU_GetTachReading(handle, out value);
186 uint[] values = GetClocks();
187 if (values != null) {
188 clocks[0].Value = 0.001f * values[0];
189 clocks[1].Value = 0.001f * values[8];
190 clocks[2].Value = 0.001f * values[14];
191 if (values[30] != 0) {
192 clocks[0].Value = 0.0005f * values[30];
193 clocks[2].Value = 0.001f * values[30];
197 NvPStates states = new NvPStates();
198 states.Version = NVAPI.GPU_PSTATES_VER;
199 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
200 if (NVAPI.NvAPI_GPU_GetPStates != null &&
201 NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) {
202 for (int i = 0; i < 3; i++)
203 if (states.PStates[i].Present) {
204 loads[i].Value = states.PStates[i].Percentage;
205 ActivateSensor(loads[i]);
208 NvUsages usages = new NvUsages();
209 usages.Version = NVAPI.GPU_USAGES_VER;
210 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
211 if (NVAPI.NvAPI_GPU_GetUsages != null &&
212 NVAPI.NvAPI_GPU_GetUsages(handle, ref usages) == NvStatus.OK) {
213 loads[0].Value = usages.Usage[2];
214 loads[1].Value = usages.Usage[6];
215 loads[2].Value = usages.Usage[10];
216 for (int i = 0; i < 3; i++)
217 ActivateSensor(loads[i]);
222 NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
223 if (coolerSettings.Count > 0) {
224 control.Value = coolerSettings.Cooler[0].CurrentLevel;
225 ActivateSensor(control);
228 NvMemoryInfo memoryInfo = new NvMemoryInfo();
229 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
230 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
231 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue &&
232 NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) ==
234 uint totalMemory = memoryInfo.Values[0];
235 uint freeMemory = memoryInfo.Values[4];
236 float usedMemory = Math.Max(totalMemory - freeMemory, 0);
237 memoryLoad.Value = 100f * usedMemory / totalMemory;
238 ActivateSensor(memoryLoad);
242 public override string GetReport() {
243 StringBuilder r = new StringBuilder();
245 r.AppendLine("Nvidia GPU");
248 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
249 r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
251 if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) {
252 NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion();
253 driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
254 if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value,
255 ref driverVersion) == NvStatus.OK) {
256 r.Append("Driver Version: ");
257 r.Append(driverVersion.DriverVersion / 100);
259 r.Append((driverVersion.DriverVersion % 100).ToString("00",
260 CultureInfo.InvariantCulture));
262 r.Append("Driver Branch: ");
263 r.AppendLine(driverVersion.BuildBranch);
268 if (NVAPI.NvAPI_GPU_GetThermalSettings != null) {
269 NvGPUThermalSettings settings = new NvGPUThermalSettings();
270 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
271 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
272 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
274 NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
275 (int)NvThermalTarget.ALL, ref settings);
277 r.AppendLine("Thermal Settings");
279 if (status == NvStatus.OK) {
280 for (int i = 0; i < settings.Count; i++) {
281 r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i,
282 settings.Sensor[i].Controller, Environment.NewLine);
283 r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i,
284 settings.Sensor[i].DefaultMinTemp, Environment.NewLine);
285 r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i,
286 settings.Sensor[i].DefaultMaxTemp, Environment.NewLine);
287 r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i,
288 settings.Sensor[i].CurrentTemp, Environment.NewLine);
289 r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i,
290 settings.Sensor[i].Target, Environment.NewLine);
293 r.Append(" Status: ");
294 r.AppendLine(status.ToString());
299 if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
300 NvClocks allClocks = new NvClocks();
301 allClocks.Version = NVAPI.GPU_CLOCKS_VER;
302 allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
303 NvStatus status = NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks);
305 r.AppendLine("Clocks");
307 if (status == NvStatus.OK) {
308 for (int i = 0; i < allClocks.Clock.Length; i++)
309 if (allClocks.Clock[i] > 0) {
310 r.AppendFormat(" Clock[{0}]: {1}{2}", i, allClocks.Clock[i],
311 Environment.NewLine);
314 r.Append(" Status: ");
315 r.AppendLine(status.ToString());
320 if (NVAPI.NvAPI_GPU_GetTachReading != null) {
322 NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
324 r.AppendLine("Tachometer");
326 if (status == NvStatus.OK) {
327 r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
329 r.Append(" Status: ");
330 r.AppendLine(status.ToString());
335 if (NVAPI.NvAPI_GPU_GetPStates != null) {
336 NvPStates states = new NvPStates();
337 states.Version = NVAPI.GPU_PSTATES_VER;
338 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
339 NvStatus status = NVAPI.NvAPI_GPU_GetPStates(handle, ref states);
341 r.AppendLine("P-States");
343 if (status == NvStatus.OK) {
344 for (int i = 0; i < states.PStates.Length; i++)
345 if (states.PStates[i].Present)
346 r.AppendFormat(" Percentage[{0}]: {1}{2}", i,
347 states.PStates[i].Percentage, Environment.NewLine);
349 r.Append(" Status: ");
350 r.AppendLine(status.ToString());
355 if (NVAPI.NvAPI_GPU_GetUsages != null) {
356 NvUsages usages = new NvUsages();
357 usages.Version = NVAPI.GPU_USAGES_VER;
358 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
359 NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
361 r.AppendLine("Usages");
363 if (status == NvStatus.OK) {
364 for (int i = 0; i < usages.Usage.Length; i++)
365 if (usages.Usage[i] > 0)
366 r.AppendFormat(" Usage[{0}]: {1}{2}", i,
367 usages.Usage[i], Environment.NewLine);
369 r.Append(" Status: ");
370 r.AppendLine(status.ToString());
375 if (NVAPI.NvAPI_GPU_GetCoolerSettings != null) {
376 NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
377 settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
378 settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
380 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
382 r.AppendLine("Cooler Settings");
384 if (status == NvStatus.OK) {
385 for (int i = 0; i < settings.Count; i++) {
386 r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i,
387 settings.Cooler[i].Type, Environment.NewLine);
388 r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i,
389 settings.Cooler[i].Controller, Environment.NewLine);
390 r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i,
391 settings.Cooler[i].DefaultMin, Environment.NewLine);
392 r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i,
393 settings.Cooler[i].DefaultMax, Environment.NewLine);
394 r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i,
395 settings.Cooler[i].CurrentMin, Environment.NewLine);
396 r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i,
397 settings.Cooler[i].CurrentMax, Environment.NewLine);
398 r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i,
399 settings.Cooler[i].CurrentLevel, Environment.NewLine);
400 r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i,
401 settings.Cooler[i].DefaultPolicy, Environment.NewLine);
402 r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i,
403 settings.Cooler[i].CurrentPolicy, Environment.NewLine);
404 r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i,
405 settings.Cooler[i].Target, Environment.NewLine);
406 r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i,
407 settings.Cooler[i].ControlType, Environment.NewLine);
408 r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i,
409 settings.Cooler[i].Active, Environment.NewLine);
412 r.Append(" Status: ");
413 r.AppendLine(status.ToString());
418 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue) {
419 NvMemoryInfo memoryInfo = new NvMemoryInfo();
420 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
421 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
422 NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
425 r.AppendLine("Memory Info");
427 if (status == NvStatus.OK) {
428 for (int i = 0; i < memoryInfo.Values.Length; i++)
429 r.AppendFormat(" Value[{0}]: {1}{2}", i,
430 memoryInfo.Values[i], Environment.NewLine);
432 r.Append(" Status: ");
433 r.AppendLine(status.ToString());
441 private void SoftwareControlValueChanged(IControl control) {
442 SaveDefaultFanSpeed();
443 NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
444 coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
445 coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
446 coolerLevels.Levels[0].Level = (int)control.SoftwareValue;
447 coolerLevels.Levels[0].Policy = 1;
448 NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
451 private void SaveDefaultFanSpeed() {
452 if (!restoreDefaultFanSpeedRequired) {
453 NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
454 if (coolerSettings.Count > 0) {
455 restoreDefaultFanSpeedRequired = true;
456 initialFanSpeedValue.Level = coolerSettings.Cooler[0].CurrentLevel;
457 initialFanSpeedValue.Policy = coolerSettings.Cooler[0].CurrentPolicy;
462 private void ControlModeChanged(IControl control) {
463 if (control.ControlMode == ControlMode.Default) {
464 RestoreDefaultFanSpeed();
466 SoftwareControlValueChanged(control);
470 private void RestoreDefaultFanSpeed() {
471 if (restoreDefaultFanSpeedRequired) {
472 NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
473 coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
474 coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
475 coolerLevels.Levels[0] = initialFanSpeedValue;
476 NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
477 restoreDefaultFanSpeedRequired = false;