Hardware/Nvidia/NvidiaGPU.cs
author moel.mich
Mon, 27 Sep 2010 23:48:41 +0000
changeset 200 50de2faf3336
parent 182 4801e9eaf979
child 275 35788ddd1825
permissions -rw-r--r--
Fixed a problem where the ADL Main_Memory_Alloc callback delegate could be garbage collected while still in use.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     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
     8  
     9   http://www.mozilla.org/MPL/
    10 
    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.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    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.
    21 
    22   Contributor(s):
    23 
    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.
    35  
    36 */
    37 
    38 using System;
    39 using System.Globalization;
    40 using System.Text;
    41 
    42 namespace OpenHardwareMonitor.Hardware.Nvidia {
    43   internal class NvidiaGPU : Hardware {
    44 
    45     private readonly string name;
    46     private readonly int adapterIndex;
    47     private readonly NvPhysicalGpuHandle handle;
    48     private readonly NvDisplayHandle? displayHandle;
    49 
    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 
    57     public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle, 
    58       NvDisplayHandle? displayHandle, ISettings settings) 
    59     {
    60       string gpuName;
    61       if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
    62         this.name = "NVIDIA " + gpuName.Trim();
    63       } else {
    64         this.name = "NVIDIA";
    65       }
    66       this.adapterIndex = adapterIndex;
    67       this.handle = handle;
    68       this.displayHandle = displayHandle;
    69 
    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];
    74         string name;
    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;
    82         }
    83         temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
    84           new ParameterDescription[0], settings);
    85         ActivateSensor(temperatures[i]);
    86       }
    87 
    88       int value;
    89       if (NVAPI.NvAPI_GPU_GetTachReading != null &&
    90         NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
    91         if (value > 0) {
    92           fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
    93           ActivateSensor(fan);
    94         }
    95       }
    96 
    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]);
   103 
   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);
   109 
   110       control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
   111     }
   112 
   113     public override string Name {
   114       get { return name; }
   115     }
   116 
   117     public override Identifier Identifier {
   118       get { 
   119         return new Identifier("nvidiagpu", 
   120           adapterIndex.ToString(CultureInfo.InvariantCulture)); 
   121       }
   122     }
   123 
   124     public override HardwareType HardwareType {
   125       get { return HardwareType.GpuNvidia; }
   126     }
   127 
   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) {
   136         settings.Count = 0;        
   137       }
   138       return settings;
   139     }
   140 
   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;
   148       }
   149       return null;
   150     }
   151 
   152     public override void Update() {
   153       NvGPUThermalSettings settings = GetThermalSettings();
   154       foreach (Sensor sensor in temperatures) 
   155         sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
   156 
   157       if (fan != null) {
   158         int value = 0;
   159         NVAPI.NvAPI_GPU_GetTachReading(handle, out value);
   160         fan.Value = value;
   161       }
   162 
   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];
   171         }
   172       }
   173 
   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]);
   183           }
   184       } else {
   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]);
   195         }
   196       }
   197 
   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);
   206       }
   207 
   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) == 
   213         NvStatus.OK) 
   214       {
   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);
   220       }
   221     }
   222 
   223     public override string GetReport() {
   224       StringBuilder r = new StringBuilder();
   225 
   226       r.AppendLine("Nvidia GPU");
   227       r.AppendLine();
   228 
   229       r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
   230       r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
   231       
   232       if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) 
   233       {
   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);
   240           r.Append(".");
   241           r.Append((driverVersion.DriverVersion % 100).ToString("00", 
   242             CultureInfo.InvariantCulture));
   243           r.AppendLine();
   244           r.Append("Driver Branch: ");
   245           r.AppendLine(driverVersion.BuildBranch);
   246         }
   247       }
   248       r.AppendLine();
   249 
   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];
   255 
   256         NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
   257           (int)NvThermalTarget.ALL, ref settings);
   258 
   259         r.AppendLine("Thermal Settings");
   260         r.AppendLine();
   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);
   273           }
   274         } else {
   275           r.Append(" Status: ");
   276           r.AppendLine(status.ToString());
   277         }
   278         r.AppendLine();
   279       }      
   280 
   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);
   286 
   287         r.AppendLine("Clocks");
   288         r.AppendLine();
   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);
   294             }
   295         } else {
   296           r.Append(" Status: ");
   297           r.AppendLine(status.ToString());
   298         }
   299         r.AppendLine();
   300       }         
   301            
   302       if (NVAPI.NvAPI_GPU_GetTachReading != null) {
   303         int tachValue; 
   304         NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
   305 
   306         r.AppendLine("Tachometer");
   307         r.AppendLine();
   308         if (status == NvStatus.OK) {
   309           r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
   310         } else {
   311           r.Append(" Status: ");
   312           r.AppendLine(status.ToString());
   313         }
   314         r.AppendLine();
   315       }
   316 
   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);
   322 
   323         r.AppendLine("P-States");
   324         r.AppendLine();
   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);
   330         } else {
   331           r.Append(" Status: ");
   332           r.AppendLine(status.ToString());
   333         }
   334         r.AppendLine();
   335       }
   336 
   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);
   342      
   343         r.AppendLine("Usages");
   344         r.AppendLine();
   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);
   350         } else {
   351           r.Append(" Status: ");
   352           r.AppendLine(status.ToString());
   353         }
   354         r.AppendLine();
   355       }
   356 
   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];
   361         NvStatus status =
   362           NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
   363 
   364         r.AppendLine("Cooler Settings");
   365         r.AppendLine();
   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);
   392           }
   393         } else {
   394           r.Append(" Status: ");
   395           r.AppendLine(status.ToString());
   396         }
   397         r.AppendLine();
   398       }
   399 
   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, 
   405           ref memoryInfo);
   406 
   407         r.AppendLine("Memory Info");
   408         r.AppendLine();
   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);
   413         } else {
   414           r.Append(" Status: ");
   415           r.AppendLine(status.ToString());
   416         }
   417         r.AppendLine();
   418       }
   419 
   420       return r.ToString();
   421     }
   422   }
   423 }