Hardware/Nvidia/NvidiaGPU.cs
author moel.mich
Wed, 27 Jul 2011 18:27:16 +0000
changeset 317 1ccf99e620a9
parent 275 35788ddd1825
child 334 013e148e8f12
permissions -rw-r--r--
Added support for Intel CPU power sensors (package and cores).
     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-2011
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23   Christian Vallières
    24 
    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.
    36  
    37 */
    38 
    39 using System;
    40 using System.Globalization;
    41 using System.Text;
    42 
    43 namespace OpenHardwareMonitor.Hardware.Nvidia {
    44   internal class NvidiaGPU : Hardware {
    45 
    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     private readonly Control fanControl;
    57 
    58     private bool restoreDefaultFanSpeedRequired;
    59     private NvLevel initialFanSpeedValue;
    60 
    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;
    66       this.handle = handle;
    67       this.displayHandle = displayHandle;
    68 
    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];
    73         string name;
    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;
    81         }
    82         temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
    83           new ParameterDescription[0], settings);
    84         ActivateSensor(temperatures[i]);
    85       }
    86 
    87       int value;
    88       if (NVAPI.NvAPI_GPU_GetTachReading != null &&
    89         NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
    90         if (value > 0) {
    91           fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
    92           ActivateSensor(fan);
    93         }
    94       }
    95 
    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]);
   102 
   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);
   108 
   109       control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
   110 
   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;
   120       }
   121       Update();
   122     }
   123 
   124     private static string GetName(NvPhysicalGpuHandle handle) {
   125       string gpuName;
   126       if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
   127         return "NVIDIA " + gpuName.Trim();
   128       } else {
   129         return "NVIDIA";
   130       }
   131     }
   132 
   133     public override HardwareType HardwareType {
   134       get { return HardwareType.GpuNvidia; }
   135     }
   136 
   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)) 
   145       {
   146         settings.Count = 0;
   147       }       
   148       return settings;    
   149     }
   150 
   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)) 
   158       {
   159         settings.Count = 0;
   160       }
   161       return settings;  
   162     }
   163 
   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;
   171       }
   172       return null;
   173     }
   174 
   175     public override void Update() {
   176       NvGPUThermalSettings settings = GetThermalSettings();
   177       foreach (Sensor sensor in temperatures)
   178         sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
   179 
   180       if (fan != null) {
   181         int value = 0;
   182         NVAPI.NvAPI_GPU_GetTachReading(handle, out value);
   183         fan.Value = value;
   184       }
   185 
   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];
   194         }
   195       }
   196 
   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]);
   206           }
   207       } else {
   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]);
   218         }
   219       }
   220 
   221 
   222       NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
   223       if (coolerSettings.Count > 0) {
   224         control.Value = coolerSettings.Cooler[0].CurrentLevel;
   225         ActivateSensor(control);
   226       }
   227 
   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) ==
   233         NvStatus.OK) {
   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);
   239       }
   240     }
   241 
   242     public override string GetReport() {
   243       StringBuilder r = new StringBuilder();
   244 
   245       r.AppendLine("Nvidia GPU");
   246       r.AppendLine();
   247 
   248       r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
   249       r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
   250 
   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);
   258           r.Append(".");
   259           r.Append((driverVersion.DriverVersion % 100).ToString("00",
   260             CultureInfo.InvariantCulture));
   261           r.AppendLine();
   262           r.Append("Driver Branch: ");
   263           r.AppendLine(driverVersion.BuildBranch);
   264         }
   265       }
   266       r.AppendLine();
   267 
   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];
   273 
   274         NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
   275           (int)NvThermalTarget.ALL, ref settings);
   276 
   277         r.AppendLine("Thermal Settings");
   278         r.AppendLine();
   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);
   291           }
   292         } else {
   293           r.Append(" Status: ");
   294           r.AppendLine(status.ToString());
   295         }
   296         r.AppendLine();
   297       }
   298 
   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);
   304 
   305         r.AppendLine("Clocks");
   306         r.AppendLine();
   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);
   312             }
   313         } else {
   314           r.Append(" Status: ");
   315           r.AppendLine(status.ToString());
   316         }
   317         r.AppendLine();
   318       }
   319 
   320       if (NVAPI.NvAPI_GPU_GetTachReading != null) {
   321         int tachValue;
   322         NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
   323 
   324         r.AppendLine("Tachometer");
   325         r.AppendLine();
   326         if (status == NvStatus.OK) {
   327           r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
   328         } else {
   329           r.Append(" Status: ");
   330           r.AppendLine(status.ToString());
   331         }
   332         r.AppendLine();
   333       }
   334 
   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);
   340 
   341         r.AppendLine("P-States");
   342         r.AppendLine();
   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);
   348         } else {
   349           r.Append(" Status: ");
   350           r.AppendLine(status.ToString());
   351         }
   352         r.AppendLine();
   353       }
   354 
   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);
   360 
   361         r.AppendLine("Usages");
   362         r.AppendLine();
   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);
   368         } else {
   369           r.Append(" Status: ");
   370           r.AppendLine(status.ToString());
   371         }
   372         r.AppendLine();
   373       }
   374 
   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];
   379         NvStatus status =
   380           NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
   381 
   382         r.AppendLine("Cooler Settings");
   383         r.AppendLine();
   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);
   410           }
   411         } else {
   412           r.Append(" Status: ");
   413           r.AppendLine(status.ToString());
   414         }
   415         r.AppendLine();
   416       }
   417 
   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,
   423           ref memoryInfo);
   424 
   425         r.AppendLine("Memory Info");
   426         r.AppendLine();
   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);
   431         } else {
   432           r.Append(" Status: ");
   433           r.AppendLine(status.ToString());
   434         }
   435         r.AppendLine();
   436       }
   437 
   438       return r.ToString();
   439     }
   440 
   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);
   449     }
   450 
   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;
   458         }
   459       }
   460     }
   461 
   462     private void ControlModeChanged(IControl control) {
   463       if (control.ControlMode == ControlMode.Default) {
   464         RestoreDefaultFanSpeed();
   465       } else {
   466         SoftwareControlValueChanged(control);
   467       }
   468     }
   469 
   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;
   478       }
   479     }
   480   }
   481 }