Hardware/Nvidia/NvidiaGPU.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 334 013e148e8f12
child 428 3c1cdc197b24
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
     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 }