Hardware/Nvidia/NvidiaGPU.cs
author sl
Thu, 01 Jan 2015 23:35:49 +0100
changeset 405 5715aefd2bcc
parent 334 013e148e8f12
permissions -rw-r--r--
SharpDisplay: Migrating to new robust client scheme.
     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-2012 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     private bool restoreDefaultFanSpeedRequired;
    32     private NvLevel initialFanSpeedValue;
    33 
    34     public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
    35       NvDisplayHandle? displayHandle, ISettings settings)
    36       : base(GetName(handle), new Identifier("nvidiagpu",
    37           adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) {
    38       this.adapterIndex = adapterIndex;
    39       this.handle = handle;
    40       this.displayHandle = displayHandle;
    41 
    42       NvGPUThermalSettings thermalSettings = GetThermalSettings();
    43       temperatures = new Sensor[thermalSettings.Count];
    44       for (int i = 0; i < temperatures.Length; i++) {
    45         NvSensor sensor = thermalSettings.Sensor[i];
    46         string name;
    47         switch (sensor.Target) {
    48           case NvThermalTarget.BOARD: name = "GPU Board"; break;
    49           case NvThermalTarget.GPU: name = "GPU Core"; break;
    50           case NvThermalTarget.MEMORY: name = "GPU Memory"; break;
    51           case NvThermalTarget.POWER_SUPPLY: name = "GPU Power Supply"; break;
    52           case NvThermalTarget.UNKNOWN: name = "GPU Unknown"; break;
    53           default: name = "GPU"; break;
    54         }
    55         temperatures[i] = new Sensor(name, i, SensorType.Temperature, this,
    56           new ParameterDescription[0], settings);
    57         ActivateSensor(temperatures[i]);
    58       }
    59 
    60       int value;
    61       if (NVAPI.NvAPI_GPU_GetTachReading != null &&
    62         NVAPI.NvAPI_GPU_GetTachReading(handle, out value) == NvStatus.OK) {
    63         if (value > 0) {
    64           fan = new Sensor("GPU", 0, SensorType.Fan, this, settings);
    65           ActivateSensor(fan);
    66         }
    67       }
    68 
    69       clocks = new Sensor[3];
    70       clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings);
    71       clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings);
    72       clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this, settings);
    73       for (int i = 0; i < clocks.Length; i++)
    74         ActivateSensor(clocks[i]);
    75 
    76       loads = new Sensor[3];
    77       loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings);
    78       loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings);
    79       loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings);
    80       memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
    81 
    82       control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
    83 
    84       NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
    85       if (coolerSettings.Count > 0) {
    86         fanControl = new Control(control, settings,
    87           coolerSettings.Cooler[0].DefaultMin, 
    88           coolerSettings.Cooler[0].DefaultMax);
    89         fanControl.ControlModeChanged += ControlModeChanged;
    90         fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged;
    91         ControlModeChanged(fanControl);
    92         control.Control = fanControl;
    93       }
    94       Update();
    95     }
    96 
    97     private static string GetName(NvPhysicalGpuHandle handle) {
    98       string gpuName;
    99       if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK) {
   100         return "NVIDIA " + gpuName.Trim();
   101       } else {
   102         return "NVIDIA";
   103       }
   104     }
   105 
   106     public override HardwareType HardwareType {
   107       get { return HardwareType.GpuNvidia; }
   108     }
   109 
   110     private NvGPUThermalSettings GetThermalSettings() {
   111       NvGPUThermalSettings settings = new NvGPUThermalSettings();
   112       settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
   113       settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
   114       settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
   115       if (!(NVAPI.NvAPI_GPU_GetThermalSettings != null &&
   116         NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
   117           ref settings) == NvStatus.OK)) 
   118       {
   119         settings.Count = 0;
   120       }       
   121       return settings;    
   122     }
   123 
   124     private NvGPUCoolerSettings GetCoolerSettings() {
   125       NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
   126       settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
   127       settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
   128       if (!(NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
   129         NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, 
   130           ref settings) == NvStatus.OK)) 
   131       {
   132         settings.Count = 0;
   133       }
   134       return settings;  
   135     }
   136 
   137     private uint[] GetClocks() {
   138       NvClocks allClocks = new NvClocks();
   139       allClocks.Version = NVAPI.GPU_CLOCKS_VER;
   140       allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
   141       if (NVAPI.NvAPI_GPU_GetAllClocks != null &&
   142         NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks) == NvStatus.OK) {
   143         return allClocks.Clock;
   144       }
   145       return null;
   146     }
   147 
   148     public override void Update() {
   149       NvGPUThermalSettings settings = GetThermalSettings();
   150       foreach (Sensor sensor in temperatures)
   151         sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
   152 
   153       if (fan != null) {
   154         int value = 0;
   155         NVAPI.NvAPI_GPU_GetTachReading(handle, out value);
   156         fan.Value = value;
   157       }
   158 
   159       uint[] values = GetClocks();
   160       if (values != null) {
   161         clocks[0].Value = 0.001f * values[0];
   162         clocks[1].Value = 0.001f * values[8];
   163         clocks[2].Value = 0.001f * values[14];
   164         if (values[30] != 0) {
   165           clocks[0].Value = 0.0005f * values[30];
   166           clocks[2].Value = 0.001f * values[30];
   167         }
   168       }
   169 
   170       NvPStates states = new NvPStates();
   171       states.Version = NVAPI.GPU_PSTATES_VER;
   172       states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
   173       if (NVAPI.NvAPI_GPU_GetPStates != null &&
   174         NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) {
   175         for (int i = 0; i < 3; i++)
   176           if (states.PStates[i].Present) {
   177             loads[i].Value = states.PStates[i].Percentage;
   178             ActivateSensor(loads[i]);
   179           }
   180       } else {
   181         NvUsages usages = new NvUsages();
   182         usages.Version = NVAPI.GPU_USAGES_VER;
   183         usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
   184         if (NVAPI.NvAPI_GPU_GetUsages != null &&
   185           NVAPI.NvAPI_GPU_GetUsages(handle, ref usages) == NvStatus.OK) {
   186           loads[0].Value = usages.Usage[2];
   187           loads[1].Value = usages.Usage[6];
   188           loads[2].Value = usages.Usage[10];
   189           for (int i = 0; i < 3; i++)
   190             ActivateSensor(loads[i]);
   191         }
   192       }
   193 
   194 
   195       NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
   196       if (coolerSettings.Count > 0) {
   197         control.Value = coolerSettings.Cooler[0].CurrentLevel;
   198         ActivateSensor(control);
   199       }
   200 
   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) ==
   206         NvStatus.OK) {
   207         uint totalMemory = memoryInfo.Values[0];
   208         uint freeMemory = memoryInfo.Values[4];
   209         float usedMemory = Math.Max(totalMemory - freeMemory, 0);
   210         memoryLoad.Value = 100f * usedMemory / totalMemory;
   211         ActivateSensor(memoryLoad);
   212       }
   213     }
   214 
   215     public override string GetReport() {
   216       StringBuilder r = new StringBuilder();
   217 
   218       r.AppendLine("Nvidia GPU");
   219       r.AppendLine();
   220 
   221       r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
   222       r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
   223 
   224       if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) {
   225         NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion();
   226         driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
   227         if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value,
   228           ref driverVersion) == NvStatus.OK) {
   229           r.Append("Driver Version: ");
   230           r.Append(driverVersion.DriverVersion / 100);
   231           r.Append(".");
   232           r.Append((driverVersion.DriverVersion % 100).ToString("00",
   233             CultureInfo.InvariantCulture));
   234           r.AppendLine();
   235           r.Append("Driver Branch: ");
   236           r.AppendLine(driverVersion.BuildBranch);
   237         }
   238       }
   239       r.AppendLine();
   240 
   241       if (NVAPI.NvAPI_GPU_GetPCIIdentifiers != null) {
   242         uint deviceId, subSystemId, revisionId, extDeviceId;
   243 
   244         NvStatus status = NVAPI.NvAPI_GPU_GetPCIIdentifiers(handle, 
   245           out deviceId, out subSystemId, out revisionId, out extDeviceId);
   246 
   247         if (status == NvStatus.OK) {
   248           r.Append("DeviceID: 0x");
   249           r.AppendLine(deviceId.ToString("X", CultureInfo.InvariantCulture));
   250           r.Append("SubSystemID: 0x");
   251           r.AppendLine(subSystemId.ToString("X", CultureInfo.InvariantCulture));
   252           r.Append("RevisionID: 0x");
   253           r.AppendLine(revisionId.ToString("X", CultureInfo.InvariantCulture));
   254           r.Append("ExtDeviceID: 0x");
   255           r.AppendLine(extDeviceId.ToString("X", CultureInfo.InvariantCulture));
   256           r.AppendLine();
   257         }
   258       }
   259 
   260       if (NVAPI.NvAPI_GPU_GetThermalSettings != null) {
   261         NvGPUThermalSettings settings = new NvGPUThermalSettings();
   262         settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
   263         settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
   264         settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
   265 
   266         NvStatus status = NVAPI.NvAPI_GPU_GetThermalSettings(handle,
   267           (int)NvThermalTarget.ALL, ref settings);
   268 
   269         r.AppendLine("Thermal Settings");
   270         r.AppendLine();
   271         if (status == NvStatus.OK) {
   272           for (int i = 0; i < settings.Count; i++) {
   273             r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i,
   274               settings.Sensor[i].Controller, Environment.NewLine);
   275             r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i,
   276               settings.Sensor[i].DefaultMinTemp, Environment.NewLine);
   277             r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i,
   278               settings.Sensor[i].DefaultMaxTemp, Environment.NewLine);
   279             r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i,
   280               settings.Sensor[i].CurrentTemp, Environment.NewLine);
   281             r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i,
   282               settings.Sensor[i].Target, Environment.NewLine);
   283           }
   284         } else {
   285           r.Append(" Status: ");
   286           r.AppendLine(status.ToString());
   287         }
   288         r.AppendLine();
   289       }
   290 
   291       if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
   292         NvClocks allClocks = new NvClocks();
   293         allClocks.Version = NVAPI.GPU_CLOCKS_VER;
   294         allClocks.Clock = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
   295         NvStatus status = NVAPI.NvAPI_GPU_GetAllClocks(handle, ref allClocks);
   296 
   297         r.AppendLine("Clocks");
   298         r.AppendLine();
   299         if (status == NvStatus.OK) {
   300           for (int i = 0; i < allClocks.Clock.Length; i++)
   301             if (allClocks.Clock[i] > 0) {
   302               r.AppendFormat(" Clock[{0}]: {1}{2}", i, allClocks.Clock[i],
   303                 Environment.NewLine);
   304             }
   305         } else {
   306           r.Append(" Status: ");
   307           r.AppendLine(status.ToString());
   308         }
   309         r.AppendLine();
   310       }
   311 
   312       if (NVAPI.NvAPI_GPU_GetTachReading != null) {
   313         int tachValue;
   314         NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
   315 
   316         r.AppendLine("Tachometer");
   317         r.AppendLine();
   318         if (status == NvStatus.OK) {
   319           r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine);
   320         } else {
   321           r.Append(" Status: ");
   322           r.AppendLine(status.ToString());
   323         }
   324         r.AppendLine();
   325       }
   326 
   327       if (NVAPI.NvAPI_GPU_GetPStates != null) {
   328         NvPStates states = new NvPStates();
   329         states.Version = NVAPI.GPU_PSTATES_VER;
   330         states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
   331         NvStatus status = NVAPI.NvAPI_GPU_GetPStates(handle, ref states);
   332 
   333         r.AppendLine("P-States");
   334         r.AppendLine();
   335         if (status == NvStatus.OK) {
   336           for (int i = 0; i < states.PStates.Length; i++)
   337             if (states.PStates[i].Present)
   338               r.AppendFormat(" Percentage[{0}]: {1}{2}", i,
   339                 states.PStates[i].Percentage, Environment.NewLine);
   340         } else {
   341           r.Append(" Status: ");
   342           r.AppendLine(status.ToString());
   343         }
   344         r.AppendLine();
   345       }
   346 
   347       if (NVAPI.NvAPI_GPU_GetUsages != null) {
   348         NvUsages usages = new NvUsages();
   349         usages.Version = NVAPI.GPU_USAGES_VER;
   350         usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
   351         NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
   352 
   353         r.AppendLine("Usages");
   354         r.AppendLine();
   355         if (status == NvStatus.OK) {
   356           for (int i = 0; i < usages.Usage.Length; i++)
   357             if (usages.Usage[i] > 0)
   358               r.AppendFormat(" Usage[{0}]: {1}{2}", i,
   359                 usages.Usage[i], Environment.NewLine);
   360         } else {
   361           r.Append(" Status: ");
   362           r.AppendLine(status.ToString());
   363         }
   364         r.AppendLine();
   365       }
   366 
   367       if (NVAPI.NvAPI_GPU_GetCoolerSettings != null) {
   368         NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
   369         settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
   370         settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
   371         NvStatus status =
   372           NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref settings);
   373 
   374         r.AppendLine("Cooler Settings");
   375         r.AppendLine();
   376         if (status == NvStatus.OK) {
   377           for (int i = 0; i < settings.Count; i++) {
   378             r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i,
   379               settings.Cooler[i].Type, Environment.NewLine);
   380             r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i,
   381               settings.Cooler[i].Controller, Environment.NewLine);
   382             r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i,
   383               settings.Cooler[i].DefaultMin, Environment.NewLine);
   384             r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i,
   385               settings.Cooler[i].DefaultMax, Environment.NewLine);
   386             r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i,
   387               settings.Cooler[i].CurrentMin, Environment.NewLine);
   388             r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i,
   389               settings.Cooler[i].CurrentMax, Environment.NewLine);
   390             r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i,
   391               settings.Cooler[i].CurrentLevel, Environment.NewLine);
   392             r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i,
   393               settings.Cooler[i].DefaultPolicy, Environment.NewLine);
   394             r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i,
   395               settings.Cooler[i].CurrentPolicy, Environment.NewLine);
   396             r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i,
   397               settings.Cooler[i].Target, Environment.NewLine);
   398             r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i,
   399               settings.Cooler[i].ControlType, Environment.NewLine);
   400             r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i,
   401               settings.Cooler[i].Active, Environment.NewLine);
   402           }
   403         } else {
   404           r.Append(" Status: ");
   405           r.AppendLine(status.ToString());
   406         }
   407         r.AppendLine();
   408       }
   409 
   410       if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue) {
   411         NvMemoryInfo memoryInfo = new NvMemoryInfo();
   412         memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
   413         memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
   414         NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
   415           ref memoryInfo);
   416 
   417         r.AppendLine("Memory Info");
   418         r.AppendLine();
   419         if (status == NvStatus.OK) {
   420           for (int i = 0; i < memoryInfo.Values.Length; i++)
   421             r.AppendFormat(" Value[{0}]: {1}{2}", i,
   422                 memoryInfo.Values[i], Environment.NewLine);
   423         } else {
   424           r.Append(" Status: ");
   425           r.AppendLine(status.ToString());
   426         }
   427         r.AppendLine();
   428       }
   429 
   430       return r.ToString();
   431     }
   432 
   433     private void SoftwareControlValueChanged(IControl control) {
   434       SaveDefaultFanSpeed();
   435       NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
   436       coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
   437       coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
   438       coolerLevels.Levels[0].Level = (int)control.SoftwareValue;
   439       coolerLevels.Levels[0].Policy = 1;
   440       NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
   441     }
   442 
   443     private void SaveDefaultFanSpeed() {
   444       if (!restoreDefaultFanSpeedRequired) {
   445         NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
   446         if (coolerSettings.Count > 0) {
   447           restoreDefaultFanSpeedRequired = true;
   448           initialFanSpeedValue.Level = coolerSettings.Cooler[0].CurrentLevel;
   449           initialFanSpeedValue.Policy = coolerSettings.Cooler[0].CurrentPolicy;
   450         }
   451       }
   452     }
   453 
   454     private void ControlModeChanged(IControl control) {
   455       if (control.ControlMode == ControlMode.Default) {
   456         RestoreDefaultFanSpeed();
   457       } else {
   458         SoftwareControlValueChanged(control);
   459       }
   460     }
   461 
   462     private void RestoreDefaultFanSpeed() {
   463       if (restoreDefaultFanSpeedRequired) {
   464         NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
   465         coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
   466         coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
   467         coolerLevels.Levels[0] = initialFanSpeedValue;
   468         NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
   469         restoreDefaultFanSpeedRequired = false;
   470       }
   471     }
   472   }
   473 }