/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. Copyright (C) 2020 Michael Möller */ using System; using System.Runtime.InteropServices; namespace OpenHardwareMonitor.Hardware.Nvidia { internal class NVML { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate NvmlReturn nvmlInitDelegate(); private static readonly nvmlInitDelegate nvmlInit; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate NvmlReturn nvmlInit_v2Delegate(); private static readonly nvmlInit_v2Delegate nvmlInit_v2; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NvmlReturn nvmlShutdownDelegate(); public static readonly nvmlShutdownDelegate NvmlShutdown; public delegate NvmlReturn nvmlDeviceGetHandleByPciBusIdDelegate( string pciBusId, out NvmlDevice device); public static readonly nvmlDeviceGetHandleByPciBusIdDelegate NvmlDeviceGetHandleByPciBusId; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NvmlReturn nvmlDeviceGetPowerUsageDelegate( NvmlDevice device, out int power); public static readonly nvmlDeviceGetPowerUsageDelegate NvmlDeviceGetPowerUsage; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NvmlReturn nvmlDeviceGetPcieThroughputDelegate( NvmlDevice devicee, NvmlPcieUtilCounter counter, out uint value); public static readonly nvmlDeviceGetPcieThroughputDelegate NvmlDeviceGetPcieThroughput; public static NvmlReturn NvmlInit() { try { var result = nvmlInit_v2(); initialized = result == NvmlReturn.Success; return result; } catch { try { var result = nvmlInit(); initialized = result == NvmlReturn.Success; return result; } catch { return NvmlReturn.ErrorLibraryNotFound; } } } private static string GetDllName() { if (OperatingSystem.IsUnix) return "libnvidia-ml.so"; else return "nvml.dll"; } private static T CreateDelegate(string entryPoint) where T : Delegate { var attribute = new DllImportAttribute(GetDllName()) { CallingConvention = CallingConvention.Cdecl, PreserveSig = true, EntryPoint = entryPoint }; PInvokeDelegateFactory.CreateDelegate(attribute, out T newDelegate); return newDelegate; } static NVML() { nvmlInit = CreateDelegate( "nvmlInit"); nvmlInit_v2 = CreateDelegate( "nvmlInit_v2"); NvmlShutdown = CreateDelegate( "nvmlShutdown"); NvmlDeviceGetHandleByPciBusId = CreateDelegate( "nvmlDeviceGetHandleByPciBusId_v2"); NvmlDeviceGetPowerUsage = CreateDelegate( "nvmlDeviceGetPowerUsage"); NvmlDeviceGetPcieThroughput = CreateDelegate( "nvmlDeviceGetPcieThroughput"); } private static bool initialized; public static bool IsInitialized { get { return initialized; } } [StructLayout(LayoutKind.Sequential)] internal struct NvmlDevice { private readonly IntPtr ptr; } internal enum NvmlPcieUtilCounter { TxBytes = 0, RxBytes = 1 } internal enum NvmlReturn { /// /// The operation was successful /// Success = 0, /// /// NVML was not first initialized with nvmlInit() /// ErrorUninitialized = 1, /// /// A supplied argument is invalid /// ErrorInvalidArgument = 2, /// /// The requested operation is not available on target device /// ErrorNotSupported = 3, /// /// The current user does not have permission for operation /// ErrorNoPermission = 4, /// /// Deprecated: Multiple initializations are now allowed through ref /// counting /// ErrorAlreadyInitialized = 5, /// /// A query to find an object was unsuccessful /// ErrorNotFound = 6, /// /// An input argument is not large enough /// ErrorInsufficientSize = 7, /// /// A device's external power cables are not properly attached /// ErrorInsufficientPower = 8, /// /// NVIDIA driver is not loaded /// ErrorDriverNotLoaded = 9, /// /// User provided timeout passed /// ErrorTimeout = 10, /// /// NVIDIA Kernel detected an interrupt issue with a GPU /// ErrorIrqIssue = 11, /// /// NVML Shared Library couldn't be found or loaded /// ErrorLibraryNotFound = 12, /// /// Local version of NVML doesn't implement this function /// ErrorFunctionNotFound = 13, /// /// infoROM is corruptedinfoROM is corrupted /// ErrorCorruptedInforom = 14, /// /// The GPU has fallen off the bus or has otherwise become inaccessible /// ErrorGpuIsLost = 15, /// /// The GPU requires a reset before it can be used again /// ErrorResetRequired = 16, /// /// The GPU control device has been blocked by the operating /// system/cgroups /// ErrorOperatingSystem = 17, /// /// RM detects a driver/library version mismatch /// ErrorLibRmVersionMismatch = 18, /// /// An operation cannot be performed because the GPU is currently in use /// ErrorInUse = 19, /// /// Insufficient memory /// ErrorMemory = 20, /// /// No data /// ErrorNoData = 21, /// /// The requested vgpu operation is not available on target device, /// becasue ECC is enabled /// ErrorvGpuEccNotSupported = 22, /// /// An internal driver error occurred /// ErrorUnknown = 999 }; } }