Hardware/Nvidia/NvidiaGPU.cs
author StephaneLenclud
Sun, 03 Feb 2013 18:01:50 +0100
branchMiniDisplay
changeset 433 090259cfd699
parent 428 3c1cdc197b24
permissions -rw-r--r--
Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
     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 }