Hardware/Nvidia/NvidiaGPU.cs
author Stephane Lenclud
Sat, 30 Jan 2016 23:01:51 +0100
branchMiniDisplay
changeset 454 f84878f52cd9
parent 428 3c1cdc197b24
permissions -rw-r--r--
Disabling Nuvoton NCT6791D because of fan full speed bug on Asus Z97 WS.
     1 /*
     2  
     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/.
     6  
     7   Copyright (C) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	Copyright (C) 2011 Christian Vallières
     9  
    10 */
    11 
    12 using System;
    13 using System.Globalization;
    14 using System.Text;
    15 
    16 namespace OpenHardwareMonitor.Hardware.Nvidia {
    17   internal class NvidiaGPU : Hardware {
    18 
    19     private readonly int adapterIndex;
    20     private readonly NvPhysicalGpuHandle handle;
    21     private readonly NvDisplayHandle? displayHandle;
    22 
    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;
    30 
    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;
    36       this.handle = handle;
    37       this.displayHandle = displayHandle;
    38 
    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];
    43         string name;
    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;
    51         }
    52         temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
    53           new ParameterDescription[0], settings);
    54         ActivateSensor(temperatures[i]);
    55       }
    56 
    57       int value;
    58       if (NVAPI.NvAPI_GPU_GetTachReading != null &&
    59         NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
    60         if (value >= 0) {
    61           fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
    62           ActivateSensor(fan);
    63         }
    64       }
    65 
    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]);
    72 
    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);
    78 
    79       control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
    80 
    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;
    90       }
    91       Update();
    92     }
    93 
    94     private static string GetName(NvPhysicalGpuHandle handle) {
    95       string gpuName;
    96       if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
    97         return "NVIDIA " + gpuName.Trim();
    98       } else {
    99         return "NVIDIA";
   100       }
   101     }
   102 
   103     public override HardwareType HardwareType {
   104       get { return HardwareType.GpuNvidia; }
   105     }
   106 
   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)) 
   115       {
   116         settings.Count = 0;
   117       }       
   118       return settings;    
   119     }
   120 
   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)) 
   128       {
   129         settings.Count = 0;
   130       }
   131       return settings;  
   132     }
   133 
   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;
   141       }
   142       return null;
   143     }
   144 
   145     public override void Update() {
   146       NvGPUThermalSettings settings = GetThermalSettings();
   147       foreach (Sensor sensor in temperatures)
   148         sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
   149 
   150       if (fan != null) {
   151         int value = 0;
   152         NVAPI.NvAPI_GPU_GetTachReading(handle, out value);
   153         fan.Value = value;
   154       }
   155 
   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];
   164         }
   165       }
   166 
   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]);
   176           }
   177       } else {
   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]);
   188         }
   189       }
   190 
   191 
   192       NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
   193       if (coolerSettings.Count > 0) {
   194         control.Value = coolerSettings.Cooler[0].CurrentLevel;
   195         ActivateSensor(control);
   196       }
   197 
   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) ==
   203         NvStatus.OK) {
   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);
   209       }
   210     }
   211 
   212     public override string GetReport() {
   213       StringBuilder r = new StringBuilder();
   214 
   215       r.AppendLine("Nvidia GPU");
   216       r.AppendLine();
   217 
   218       r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
   219       r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
   220 
   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);
   228           r.Append(".");
   229           r.Append((driverVersion.DriverVersion % 100).ToString("00",
   230             CultureInfo.InvariantCulture));
   231           r.AppendLine();
   232           r.Append("Driver Branch: ");
   233           r.AppendLine(driverVersion.BuildBranch);
   234         }
   235       }
   236       r.AppendLine();
   237 
   238       if (NVAPI.NvAPI_GPU_GetPCIIdentifiers != null) {
   239         uint deviceId, subSystemId, revisionId, extDeviceId;
   240 
   241         NvStatus status = NVAPI.NvAPI_GPU_GetPCIIdentifiers(handle, 
   242           out deviceId, out subSystemId, out revisionId, out extDeviceId);
   243 
   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));
   253           r.AppendLine();
   254         }
   255       }
   256 
   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];
   262 
   263         NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
   264           (int)NvThermalTarget.ALL, ref settings);
   265 
   266         r.AppendLine("Thermal Settings");
   267         r.AppendLine();
   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);
   280           }
   281         } else {
   282           r.Append(" Status: ");
   283           r.AppendLine(status.ToString());
   284         }
   285         r.AppendLine();
   286       }
   287 
   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);
   293 
   294         r.AppendLine("Clocks");
   295         r.AppendLine();
   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);
   301             }
   302         } else {
   303           r.Append(" Status: ");
   304           r.AppendLine(status.ToString());
   305         }
   306         r.AppendLine();
   307       }
   308 
   309       if (NVAPI.NvAPI_GPU_GetTachReading != null) {
   310         int tachValue;
   311         NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
   312 
   313         r.AppendLine("Tachometer");
   314         r.AppendLine();
   315         if (status == NvStatus.OK) {
   316           r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
   317         } else {
   318           r.Append(" Status: ");
   319           r.AppendLine(status.ToString());
   320         }
   321         r.AppendLine();
   322       }
   323 
   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);
   329 
   330         r.AppendLine("P-States");
   331         r.AppendLine();
   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);
   337         } else {
   338           r.Append(" Status: ");
   339           r.AppendLine(status.ToString());
   340         }
   341         r.AppendLine();
   342       }
   343 
   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);
   349 
   350         r.AppendLine("Usages");
   351         r.AppendLine();
   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);
   357         } else {
   358           r.Append(" Status: ");
   359           r.AppendLine(status.ToString());
   360         }
   361         r.AppendLine();
   362       }
   363 
   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];
   368         NvStatus status =
   369           NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
   370 
   371         r.AppendLine("Cooler Settings");
   372         r.AppendLine();
   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);
   399           }
   400         } else {
   401           r.Append(" Status: ");
   402           r.AppendLine(status.ToString());
   403         }
   404         r.AppendLine();
   405       }
   406 
   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,
   412           ref memoryInfo);
   413 
   414         r.AppendLine("Memory Info");
   415         r.AppendLine();
   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);
   420         } else {
   421           r.Append(" Status: ");
   422           r.AppendLine(status.ToString());
   423         }
   424         r.AppendLine();
   425       }
   426 
   427       return r.ToString();
   428     }
   429 
   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);
   437     }
   438 
   439     private void ControlModeChanged(IControl control) {
   440       switch (control.ControlMode) {
   441         case ControlMode.Undefined:
   442           return;
   443         case ControlMode.Default:
   444           SetDefaultFanSpeed();
   445           break;
   446         case ControlMode.Software:
   447           SoftwareControlValueChanged(control);
   448           break;
   449         default:
   450           return;
   451       }
   452     }
   453 
   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);
   460     }
   461 
   462     public override void Close() {
   463       if (this.fanControl != null) {
   464         this.fanControl.ControlModeChanged -= ControlModeChanged;
   465         this.fanControl.SoftwareControlValueChanged -=
   466           SoftwareControlValueChanged;
   467 
   468         if (this.fanControl.ControlMode != ControlMode.Undefined)
   469           SetDefaultFanSpeed();
   470       }
   471       base.Close();
   472     }
   473   }
   474 }