Fixed Issue 218.
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.
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 int adapterIndex;
46 private readonly NvPhysicalGpuHandle handle;
47 private readonly NvDisplayHandle? displayHandle;
49 private readonly Sensor[] temperatures;
50 private readonly Sensor fan;
51 private readonly Sensor[] clocks;
52 private readonly Sensor[] loads;
53 private readonly Sensor control;
54 private readonly Sensor memoryLoad;
56 public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
57 NvDisplayHandle? displayHandle, ISettings settings)
58 : base(GetName(handle), new Identifier("nvidiagpu",
59 adapterIndex.ToString(CultureInfo.InvariantCulture)), settings)
61 this.adapterIndex = adapterIndex;
63 this.displayHandle = displayHandle;
65 NvGPUThermalSettings thermalSettings = GetThermalSettings();
66 temperatures = new Sensor[thermalSettings.Count];
67 for (int i = 0; i < temperatures.Length; i++) {
68 NvSensor sensor = thermalSettings.Sensor[i];
70 switch (sensor.Target) {
71 case NvThermalTarget.BOARD: name = "GPU Board"; break;
72 case NvThermalTarget.GPU: name = "GPU Core"; break;
73 case NvThermalTarget.MEMORY: name = "GPU Memory"; break;
74 case NvThermalTarget.POWER_SUPPLY: name = "GPU Power Supply"; break;
75 case NvThermalTarget.UNKNOWN: name = "GPU Unknown"; break;
76 default: name = "GPU"; break;
78 temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
79 new ParameterDescription[0], settings);
80 ActivateSensor(temperatures[i]);
84 if (NVAPI.NvAPI_GPU_GetTachReading != null &&
85 NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
87 fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
92 clocks = new Sensor[3];
93 clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings);
94 clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings);
95 clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this, settings);
96 for (int i = 0; i < clocks.Length; i++)
97 ActivateSensor(clocks[i]);
99 loads = new Sensor[3];
100 loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings);
101 loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings);
102 loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings);
103 memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
105 control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
108 private static string GetName(NvPhysicalGpuHandle handle) {
110 if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
111 return "NVIDIA " + gpuName.Trim();
117 public override HardwareType HardwareType {
118 get { return HardwareType.GpuNvidia; }
121 private NvGPUThermalSettings GetThermalSettings() {
122 NvGPUThermalSettings settings = new NvGPUThermalSettings();
123 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
124 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
125 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
126 if (NVAPI.NvAPI_GPU_GetThermalSettings != null &&
127 NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
128 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]);
191 NvGPUCoolerSettings coolerSettings = new NvGPUCoolerSettings();
192 coolerSettings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
193 coolerSettings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
194 if (NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
195 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref coolerSettings) ==
196 NvStatus.OK && coolerSettings.Count > 0) {
197 control.Value = coolerSettings.Cooler[0].CurrentLevel;
198 ActivateSensor(control);
201 NvMemoryInfo memoryInfo = new NvMemoryInfo();
202 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
203 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
204 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue &&
205 NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) ==
208 uint totalMemory = memoryInfo.Values[0];
209 uint freeMemory = memoryInfo.Values[4];
210 float usedMemory = Math.Max(totalMemory - freeMemory, 0);
211 memoryLoad.Value = 100f * usedMemory / totalMemory;
212 ActivateSensor(memoryLoad);
216 public override string GetReport() {
217 StringBuilder r = new StringBuilder();
219 r.AppendLine("Nvidia GPU");
222 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
223 r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
225 if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null)
227 NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion();
228 driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
229 if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value,
230 ref driverVersion) == NvStatus.OK) {
231 r.Append("Driver Version: ");
232 r.Append(driverVersion.DriverVersion / 100);
234 r.Append((driverVersion.DriverVersion % 100).ToString("00",
235 CultureInfo.InvariantCulture));
237 r.Append("Driver Branch: ");
238 r.AppendLine(driverVersion.BuildBranch);
243 if (NVAPI.NvAPI_GPU_GetThermalSettings != null) {
244 NvGPUThermalSettings settings = new NvGPUThermalSettings();
245 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
246 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
247 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
249 NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
250 (int)NvThermalTarget.ALL, ref settings);
252 r.AppendLine("Thermal Settings");
254 if (status == NvStatus.OK) {
255 for (int i = 0; i < settings.Count; i++) {
256 r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i,
257 settings.Sensor[i].Controller, Environment.NewLine);
258 r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i,
259 settings.Sensor[i].DefaultMinTemp, Environment.NewLine);
260 r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i,
261 settings.Sensor[i].DefaultMaxTemp, Environment.NewLine);
262 r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i,
263 settings.Sensor[i].CurrentTemp, Environment.NewLine);
264 r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i,
265 settings.Sensor[i].Target, Environment.NewLine);
268 r.Append(" Status: ");
269 r.AppendLine(status.ToString());
274 if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
275 NvClocks allClocks = new NvClocks();
276 allClocks.Version = NVAPI.GPU_CLOCKS_VER;
277 allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
278 NvStatus status = NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks);
280 r.AppendLine("Clocks");
282 if (status == NvStatus.OK) {
283 for (int i = 0; i < allClocks.Clock.Length; i++)
284 if (allClocks.Clock[i] > 0) {
285 r.AppendFormat(" Clock[{0}]: {1}{2}", i, allClocks.Clock[i],
286 Environment.NewLine);
289 r.Append(" Status: ");
290 r.AppendLine(status.ToString());
295 if (NVAPI.NvAPI_GPU_GetTachReading != null) {
297 NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
299 r.AppendLine("Tachometer");
301 if (status == NvStatus.OK) {
302 r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
304 r.Append(" Status: ");
305 r.AppendLine(status.ToString());
310 if (NVAPI.NvAPI_GPU_GetPStates != null) {
311 NvPStates states = new NvPStates();
312 states.Version = NVAPI.GPU_PSTATES_VER;
313 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
314 NvStatus status = NVAPI.NvAPI_GPU_GetPStates(handle, ref states);
316 r.AppendLine("P-States");
318 if (status == NvStatus.OK) {
319 for (int i = 0; i < states.PStates.Length; i++)
320 if (states.PStates[i].Present)
321 r.AppendFormat(" Percentage[{0}]: {1}{2}", i,
322 states.PStates[i].Percentage, Environment.NewLine);
324 r.Append(" Status: ");
325 r.AppendLine(status.ToString());
330 if (NVAPI.NvAPI_GPU_GetUsages != null) {
331 NvUsages usages = new NvUsages();
332 usages.Version = NVAPI.GPU_USAGES_VER;
333 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
334 NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
336 r.AppendLine("Usages");
338 if (status == NvStatus.OK) {
339 for (int i = 0; i < usages.Usage.Length; i++)
340 if (usages.Usage[i] > 0)
341 r.AppendFormat(" Usage[{0}]: {1}{2}", i,
342 usages.Usage[i], Environment.NewLine);
344 r.Append(" Status: ");
345 r.AppendLine(status.ToString());
350 if (NVAPI.NvAPI_GPU_GetCoolerSettings != null) {
351 NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
352 settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
353 settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
355 NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
357 r.AppendLine("Cooler Settings");
359 if (status == NvStatus.OK) {
360 for (int i = 0; i < settings.Count; i++) {
361 r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i,
362 settings.Cooler[i].Type, Environment.NewLine);
363 r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i,
364 settings.Cooler[i].Controller, Environment.NewLine);
365 r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i,
366 settings.Cooler[i].DefaultMin, Environment.NewLine);
367 r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i,
368 settings.Cooler[i].DefaultMax, Environment.NewLine);
369 r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i,
370 settings.Cooler[i].CurrentMin, Environment.NewLine);
371 r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i,
372 settings.Cooler[i].CurrentMax, Environment.NewLine);
373 r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i,
374 settings.Cooler[i].CurrentLevel, Environment.NewLine);
375 r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i,
376 settings.Cooler[i].DefaultPolicy, Environment.NewLine);
377 r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i,
378 settings.Cooler[i].CurrentPolicy, Environment.NewLine);
379 r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i,
380 settings.Cooler[i].Target, Environment.NewLine);
381 r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i,
382 settings.Cooler[i].ControlType, Environment.NewLine);
383 r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i,
384 settings.Cooler[i].Active, Environment.NewLine);
387 r.Append(" Status: ");
388 r.AppendLine(status.ToString());
393 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue) {
394 NvMemoryInfo memoryInfo = new NvMemoryInfo();
395 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
396 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
397 NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
400 r.AppendLine("Memory Info");
402 if (status == NvStatus.OK) {
403 for (int i = 0; i < memoryInfo.Values.Length; i++)
404 r.AppendFormat(" Value[{0}]: {1}{2}", i,
405 memoryInfo.Values[i], Environment.NewLine);
407 r.Append(" Status: ");
408 r.AppendLine(status.ToString());