From 6e46c06edd42d1d720f47fcc63845124b2e380cd Mon Sep 17 00:00:00 2001 From: root Date: Sun, 26 Apr 2026 13:25:50 +0800 Subject: [PATCH] first commit --- .gitignore | 3 + linux/all/etc/passwd | 30 + pkgs/cuda-13.0/include | 1 + pkgs/cuda-13.0/lib64 | 1 + pkgs/cuda-13.0/nvml/doc/nvml_changelog.txt | 504 + .../nvml/doc/nvml_deprecation_and_removal.txt | 33 + pkgs/cuda-13.0/nvml/example/Makefile | 87 + pkgs/cuda-13.0/nvml/example/README.txt | 10 + pkgs/cuda-13.0/nvml/example/example.c | 180 + pkgs/cuda-13.0/nvml/example/supportedVgpus.c | 160 + .../targets/x86_64-linux/include/nvml.h | 13607 ++++++++++++++++ .../x86_64-linux/lib/stubs/libnvidia-ml.a | Bin 0 -> 557156 bytes .../x86_64-linux/lib/stubs/libnvidia-ml.so | Bin 0 -> 71600 bytes pkgs/ks/dfmt.sh | 254 + pkgs/ks/init.sh | 753 + pkgs/ks/ipxe.sh | 21 + pkgs/ks/rhel.ks | 60 + pkgs/pxelinux/tftpboot/boot/bootx64.efi | Bin 0 -> 959224 bytes pkgs/pxelinux/tftpboot/boot/undionly.kpxe | Bin 0 -> 88519 bytes sunhpc | 1570 ++ 20 files changed, 17274 insertions(+) create mode 100644 .gitignore create mode 100644 linux/all/etc/passwd create mode 120000 pkgs/cuda-13.0/include create mode 120000 pkgs/cuda-13.0/lib64 create mode 100644 pkgs/cuda-13.0/nvml/doc/nvml_changelog.txt create mode 100644 pkgs/cuda-13.0/nvml/doc/nvml_deprecation_and_removal.txt create mode 100644 pkgs/cuda-13.0/nvml/example/Makefile create mode 100644 pkgs/cuda-13.0/nvml/example/README.txt create mode 100644 pkgs/cuda-13.0/nvml/example/example.c create mode 100644 pkgs/cuda-13.0/nvml/example/supportedVgpus.c create mode 100644 pkgs/cuda-13.0/targets/x86_64-linux/include/nvml.h create mode 100644 pkgs/cuda-13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.a create mode 100755 pkgs/cuda-13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.so create mode 100644 pkgs/ks/dfmt.sh create mode 100644 pkgs/ks/init.sh create mode 100644 pkgs/ks/ipxe.sh create mode 100644 pkgs/ks/rhel.ks create mode 100755 pkgs/pxelinux/tftpboot/boot/bootx64.efi create mode 100644 pkgs/pxelinux/tftpboot/boot/undionly.kpxe create mode 100755 sunhpc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5569e64 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.swp +*.log +*.status diff --git a/linux/all/etc/passwd b/linux/all/etc/passwd new file mode 100644 index 0000000..fb9d049 --- /dev/null +++ b/linux/all/etc/passwd @@ -0,0 +1,30 @@ +root:x:0:0:Super User:/root:/bin/bash +bin:x:1:1:bin:/bin:/usr/sbin/nologin +daemon:x:2:2:daemon:/sbin:/usr/sbin/nologin +adm:x:3:4:adm:/var/adm:/usr/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/usr/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/spool/mail:/usr/sbin/nologin +operator:x:11:0:operator:/root:/usr/sbin/nologin +games:x:12:100:games:/usr/games:/usr/sbin/nologin +ftp:x:14:50:FTP User:/var/ftp:/usr/sbin/nologin +nobody:x:65534:65534:Kernel Overflow User:/:/usr/sbin/nologin +tss:x:59:59:Account used for TPM access:/:/usr/sbin/nologin +systemd-oom:x:999:999:systemd Userspace OOM Killer:/:/sbin/nologin +dbus:x:81:81:System Message Bus:/:/usr/sbin/nologin +polkitd:x:114:114:User for polkitd:/:/sbin/nologin +clevis:x:998:997:Clevis Decryption Framework unprivileged user:/var/cache/clevis:/usr/sbin/nologin +sssd:x:997:996:User for sssd:/run/sssd/:/sbin/nologin +libstoragemgmt:x:995:995:daemon account for libstoragemgmt:/:/usr/sbin/nologin +systemd-coredump:x:994:994:systemd Core Dumper:/:/usr/sbin/nologin +setroubleshoot:x:993:993:SELinux troubleshoot server:/var/lib/setroubleshoot:/usr/sbin/nologin +sshd:x:74:74:Privilege-separated SSH:/usr/share/empty.sshd:/usr/sbin/nologin +chrony:x:992:992:chrony system user:/var/lib/chrony:/sbin/nologin +tcpdump:x:72:72:tcpdump:/:/usr/sbin/nologin +dhcpcd:x:991:990:Minimalistic DHCP client:/var/lib/dhcpcd:/usr/sbin/nologin +git:x:990:989:Git Version Control:/home/git:/bin/bash +nginx:x:989:988:Nginx web server:/var/lib/nginx:/sbin/nologin +caddy:x:988:987::/home/caddy:/bin/false +admin:x:1000:1000::/home/admin:/bin/bash diff --git a/pkgs/cuda-13.0/include b/pkgs/cuda-13.0/include new file mode 120000 index 0000000..7609169 --- /dev/null +++ b/pkgs/cuda-13.0/include @@ -0,0 +1 @@ +targets/x86_64-linux/include \ No newline at end of file diff --git a/pkgs/cuda-13.0/lib64 b/pkgs/cuda-13.0/lib64 new file mode 120000 index 0000000..1ab6f09 --- /dev/null +++ b/pkgs/cuda-13.0/lib64 @@ -0,0 +1 @@ +targets/x86_64-linux/lib \ No newline at end of file diff --git a/pkgs/cuda-13.0/nvml/doc/nvml_changelog.txt b/pkgs/cuda-13.0/nvml/doc/nvml_changelog.txt new file mode 100644 index 0000000..c6ec756 --- /dev/null +++ b/pkgs/cuda-13.0/nvml/doc/nvml_changelog.txt @@ -0,0 +1,504 @@ +/*! @page KnownIssues Known issues in the current version of NVML library + * + * This is a list of known NVML issues in the current driver: + * - NVML Field Values from #251 - #273 (Power Smoothing, Clock Event Reason, and Sync Power Balancing related field values) have changed between 13.0 and 13.0U1/v580TRD2. + * - Any application that is using these field IDs must be recompiled using the NVML header file from CUDA 13.0 Update 1 in order to continue working correctly with NVIDIA drivers v580 TRD2 and beyond. + * - On systems where GPUs are NUMA nodes, the accuracy of FB memory utilization provided by NVML depends on the memory accounting of the operating system. + * This is because FB memory is managed by the operating system instead of the NVIDIA GPU driver. + * Typically, pages allocated from FB memory are not released even after the process terminates to enhance performance. In scenarios where + * the operating system is under memory pressure, it may resort to utilizing FB memory. Such actions can result in discrepancies in the accuracy of memory reporting. + * - On Linux GPU Reset can't be triggered when there is pending GPU Operation Mode (GOM) change + * - On Linux GPU Reset may not successfully change pending ECC mode. A full reboot may be required to enable the mode change. + * - \ref nvmlAccountingStats supports only one process per GPU at a time (CUDA proxy server counts as one process). + * - \ref nvmlAccountingStats_t.time reports time and utilization values starting from cuInit till process termination. Next driver versions might change this behavior slightly and account process only from cuCtxCreate till cuCtxDestroy. + * - On GPUs from Fermi family current P0 clocks (reported by \ref nvmlDeviceGetClockInfo) can differ from max clocks by few MHz. + */ +/*! @page Changelog Change log of NVML library + * This chapter list changes in API and bug fixes that were introduced to the library + * \section changelog32 Changes between NVML v575 and v580 === + * - Fixed bug with NVML_FI_PWR_SMOOTHING_* Field Value numbering, which was different than the v570 values. + * - Adjusted NVML_FI_DEV_CLOCKS_EVENT_REASON_* and NVML_FI_DEV_POWER_SYNC_BALANCING_* field value numbering to resolve overlap with NVML_FI_PWR_SMOOTHING_* field values. + * + * - Added \ref nvmlDeviceGetSramUniqueUncorrectedEccErrorCounts to get the counts of SRAM unique uncorrected ECC errors. + * - Deprecated Applications Clocks APIs, which will be removed in CUDA 14.0: + * - \ref nvmlDeviceSetApplicationsClocks + * - \ref nvmlDeviceGetApplicationsClock + * - \ref nvmlDeviceGetDefaultApplicationsClock + * - \ref nvmlDeviceResetApplicationsClocks + * - Deprecated \ref nvmlDeviceGetViolationStatus, which will be removed in CUDA 14.0 + * - Added \ref nvmlDeviceGetNvLinkInfo to query device NVLINK info. + * - Added \ref nvmlDeviceGetPdi to retrieve the device GPU PDI. + * - Added Multi-GPU mode NVLINK Encryption \ref NVML_CC_SYSTEM_MULTIGPU_NVLE + * - Added V2 struct to \ref nvmlDeviceGetNvLinkInfo to query NVLINK Firmware info. + * - Added \ref nvmlDeviceReadWritePRM_v1 to retrieve GPU PRM register contents + * - Added \ref nvmlDeviceGetAddressingMode to retrieve the addressing mode for the device. + * - Added \ref nvmlDeviceGetRepairStatus to get ECC status info. + * - Added \ref nvmlDeviceGetGpuInstanceProfileInfoByIdV which allows for MIG GPU instance profile info to be queried with profileId instead of profile name. + * - Updated nvmlGpuFabricInfoV_t to v3 to include a new Health Summary field, and new Incorrect Configuration statuses. + - nvmlGpuFabricInfo_v2_t is deprecated and will be removed in a future release + * - Added \ref nvmlDeviceGetPowerMizerMode_v1 to query the current and supported power mizer modes on Maxwell and newer gpus. Power mizer mode provides a hint to the driver as to how to manage the performance of the GPU. + * - Added \ref nvmlDeviceSetPowerMizerMode_v1 to set the power mizer mode on Maxwell and newer gpus. + * - Added new Incorrect Configuration Statuses to nvmlGpuFabricInfoV_t + * - NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INCOMPATIBLE_GPU_FW + * - NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INVALID_LOCATION + * - Added \ref nvmlDeviceSetHostname_v1 and \ref nvmlDeviceGetHostname_v1 to allow custom GPU hostname configuration. + * \section changelog31 Changes between NVML v570 and v575 === + * + * - Added \ref nvmlSystemEventSetCreate to create a system event set. + * - Added \ref nvmlSystemEventSetFree to free a system event set. + * - Added \ref nvmlSystemRegisterEvents to register system events on a system event set. + * - Added \ref nvmlSystemEventSetWait to wait for system event notification and obtain system event data. + * - Added \ref nvmlGpuInstanceGetCreatableVgpus to query the currently creatable vGPU types on the user provided GPU Instance + * - Added \ref nvmlVgpuTypeGetMaxInstancesPerGpuInstance to query the maximum number of vGPU instances per GPU Instance for the given vGPU type + * - Added \ref nvmlGpuInstanceSetVgpuSchedulerState to set the vGPU scheduler state for the given GPU Instance + * - Added \ref nvmlGpuInstanceGetActiveVgpus to query the currently active vGPU instances on the user provided GPU Instance + * - Added \ref nvmlGpuInstanceGetVgpuSchedulerState to query the vGPU software scheduler state for the given GPU Instance. + * - Added \ref nvmlGpuInstanceGetVgpuSchedulerLog to query the vGPU software scheduler logs for the given GPU Instance. + * - Added \ref nvmlGpuInstanceGetVgpuTypeCreatablePlacements to query the creatable vGPU placement IDs of the vGPU type within a GPU instance + * - Added \ref nvmlGpuInstanceSetVgpuHeterogeneousMode to enable or disable vGPU heterogenous mode for the GPU Instance. + * - Added \ref nvmlGpuInstanceGetVgpuHeterogeneousMode to query the vGPU heterogenous mode for the GPU Instance. + * - Updated \ref nvmlDeviceGetVgpuCapabilities to report whether GPU supports timesliced vGPU on MIG and whether MIG timesliced mode is enabled or not vGPU capabilities. + * - Updated \ref nvmlDeviceSetVgpuCapabilities to set the MIG timesliced mode vGPU capability of a device. + * - Updated \ref nvmlDeviceSetVgpuHeterogeneousMode to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode. + * - Updated \ref nvmlDeviceGetVgpuHeterogeneousMode to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode. + * - Updated \ref nvmlDeviceGetVgpuTypeCreatablePlacements to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode. + * - Updated \ref nvmlDeviceGetVgpuSchedulerLog to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode. + * - Updated \ref nvmlDeviceSetVgpuSchedulerState to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode. + * - Updated \ref nvmlDeviceGetVgpuSchedulerState to return \ref NVML_ERROR_NOT_SUPPORTED when in MIG mode. + * - Added 3 new NVML_FI_DEV_C2C_LINK_ERROR fieldIds + * - \ref NVML_FI_DEV_C2C_LINK_ERROR_INTR + * - \ref NVML_FI_DEV_C2C_LINK_ERROR_REPLAY + * - \ref NVML_FI_DEV_C2C_LINK_ERROR_REPLAY_B2B + * - Added new NVML_FI_DEV_C2C_LINK_POWER_STATE fieldId + * - Added new CTXSW GPM Metrics + * - Added \ref nvmlDeviceGetHandleByUUIDV that supports both the ASCII and binary format UUID to retrieve the device handle. + * - Added 2 new NVML_FI_DEV_POWER_SYNC_BALANCING fieldIds + * - \ref NVML_FI_DEV_POWER_SYNC_BALANCING_FREQ + * - \ref NVML_FI_DEV_POWER_SYNC_BALANCING_AF + * - Added 5 new Clock Event Reason Counters fieldIds + * - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_SW_POWER_CAP + * - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_SYNC_BOOST + * - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_SW_THERM_SLOWDOWN + * - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_HW_THERM_SLOWDOWN + * - \ref NVML_FI_DEV_CLOCKS_EVENT_REASON_HW_POWER_BRAKE_SLOWDOWN + * - Updated \ref nvmlDeviceGetMemoryErrorCounter to better account for transient vs. permanent errors + * - Added MIG profiles that can allocate all or none of Decoder, Encoder, JPEG and OFA engines. + * + * \section changelog30 Changes between NVML v565 Update and v570 === + * - Revert the fix for the issue where PCIe throughput (reported via \ref nvmlDeviceGetPcieThroughput and nvidia-smi -q) is 1000 times bigger than its actual value + * - Added field values for data related to Power Smoothing + * - Added \ref nvmlDevicePowerSmoothingActivatePresetProfile to activate a specific Preset Profile for Power Smoothing + * - Added \ref nvmlDevicePowerSmoothingSetState to enable/disable the Power Smoothing feature + * - Added \ref nvmlDevicePowerSmoothingUpdatePresetProfileParam to update parameters to preset profiles for Power Smoothing + * - Added new enums for fieldId NVML_FI_DEV_NVLINK_GET_STATE to expose INACTIVE, ACTIVE, and SLEEP state for a link + * - Added \ref nvmlDeviceGetMarginTemperature to retrieve the thermal margin temperature (distance to nearest slowdown threshold). + * - Added \ref nvmlDeviceGetNvlinkSupportedBwModes to get all supported Nvlink Bandwidth modes + * - Added \ref nvmlDeviceGetNvlinkBwMode to get the current Nvlink Bandwidth mode + * - Added \ref nvmlDeviceSetNvlinkBwMode to set the Nvlink Bandwidth mode + * - Added MIG profiles with support for graphics. + * - Added support for new recovery action - NVML_GPU_RECOVERY_ACTION_DRAIN_AND_RESET + * - Deprecated nvml fieldIds NVML_FI_DEV_RESET_STATUS and NVML_FI_DEV_DRAIN_AND_RESET_STATUS. Usee NVML_FI_DEV_GET_GPU_RECOVERY_ACTION instead + * - Added \ref nvmlDeviceGetDramEncryptionMode and \ref nvmlDeviceSetDramEncryptionMode to query and configure DRAM Encryption Mode + * - Added 3 new flags to GPU Fabric Health Mask + * - NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ROUTE_RECOVERY + * - NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ROUTE_UNHEALTHY + * - NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ACCESS_TIMEOUT_RECOVERY + * - Added 4 new GPM metrics + * - NVML_GPM_METRIC_NVENC_0_UTIL + * - NVML_GPM_METRIC_NVENC_1_UTIL + * - NVML_GPM_METRIC_NVENC_2_UTIL + * - NVML_GPM_METRIC_NVENC_3_UTIL + * - Added new counters for Nvlink5 + * - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_ERRORS to get sum of the number of errors in each Nvlink packet + * - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_BER to get Effective BER for effective errors + * - \ref NVML_FI_DEV_NVLINK_COUNT_FEC_HISTORY_0 to 15 to get count of symbol errors that are corrected + * - Swapped the values of field IDs \ref NVML_FI_DEV_IS_MIG_MODE_INDEPENDENT_MIG_QUERY_CAPABLE and \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MAX to fix backwards compatibility with v550. + * - New revision of nvmlPlatformInfo_t -- nvmlPlatformInfo_v2 has been added. In this version the following fields from v1 have been renamed + * - rackGuid to chassisSerialNumber + * - chassisPhysicalSlotNumber to slotNumber + * - computeSlotIndex to trayIndex + * - nodeIndex to hostId + * - nvmlPlatformInfo_v1 is deprecated and will be removed in subsequent releases + * + * \section changelog29 Changes between NVML v560 Update and v565 === + * - Fixed the ECC error count mismatch between nvidia-smi query output and NVML APIs, \ref nvmlDeviceGetMemoryErrorCounter and \ref nvmlDeviceGetFieldValues. + * - Added new value NVML_CC_SYSTEM_CPU_CAPS_AMD_SNP_VTOM for CC CPU capability reporting + * - Added \ref nvmlDeviceGetCoolerInfo to retrieve a cooler's control signal characteristics and target that cooler cools. + * - Added new value NVML_CC_SYSTEM_CPU_CAPS_AMD_SEV_SNP for CC CPU capability reporting + * - Added \ref nvmlDeviceGetFanSpeedRPM to report the intended operating speed in rotations per minute (RPM) of the device's specified fan. + * - Added \ref nvmlDeviceGetPerformanceModes to retrieve a performance modes string with all the performance modes defined for this device along with their associated GPU Clock and Memory Clock values. + * - Added \ref nvmlDeviceGetCurrentClockFreqs to retrieve a string with the associated GPU Clock and Memory Clock values for the current pstate. + * - Added \ref nvmlNvlinkVersion_t enum to define NvLink Version + * - Added \ref nvmlDeviceGetPlatformInfo to retrieve the platform information of a device + * - Added new event type nvmlEventTypeGpuUnavailableError + * - Removed support for \p nvmlDeviceGetNvLinkCrcLaneErrorCounter \p nvmlDeviceGetNvLinkEccLaneErrorCounter \p nvmlDeviceGetNvLinkErrorCounter on Blackwell + * - Removed support for fieldIds \ref NVML_FI_DEV_NVLINK_ERROR_DL_REPLAY \ref NVML_FI_DEV_NVLINK_ERROR_DL_RECOVERY \ref NVML_FI_DEV_NVLINK_ERROR_DL_CRC on Blackwell + * - Added \ref nvmlVgpuInstanceGetRuntimeStateSize to get the vGPU runtime state size + * - Updated nvmlDeviceGetVgpuTypeSupportedPlacements function to report both Heterogeneous and Homogeneous vGPU placements. + * - Updated nvmlDeviceGetVgpuCapabilities to report the Homogeneous vGPU capability. + * - Added \ref nvmlDeviceWorkloadPowerProfileGetProfilesInfo to retrieve Workload Power Profile Info + * - Added \ref nvmlDeviceWorkloadPowerProfileGetCurrentProfiles to retrieve current Requested and Enforced Workload Power Profiles + * - Added \ref nvmlDeviceWorkloadPowerProfileSetRequestedProfiles to set Requested Workload Power Profiles + * - Added \ref nvmlDeviceWorkloadPowerProfileClearRequestedProfiles to clear Requested Performance Profiles + * - Added new event type nvmlEventTypeGpuRecoveryAction + * - Added new fieldId to query gpu recovery action NVML_FI_DEV_GET_GPU_RECOVERY_ACTION + * - Deprecated fieldIds + * - \ref NVML_FI_DEV_NVLINK_COUNT_VL15_DROPPED to get Number of VL15 MADs dropped on a link in NVLink5 + * - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE0 to get BER per lane for lane 0 + * - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE1 to get BER per lane for lane 1 + * - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER to get BER per link. Sum of all the raw errors per lane/Bits received per link + * - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_ERRORS to get Sum of the number of errors in each Nvlink packet + * - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_BER to get Effective BER for effective errors + * + * \section changelog28 Changes between NVML v555 Update and v560 === + * + * - Added field values NVML_FI_DEV_PCIE_OUTBOUND_ATOMICS_MASK and NVML_FI_DEV_PCIE_INBOUND_ATOMICS_MASK for nvmlDeviceGetFieldValues. + * - Added field ids NVML_FI_DEV_RESET_STATUS and NVML_FI_DEV_DRAIN_AND_RESET_STATUS which correspond to the nvidia-smi output. + * - Added NVML_DEVICE_ARCH_T23X architecture type. + * - Added \ref nvmlVgpuTypeGetBAR1Info to query the BAR1 information of a vGPU type. + * - Added new event types, nvmlEventTypeSingleBitEccErrorStorm, nvmlEventTypeDramRetirementEvent, nvmlEventTypeDramRetirementFailure, nvmlEventTypeNonFatalPoisonError and nvmlEventTypeFatalPoisonError. + * - Added \ref nvmlSystemGetDriverBranch to query the driver branch information. + * + * \section changelog27 Changes between NVML v550 Update and v555 === + * + * - Added \ref nvmlDeviceGetClockOffsets to query min, max and current clock offset value on a Maxwell and later GPU for a specified clock. + * - Added \ref nvmlDeviceSetClockOffsets to control clock offset value on a Maxwell and later GPU for a specified clock. + * - Added new fieldIds for Nvlink5 telemetry on Blackwell + * - \ref NVML_FI_DEV_NVLINK_COUNT_XMIT_PACKETS to get Total Tx packets on the link in NVLink5 + * - \ref NVML_FI_DEV_NVLINK_COUNT_XMIT_BYTES to get Total Tx bytes on the link in NVLink5 + * - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_PACKETS to get Total Rx packets on the link in NVLink5 + * - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_BYTES to get Total Rx bytes on the link in NVLink5 + * - \ref NVML_FI_DEV_NVLINK_COUNT_VL15_DROPPED to get Number of VL15 MADs dropped on a link in NVLink5 + * - \ref NVML_FI_DEV_NVLINK_COUNT_MALFORMED_PACKET_ERRORS to get Number of packets Rx on a link where packets are malformed + * - \ref NVML_FI_DEV_NVLINK_COUNT_BUFFER_OVERRUN_ERRORS to get Number of packets that were discarded on Rx due to buffer overrun + * - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_ERRORS to get Total number of packets with errors Rx on a link + * - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_REMOTE_ERRORS to get Total number of packets Rx - stomp/EBP marker + * - \ref NVML_FI_DEV_NVLINK_COUNT_RCV_GENERAL_ERRORS to get Total number of packets Rx with header mismatch + * - \ref NVML_FI_DEV_NVLINK_COUNT_LOCAL_LINK_INTEGRITY_ERRORS to get Total number of times that the count of local errors exceeded a threshold + * - \ref NVML_FI_DEV_NVLINK_COUNT_XMIT_DISCARDS to get Total number of tx error packets that were discarded + * - \ref NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_SUCCESSFUL_EVENTS to get Number of times link went from Up to recovery, succeeded and link came back up + * - \ref NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_FAILED_EVENTS to get Number of times link went from Up to recovery, failed and link was declared down + * - \ref NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_EVENTS to get Number of times link went from Up to recovery, irrespective of the result + * - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE0 to get BER per lane for lane 0 + * - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER_LANE1 to get BER per lane for lane 1 + * - \ref NVML_FI_DEV_NVLINK_COUNT_RAW_BER to get BER per link. Sum of all the raw errors per lane/Bits received per link + * - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_ERRORS to get Sum of the number of errors in each Nvlink packet + * - \ref NVML_FI_DEV_NVLINK_COUNT_EFFECTIVE_BER to get Effective BER for effective errors + * - \ref NVML_FI_DEV_NVLINK_COUNT_SYMBOL_ERRORS to get Number of errors in rx symbols + * - \ref NVML_FI_DEV_NVLINK_COUNT_SYMBOL_BER to get BER for symbol errors + * - Added two new field ids NVML_FI_DEV_PCIE_COUNT_TX_BYTES and NVML_FI_DEV_PCIE_COUNT_RX_BYTES for nvmlDeviceGetFieldValues. + * - Added new API nvmlDeviceGetCapabilities with the first capability bit NVML_DEV_CAP_EGM for Extended GPU Memory (EGM) capability. + * - Added multiGpuMode display on CC enabled system via new API nvmlSystemGetConfComputeSettings or "nvidia-smi conf-compute --get-multigpu-mode" or "nvidia-smi conf-compute -mgm". + * - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MAX to get the Max Nvlink Power Threshold for a device. + * - Deprecated \ref nvmlDeviceGetTemperature and replaced with a new API \ref nvmlDeviceGetTemperatureV to retrieve device temperature. + * - Added new field ID \ref NVML_VGPU_DRIVER_CAP_WARM_UPDATE and NVML_DEVICE_VGPU_CAP_WARM_UPDATE to query whether the driver and the device supports FSR and warm update of vGPU host driver without terminating the running guest VM respectively. + * - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MIN to get the Min Nvlink Power Threshold for a device. + * - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_UNITS to get the Units of the Nvlink Power Threshold for a device. + * - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_SUPPORTED to get if Nvlink Power Threshold is supported for a device. + * + * + * \section changelog26 Changes between NVML v545 Update and v550 === + * + * - Added \ref nvmlDeviceGetNumaNodeId to query the NUMA node of a GPU. + * - Fix the issue where PCIe throughput (reported via nvmlDeviceGetPcieThroughput and nvidia-smi -q) is 1000 times bigger than its actual value. + * - Added new GPM metric Id NVML_GPM_METRIC_NVOFA_1_UTIL to \ref nvmlGpmMetricId_t. + * - Added new field ID \ref NVML_FI_DEV_IS_MIG_MODE_INDEPENDENT_MIG_QUERY_CAPABLE, to check MIG query capable device irrespective of MIG mode. + * - Deprecated NVML_P2P_CAPS_INDEX_PROP and added NVML_P2P_CAPS_INDEX_PCI to reflect the same P2P capability. + * - Added \ref nvmlDeviceGetProcessesUtilizationInfo to retrieve the recent utilization and process ID for all running processes. + * - Added new struct \ref nvmlProcessesUtilizationInfo_v1_t, which includes the new utilization of NVJPG and NVOFA. + * - Added \ref nvmlDeviceGetVgpuInstancesUtilizationInfo to retrieve the recent utilization for vGPU instances running on a physical GPU. + * - Added \ref nvmlDeviceGetVgpuProcessesUtilizationInfo to retrieve the recent utilization for processes running on vGPU instances on a physical GPU. + * - Added \ref nvmlDeviceSetVgpuHeterogeneousMode to enable or disable vGPU heterogenous mode for the device. + * - Added \ref nvmlDeviceGetVgpuHeterogeneousMode to query the vGPU heterogenous mode for the device. + * - Added \ref nvmlVgpuInstanceGetPlacementId to query placement ID of the active vGPU instance. + * - Added \ref nvmlDeviceGetVgpuTypeSupportedPlacements to query the supported vGPU placement IDs of a vGPU type. + * - Added \ref nvmlDeviceGetVgpuTypeCreatablePlacements to query the creatable vGPU placement IDs of a vGPU type. + * - Added support to display confidential compute protected memory along with fb & bar1 in nvidia-smi pmon & dmon commands. + * - Added \ref nvmlDeviceGetGpuFabricInfoV to query Gpu Fabric Probe Info for the device. + * - Deprecated \ref nvmlDeviceGetGpuFabricInfo. This function should not be used, and will be removed in a future release. Use \ref nvmlDeviceGetGpuFabricInfoV instead. + * - Modified \ref nvmlDeviceGetGpuInstanceProfileInfo and \ref nvmlDeviceGetGpuInstancePossiblePlacements_v2 to no longer require MIG being enabled + * - Added \ref nvmlSystemSetConfComputeKeyRotationThresholdInfo to set confidential compute key rotation threshold. + * - Added \ref nvmlSystemGetConfComputeKeyRotationThresholdInfo to query confidential compute key rotation threshold detail. + * - Added \ref nvmlDeviceSetVgpuCapabilities to set the desirable vGPU capability of a device. + * + * + * \section changelog25 Changes between NVML v535 Update and v545 === + * + * - Added a new error code \ref NVML_ERROR_GPU_NOT_FOUND to be returned if no supported GPUS are found during initialization. + * - In \ref nvmlGpuFabricInfo_t \p partitionId has been renamed to \p cliqueId. + * - Added new versioned structs \ref nvmlGpuInstanceProfileInfo_v3_t and \ref nvmlComputeInstanceProfileInfo_v3_t. + * - Added \ref nvmlDeviceGetLastBBXFlushTime for retrieving the timestamp and duration of the latest flush of the BBX object to the inforom storage. + * - Added \ref NVML_POWER_SCOPE_MEMORY to report out power usage for GPU Memory. + * - Added \ref nvmlDeviceGetPciInfoExt which expands \ref nvmlDeviceGetPciInfo_v3 to also report PCI base and sub classcodes. + * - Added new struct \ref nvmlPciInfoExt_v1_t, which is used in \ref nvmlDeviceGetPciInfoExt. + * - Added \ref nvmlDeviceGetRunningProcessDetailList api to get information about Compute, Graphics or MPS-Compute processes running on a GPU with protected memory usage info. + * + * + * \section changelog24 Changes between NVML v530 Update and v535 === + * + * - Fixed \ref nvmlDeviceGetMemoryErrorCounter and \ref nvmlDeviceGetFieldValues to return correct SRAM volatile total error counts. + * - Added \ref nvmlDeviceGetSramEccErrorStatus to query SRAM ECC error status for the device. + * - Added \ref nvmlDeviceGetModuleId for getting device module id + * - Updated \ref nvmlDeviceGetPowerSource API to report undersized power source. + * - Added \ref nvmlDeviceGetJpgUtilization and \ref nvmlDeviceGetOfaUtilization APIs + * - Added \ref nvmlSystemGetNvlinkBwMode and \ref nvmlSystemSetNvlinkBwMode APIs + * - Added \ref nvmlDeviceSetVgpuSchedulerState to set the vGPU scheduler state. + * - Added new field ID \ref NVML_FI_DEV_IS_RESETLESS_MIG_SUPPORTED for device's resetless MIG capability + * - Added \ref nvmlDeviceGetComputeRunningProcesses_v3 to get information about Compute processes running on a GPU. + * - Added \ref nvmlDeviceGetGraphicsRunningProcesses_v3 to get information about Graphics processes running on a GPU. + * - Added \ref nvmlDeviceGetMPSComputeRunningProcesses_v3 to get information about MPS-Compute processes running on a GPU. + * - Added \ref nvmlDeviceGetRunningProcessDetailList to get information about Compute, Graphics or MPS-Compute processes running on a GPU with protected memory usage info. Currently returns NVML_ERROR_NOT_SUPPORTED. Functionality will be implemented in next release. + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_CORRECTABLE_ERRORS for PCIe correctable errors counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_NAKS_RECEIVED for PCIe NAK Receive counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_RECEIVER_ERROR for PCIe receiver error counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_BAD_TLP for PCIe bad TLP counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_NAKS_SENT for NAK Send counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_BAD_DLLP for PCIe bad DLLP counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_NON_FATAL_ERROR for PCIe non fatal error counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_FATAL_ERROR for PCIe fatal error counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_UNSUPPORTED_REQ for PCIe unsupported request counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_LCRC_ERROR for PCIe LCRC error counter + * - Added new field ID \ref NVML_FI_DEV_PCIE_COUNT_LANE_ERROR for per lane error counter with scope as PCIe lane number. + * - Added \ref nvmlDeviceGetPowerUsage to retrieve current power usage + * - Added \ref nvmlDeviceGetTotalEnergyConsumption to get current energy consumption + * - Added \ref nvmlDeviceSetPowerManagementLimit_v2 to set the power limit + * - Renamed nvmlDeviceCcuGetStreamState to nvmlGpmQueryIfStreamingEnabled and nvmlDeviceCcuSetStreamState to nvmlGpmSetStreamingEnabled. + * + * + * \section changelog23 Changes between NVML v525 Update and v530 === + * + * - Fixed a typo in nvmlGpuP2PStatus_t: added a new enum entry for NVML_P2P_STATUS_CHIPSET_NOT_SUPPORTED with the same numeric value as the existing erroneous entry ("NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED") + * - Added \ref nvmlDeviceGetVgpuSchedulerLog to fetch the vGPU software scheduler logs. + * - Added \ref nvmlDeviceGetVgpuSchedulerState to fetch the vGPU software scheduler state. + * - Added \ref nvmlDeviceGetVgpuSchedulerCapabilities to fetch the vGPU software scheduler capabilities. + * + * + * \section changelog22 Changes between NVML v520 Update and v525 === + * + * - Added \ref nvmlDeviceSetNvLinkDeviceLowPowerThreshold to set the NvLink low power threshold. + * - Added \p nvmlDeviceGetPcieAtomicCaps to report PCIe atomic capabilities. + * - Added \p nvmlDeviceCcuGetStreamState API to report the counter collection unit stream state. + * - Added \p nvmlDeviceCcuSetStreamState API to set the counter collection unit stream state. + * - Removed support for NVML_FI_DEV_LINK_SPEED_MBPS_L{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_GET_SPEED with scope as link Id. + * - Removed support for NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_ERROR_DL_CRC with scope as link Id. + * - Removed support for NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_ERROR_DL_REPLAY with scope as link Id. + * - Removed support for NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_{0..} field Ids in Hopper. Replaced with NVML_FI_DEV_NVLINK_ERROR_DL_RECOVERY with scope as link Id. + * - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_STATE to get nvlink state + * - Added new field ID \ref NVML_FI_DEV_NVLINK_GET_VERSION to get nvlink version + * - Added new field ID \ref NVML_FI_DEV_C2C_LINK_COUNT to get C2C link count + * - Added new field ID \ref NVML_FI_DEV_C2C_LINK_GET_STATUS to get C2C link status + * - Added new field ID \ref NVML_FI_DEV_C2C_LINK_GET_MAX_BW to get C2C link bandwidth + * + * + * \section changelog21 Changes between NVML v515 Update and v520 === + * + * - Added \ref nvmlDeviceGetMemClkVfOffset API to report the MemClk VF offset value. + * - Added \ref nvmlDeviceGetMemClkMinMaxVfOffset API to report the Memory clock min and max VF offset that user can set for a specified GPU. + * - Added \ref nvmlDeviceGetGpcClkMinMaxVfOffset API to report the Graphics clock min and max VF offset that user can set for a specified GPU. + * - Added \ref nvmlGpmMetricsGet to calculate GPM metrics from two GPM samples + * - Added \ref nvmlGpmSampleFree to free allocated GPM sample + * - Added \ref nvmlGpmSampleAlloc to allocate a GPM sample + * - Added \ref nvmlGpmSampleGet to retrieve a GPM snapshot + * - Added \ref nvmlGpmQueryDeviceSupport to query whether a device supports GPM + * - Added \ref nvmlDeviceGetFanControlPolicy_v2 API to report the control policy for a specified GPU fan. + * - Added \ref nvmlDeviceSetFanControlPolicy API to set the control policy for a specified GPU fan. + * + * + * \section changelog20 Changes between NVML v510 Update and v515 === + * + * - Added \ref nvmlDeviceGetMinMaxClockOfPState API to report the min and max clocks of some clock domain for a given PState. + * - Added \ref nvmlDeviceGetSupportedPerformanceStates API to get all supported Performance States (P-States) for the GPU. + * - Added \ref nvmlDeviceGetGpcClkVfOffset API to report the GPCCLK VF offset value. + * - Added \ref nvmlDeviceGetMinMaxFanSpeed API to report the min and max fan speed that user can set for a specified GPU fan. + * + * + * \section changelog19 Changes between NVML v495 Update and v510 === + * + * - Added \ref nvmlDeviceGetGpuInstanceProfileInfoV and \ref nvmlGpuInstanceGetComputeInstanceProfileInfoV APIs to include the profile name in their output. + * - Added \ref nvmlDeviceGetMemoryBusWidth API to report the GPU's Memory Bus Width. + * - Added \ref nvmlDeviceGetPcieLinkMaxSpeed API to report the GPU's PCIe Max Speed. + * - Added \ref nvmlDeviceGetPowerSource API to report the GPU's power source as AC or battery. + * - Added \ref nvmlDeviceGetNumFans API to report the GPU's number of fans. + * - Added \ref nvmlDeviceGetNumGpuCores API to report the GPU's number of cores. + * - Added \ref nvmlDeviceGetMemoryInfo_v2. The new version accounts separately for system-reserved memory, and includes it in the used memory amount. The previous version of the API reduced the total memory amount by the amount of system-reserved memory. + * - Added \ref nvmlDeviceGetAdaptiveClockInfoStatus API to report the status of adaptive clocking for the GPU. + * + * + * \section changelog18 Changes between NVML v465 Update and v470 === + * + * - Added new MIG GPU instance profile NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV1. + * - Added \ref nvmlDeviceGetGpuInstancePossiblePlacements_v2. The previous version of the API will not support the profiles with possible placements greater than its total capacity, such as NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV1. + * + * + * \section changelog17 Changes between NVML v460 Update and v465 === + * + * - Added new NVML_BRAND_* enumeration values for NVIDIA, NVIDIA_RTX, GEFORCE_RTX, QUADRO_RTX and TITAN_RTX + * - Updated \ref nvmlDeviceGetHandleByUUID to make it MIG-aware. + * - Updated \ref nvmlDeviceGetUUID to return MIG UUIDs in the canonical format, 'MIG-UUID'. + * - Updated \ref nvmlDeviceGetHandleByUUID to accept both UUID formats, 'MIG-UUID' and 'MIG-GPU UUID/GID/CID'. + * - The \ref nvmlDeviceSetAPIRestriction and \ref nvmlDeviceGetAPIRestriction APIs would no longer support the ability to toggle root-only requirement for \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks. + * + * + * \section changelog16 Changes between NVML v450 Update and v460 === + * + * - Added \ref nvmlDeviceCreateGpuInstanceWithPlacement to allow placement specification when creating a new MIG GPU instance. + * + * + * \section changelog15 Changes between NVML v445 Update and v450 === + * + * - Updated \ref nvmlDeviceGetFanSpeed and \ref nvmlDeviceGetFanSpeed_v2 for allowing fan speeds greater than 100% to be reported. + * - Added \ref nvmlDeviceGetCpuAffinityWithinScope to determine the closest processor(s) within a NUMA node or socket. + * - Added \ref nvmlDeviceGetMemoryAffinity to determine the closest NUMA node(s) within a NUMA node or socket. + * - Added support to query and disable MIG mode on Windows. + * + * + * \section changelog14 Changes between NVML v418 Update and v445 === + * + * - Added support for NVIDIA Ampere architecture. + * - Added support for Multi Instance GPU management. Refer "Multi Instance GPU Management" section for details. + * + * + * \section changelog13 Changes between NVML v361 Update and v418 + * + * - Support for Volta and Turing architectures, bug fixes, performance improvements, and new features + * + * + * \section changelog12 Changes between NVML v349 Update and v361 + * + * - Added \ref nvmlDeviceGetBoardPartNumber to return GPU part numbers + * - Removed support for exclusive thread compute mode (Deprecated in 7.5) + * - Added NVML_CLOCK_VIDEO (encoder/decoder) clock type as a supported clock type for \ref nvmlDeviceGetClockInfo and \ref nvmlDeviceGetMaxClockInfo. + * + * + * \section changelog11 Changes between NVML v346 Update and v349 + * + * The following new functionality is exposed on NVIDIA display drivers version 349 Production or later + * - Updated \ref nvmlDeviceGetMemoryInfo to report Used/Free memory under Windows WDDM mode + * - Added \ref nvmlDeviceGetTopologyCommonAncestor to find the common path between two devices + * - Added \ref nvmlDeviceGetTopologyNearestGpus to get a set of GPUs given a path level + * - Added \ref nvmlSystemGetTopologyGpuSet to retrieve a set of GPUs with a given CPU affinity + * - Updated \ref nvmlDeviceGetAccountingPids, \ref nvmlDeviceGetAccountingBufferSize and \ref nvmlDeviceGetAccountingStats to report accounting information for both active and terminated processes. The execution time field in \ref nvmlAccountingStats_t structure is populated only when the process is terminated. + * + * + * \section changelog10 Changes between NVML v340 Update and v346 + * + * The following new functionality is exposed on NVIDIA display drivers version 346 Production or later + * - added the public APIs nvmlDeviceGetPcieReplayCounter and nvmlDeviceGetPcieThroughput + * - Discontinued Perl bindings support + * - Added \p nvmlDeviceGetGraphicsRunningProcesses_v2 to get information about Graphics processes running on a GPU. + * + * + * \section changelog9 Changes between NVML v331 Update and v340 + * + * The following new functionality is exposed on NVIDIA display drivers version 340 Production or later + * - Added \ref nvmlDeviceGetSamples to get recent power, utilization and clock samples for the GPU. + * - Added \ref nvmlDeviceGetTemperatureThreshold to retrieve temperature threshold information. + * - Added \ref nvmlDeviceGetBrand to retrieve brand information (e.g. Tesla, Quadro, etc.) + * - Added support for K40d and K80 + * - Added nvmlDeviceGetTopology internal API to retrieve path info between PCI devices (remove this for DITA) + * - Added \ref nvmlDeviceGetViolationStatus to get the duration of time during which the device was throttled (lower than requested clocks) due to thermal or power constraints. + * - Added \ref nvmlDeviceGetEncoderUtilization and \ref nvmlDeviceGetDecoderUtilization APIs + * - Added \ref nvmlDeviceGetCpuAffinity to determine the closest processor(s) affinity to a specific GPU + * - Added \ref nvmlDeviceSetCpuAffinity to bind a specific GPU to the closest processor + * - Added \ref nvmlDeviceClearCpuAffinity to unbind a specific GPU + * - Added \ref nvmlDeviceGetBoardId to get a unique boardId for the running system + * - Added \ref nvmlDeviceGetMultiGpuBoard to get whether the device is on a multiGPU board + * - Added \ref nvmlDeviceGetAutoBoostedClocksEnabled and nvmlDeviceSetAutoBoostedClocksEnabled for querying and setting the state of auto boosted clocks on supporting hardware. + * - Added \ref nvmlDeviceSetDefaultAutoBoostedClocksEnabled for setting the default state of auto boosted clocks on supporting hardware. + * + * + * \section changelog8 Changes between NVML v5.319 Update and v331 + * + * The following new functionality is exposed on NVIDIA display drivers version 331 Production or later + * - Added \ref nvmlDeviceGetMinorNumber to get the minor number for the device. + * - Added \ref nvmlDeviceGetBAR1MemoryInfo to get BAR1 total, available and used memory size. + * - Added \ref nvmlDeviceGetBridgeChipInfo to get the information related to bridge chip firmware. + * - Added enforced power limit query API \ref nvmlDeviceGetEnforcedPowerLimit + * - Updated \ref nvmlEventSetWait_v2 to return xid event data in case of xid error event. + * - Added support for K8 + * + * \section changelog7 Changes between NVML v5.319 RC and v5.319 Update + * + * The following new functionality is exposed on NVIDIA display drivers version 319 Update or later + * + * - Added \ref nvmlDeviceSetAPIRestriction and \ref nvmlDeviceGetAPIRestriction, with initial ability to toggle root-only requirement for \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks. + * + * \section changelog6 Changes between NVML v4.304 and v5.319 RC + * + * The following new functionality is exposed on NVIDIA display drivers version 319 Production or later + * + * - IMPORTANT: Added _v2 versions of \ref nvmlDeviceGetHandleByIndex_v2 and \ref nvmlDeviceGetCount_v2 that also count devices not accessible by current user + * - IMPORTANT: nvmlDeviceGetHandleByIndex_v2 (default) can also return NVML_ERROR_NO_PERMISSION + * - Added nvmlInit_v2 and nvmlDeviceGetHandleByIndex_v2 that is safer and thus recommended function for initializing the library + * - nvmlInit_v2 lazily initializes only requested devices (queried with nvmlDeviceGetHandle*) + * - nvml.h defines nvmlInit_v2 and nvmlDeviceGetHandleByIndex_v2 as default functions + * - Added \ref nvmlDeviceGetIndex + * - Added \ref NVML_ERROR_GPU_IS_LOST to report GPUs that have fallen off the bus. + * - Note: All NVML device APIs can return this error code, as a GPU can fall off the bus at any time. + * - Added new class of APIs for gathering process statistics (\ref nvmlAccountingStats) + * - Application Clocks are no longer supported on GPU's from Quadro product line + * - Added APIs to support dynamic page retirement. See \ref nvmlDeviceGetRetiredPages and + * \ref nvmlDeviceGetRetiredPagesPendingStatus + * - Renamed nvmlClocksThrottleReasonUserDefinedClocks to nvmlClocksThrottleReasonApplicationsClocksSetting. Old name is deprecated and can be removed in one of the next major releases. + * - Added \ref nvmlDeviceGetDisplayActive and updated documentation to clarify how it differs from \ref nvmlDeviceGetDisplayMode + * + * \section changelog5 Changes between NVML v4.304 RC and v4.304 Production + * + * The following new functionality is exposed on NVIDIA display drivers version 304 Production or later + * + * - Added \ref nvmlDeviceGetGpuOperationMode and \ref nvmlDeviceSetGpuOperationMode + * + * \section changelog4 Changes between NVML v3.295 and v4.304 RC + * + * The following new functionality is exposed on NVIDIA display drivers version 304 RC or later + * + * - Added \ref nvmlDeviceGetInforomConfigurationChecksum and \ref nvmlDeviceValidateInforom + * - Added new error return value for initialization failure due to kernel module not receiving interrupts + * - Added \ref nvmlDeviceSetApplicationsClocks, \ref nvmlDeviceGetApplicationsClock, \ref nvmlDeviceResetApplicationsClocks + * - Added \ref nvmlDeviceGetSupportedMemoryClocks and \ref nvmlDeviceGetSupportedGraphicsClocks + * - Added \ref nvmlDeviceGetPowerManagementLimitConstraints, \ref nvmlDeviceGetPowerManagementDefaultLimit and \ref nvmlDeviceSetPowerManagementLimit + * - Added \ref nvmlDeviceGetInforomImageVersion + * - Expanded \ref nvmlDeviceGetUUID to support all CUDA capable GPUs + * - Deprecated \ref nvmlDeviceGetDetailedEccErrors in favor of \ref nvmlDeviceGetMemoryErrorCounter + * - Added \ref NVML_MEMORY_LOCATION_TEXTURE_MEMORY to support reporting of texture memory error counters + * - Added \ref nvmlDeviceGetCurrentClocksThrottleReasons and \ref nvmlDeviceGetSupportedClocksThrottleReasons + * - \ref NVML_CLOCK_SM is now also reported on supported Kepler devices. + * - Dropped support for GT200 based Tesla brand GPUs: C1060, M1060, S1070 + * + * \section changelog3 Changes between NVML v2.285 and v3.295 + * + * The following new functionality is exposed on NVIDIA display drivers version 295 or later + * + * - deprecated \ref nvmlDeviceGetHandleBySerial in favor of newly added \ref nvmlDeviceGetHandleByUUID + * - Marked the input parameters of \ref nvmlDeviceGetHandleBySerial, \ref nvmlDeviceGetHandleByUUID and \ref nvmlDeviceGetHandleByPciBusId_v2 as const + * - Added \ref nvmlDeviceOnSameBoard + * - Added \ref nvmlConstants defines + * - Added \ref nvmlDeviceGetMaxPcieLinkGeneration, \ref nvmlDeviceGetMaxPcieLinkWidth, \ref nvmlDeviceGetCurrPcieLinkGeneration,\ref nvmlDeviceGetCurrPcieLinkWidth + * - Format change of \ref nvmlDeviceGetUUID output to match the UUID standard. This function will return a different value. + * - \ref nvmlDeviceGetDetailedEccErrors will report zero for unsupported ECC error counters when a subset of ECC error counters are supported + * \section changelog1 Changes between NVML v1.0 and v2.285 + * + * The following new functionality is exposed on NVIDIA display drivers version 285 or later + * + * - Added possibility to query separately current and pending driver model with \p nvmlDeviceGetDriverModel + * - Added API \ref nvmlDeviceGetVbiosVersion function to report VBIOS version. + * - Added pciSubSystemId to \ref nvmlPciInfo_t struct + * - Added API \ref nvmlErrorString function to convert error code to string + * - Updated docs to indicate we support M2075 and C2075 + * - Added API \ref nvmlSystemGetHicVersion function to report HIC firmware version + * - Added NVML versioning support + * - Functions that changed API and/or size of structs have appended versioning suffix + * (e.g. nvmlDeviceGetPciInfo_v2). Appropriate C defines have been + * added that map old function names to the newer version of the function + * - Added support for concurrent library usage by multiple libraries + * - Added API \ref nvmlDeviceGetMaxClockInfo function for reporting device's clock limits + * - Added new error code NVML_ERROR_DRIVER_NOT_LOADED used by \ref nvmlInit_v2 + * - Extended \ref nvmlPciInfo_t struct with new field: sub system id + * - Added NVML support on Windows guest account + * - Changed format of pciBusId string (to XXXX:XX:XX.X) of \ref nvmlPciInfo_t + * - Parsing of busId in \ref nvmlDeviceGetHandleByPciBusId_v2 is less restrictive. You can pass 0:2:0.0 or 0000:02:00 and other variations + * - Added API for events waiting for GPU events (Linux only) see docs of \ref nvmlEvents + * - Added API \p nvmlDeviceGetComputeRunningProcesses_v2 and \ref nvmlSystemGetProcessName functions for looking up currently running compute applications + * - Deprecated \ref nvmlDeviceGetPowerState in favor of \ref nvmlDeviceGetPerformanceState. + * - Added \ref NVML_FI_DEV_POWER_REQUESTED_LIMIT to report out the power limit requested by the client. + */ diff --git a/pkgs/cuda-13.0/nvml/doc/nvml_deprecation_and_removal.txt b/pkgs/cuda-13.0/nvml/doc/nvml_deprecation_and_removal.txt new file mode 100644 index 0000000..23c1303 --- /dev/null +++ b/pkgs/cuda-13.0/nvml/doc/nvml_deprecation_and_removal.txt @@ -0,0 +1,33 @@ +/*! @page DeprecationNotices Deprecation and/or removal notices for the NVML library + * This chap†er lists the NVML functions marked for deprecation and/or removal. Starting from CUDA 13.1 deprecated functions will generate a compiler warning. Removed functions will return the NVML error code NVML_ERROR_DEPRECATED. + * + * \section depNotice1 CUDA 13.0 === + * The following functions are deprecated starting CUDA 13.0; they will be removed in CUDA 14.0. + * + * - nvmlDeviceSetApplicationsClocks + * - nvmlDeviceGetApplicationsClock + * - nvmlDeviceGetDefaultApplicationsClock + * - nvmlDeviceResetApplicationsClocks + * - nvmlDeviceGetViolationStatus + * - nvmlVgpuInstanceGetLicenseStatus + * - nvmlDeviceResetNvLinkUtilizationCounter + * - nvmlDeviceFreezeNvLinkUtilizationCounter + * - nvmlDeviceGetNvLinkUtilizationCounter + * - nvmlDeviceGetNvLinkUtilizationControl + * - nvmlDeviceSetNvLinkUtilizationControl + * - nvmlDeviceSetMemClkVfOffset + * - nvmlDeviceSetGpcClkVfOffset + * - nvmlDeviceGetGpuFabricInfo + * - nvmlDeviceGetDetailedEccErrors + * - nvmlDeviceGetPowerManagementMode + * - nvmlDeviceGetPowerState + * - nvmlDeviceGetSupportedClocksThrottleReasons + * - nvmlDeviceGetCurrentClocksThrottleReasons + * - nvmlDeviceGetTemperature + * - nvmlDeviceGetHandleBySerial + * + * The following data structures are deprecated starting CUDA 13.0 + * + * - nvmlGpuFabricInfo_v2_t + * + */ diff --git a/pkgs/cuda-13.0/nvml/example/Makefile b/pkgs/cuda-13.0/nvml/example/Makefile new file mode 100644 index 0000000..459db52 --- /dev/null +++ b/pkgs/cuda-13.0/nvml/example/Makefile @@ -0,0 +1,87 @@ +ARCH := $(shell getconf LONG_BIT) +OS := $(shell cat /etc/issue) + +ifneq (,$(wildcard /etc/redhat-release)) + RHEL_OS := $(shell cat /etc/redhat-release) +endif + +# Gets Driver Branch +DRIVER_BRANCH := $(shell nvidia-smi | grep Driver | cut -f 3 -d' ' | cut -f 1 -d '.') + +# Location of the CUDA Toolkit +CUDA_PATH ?= "/usr/local/cuda-8.0" + +ifeq (${ARCH},$(filter ${ARCH},32 64)) + # If correct architecture and libnvidia-ml library is not found + # within the environment, build using the stub library + + ifneq (,$(findstring Ubuntu,$(OS))) + DEB := $(shell dpkg -l | grep cuda) + ifneq (,$(findstring cuda, $(DEB))) + NVML_LIB := /usr/lib/nvidia-$(DRIVER_BRANCH) + else + NVML_LIB := /lib${ARCH} + endif + endif + + ifneq (,$(findstring SUSE,$(OS))) + RPM := $(shell rpm -qa cuda*) + ifneq (,$(findstring cuda, $(RPM))) + NVML_LIB := /usr/lib${ARCH} + else + NVML_LIB := /lib${ARCH} + endif + endif + + ifneq (,$(findstring CentOS,$(RHEL_OS))) + RPM := $(shell rpm -qa cuda*) + ifneq (,$(findstring cuda, $(RPM))) + NVML_LIB := /usr/lib${ARCH}/nvidia + else + NVML_LIB := /lib${ARCH} + endif + endif + + ifneq (,$(findstring Red Hat,$(RHEL_OS))) + RPM := $(shell rpm -qa cuda*) + ifneq (,$(findstring cuda, $(RPM))) + NVML_LIB := /usr/lib${ARCH}/nvidia + else + NVML_LIB := /lib${ARCH} + endif + endif + + ifneq (,$(findstring Fedora,$(RHEL_OS))) + RPM := $(shell rpm -qa cuda*) + ifneq (,$(findstring cuda, $(RPM))) + NVML_LIB := /usr/lib${ARCH}/nvidia + else + NVML_LIB := /lib${ARCH} + endif + endif + +else + NVML_LIB := ../../lib${ARCH}/stubs/ + $(info "libnvidia-ml.so.1" not found, using stub library.) +endif + +ifneq (${ARCH},$(filter ${ARCH},32 64)) + $(error Unknown architecture!) +endif + +NVML_LIB += ../lib/ +NVML_LIB_L := $(addprefix -L , $(NVML_LIB)) + +CFLAGS := -I ../../include -I ../include +LDFLAGS := -lnvidia-ml $(NVML_LIB_L) + +all: example supportedVgpus +example: example.o + $(CC) $< $(CFLAGS) $(LDFLAGS) -o $@ +supportedVgpus: supportedVgpus.o + $(CC) $< $(CFLAGS) $(LDFLAGS) -o $@ +clean: + -@rm -f example.o + -@rm -f example + -@rm -f supportedVgpus.o + -@rm -f supportedVgpus diff --git a/pkgs/cuda-13.0/nvml/example/README.txt b/pkgs/cuda-13.0/nvml/example/README.txt new file mode 100644 index 0000000..20fceb9 --- /dev/null +++ b/pkgs/cuda-13.0/nvml/example/README.txt @@ -0,0 +1,10 @@ +The NVIDIA GDK provides a simple example program that shows how to build an +NVML client. When running an NVML client while the GDK is installed, be +sure your library path first includes the actual NVML library (installed +with the driver), not the stub library that exists solely for +compilation on systems without an NVIDIA driver available. + +If you have installed this example code via your packaging system, +you should first copy it to a user directory before compilation. +The packaging system uninstall feature will not remove this directory if it +contains new files beyond what were installed as part of the GDK. diff --git a/pkgs/cuda-13.0/nvml/example/example.c b/pkgs/cuda-13.0/nvml/example/example.c new file mode 100644 index 0000000..9b7967a --- /dev/null +++ b/pkgs/cuda-13.0/nvml/example/example.c @@ -0,0 +1,180 @@ + /***************************************************************************\ +|* *| +|* Copyright 2010-2016 NVIDIA Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: *| +|* *| +|* This source code is subject to NVIDIA ownership rights under U.S. *| +|* and international Copyright laws. Users and possessors of this *| +|* source code are hereby granted a nonexclusive, royalty-free *| +|* license to use this code in individual and commercial software. *| +|* *| +|* NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE *| +|* CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR *| +|* IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH *| +|* REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF *| +|* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR *| +|* PURPOSE. IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, *| +|* INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES *| +|* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN *| +|* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *| +|* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE *| +|* CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial item" *| +|* as that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting *| +|* of "commercial computer software" and "commercial computer software *| +|* documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) *| +|* and is provided to the U.S. Government only as a commercial end item. *| +|* Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through *| +|* 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the *| +|* source code with only those rights set forth herein. *| +|* *| +|* Any use of this source code in individual and commercial software must *| +|* include, in the user documentation and internal comments to the code, *| +|* the above Disclaimer and U.S. Government End Users Notice. *| +|* *| +|* *| + \***************************************************************************/ + +#include +#include + +static const char * convertToComputeModeString(nvmlComputeMode_t mode) +{ + switch (mode) + { + case NVML_COMPUTEMODE_DEFAULT: + return "Default"; + case NVML_COMPUTEMODE_EXCLUSIVE_THREAD: + return "Exclusive_Thread"; + case NVML_COMPUTEMODE_PROHIBITED: + return "Prohibited"; + case NVML_COMPUTEMODE_EXCLUSIVE_PROCESS: + return "Exclusive Process"; + default: + return "Unknown"; + } +} + +int main(void) +{ + nvmlReturn_t result; + unsigned int device_count, i; + + // First initialize NVML library + result = nvmlInit(); + if (NVML_SUCCESS != result) + { + printf("Failed to initialize NVML: %s\n", nvmlErrorString(result)); + + printf("Press ENTER to continue...\n"); + getchar(); + return 1; + } + + result = nvmlDeviceGetCount(&device_count); + if (NVML_SUCCESS != result) + { + printf("Failed to query device count: %s\n", nvmlErrorString(result)); + goto Error; + } + printf("Found %u device%s\n\n", device_count, device_count != 1 ? "s" : ""); + + printf("Listing devices:\n"); + for (i = 0; i < device_count; i++) + { + nvmlDevice_t device; + char name[NVML_DEVICE_NAME_BUFFER_SIZE]; + nvmlPciInfo_t pci; + nvmlComputeMode_t compute_mode; + + // Query for device handle to perform operations on a device + // You can also query device handle by other features like: + // nvmlDeviceGetHandleBySerial + // nvmlDeviceGetHandleByPciBusId + result = nvmlDeviceGetHandleByIndex(i, &device); + if (NVML_SUCCESS != result) + { + printf("Failed to get handle for device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + + result = nvmlDeviceGetName(device, name, NVML_DEVICE_NAME_BUFFER_SIZE); + if (NVML_SUCCESS != result) + { + printf("Failed to get name of device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + + // pci.busId is very useful to know which device physically you're talking to + // Using PCI identifier you can also match nvmlDevice handle to CUDA device. + result = nvmlDeviceGetPciInfo(device, &pci); + if (NVML_SUCCESS != result) + { + printf("Failed to get pci info for device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + + printf("%u. %s [%s]\n", i, name, pci.busId); + + // This is a simple example on how you can modify GPU's state + result = nvmlDeviceGetComputeMode(device, &compute_mode); + if (NVML_ERROR_NOT_SUPPORTED == result) + printf("\t This is not CUDA capable device\n"); + else if (NVML_SUCCESS != result) + { + printf("Failed to get compute mode for device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + else + { + // try to change compute mode + printf("\t Changing device's compute mode from '%s' to '%s'\n", + convertToComputeModeString(compute_mode), + convertToComputeModeString(NVML_COMPUTEMODE_PROHIBITED)); + + result = nvmlDeviceSetComputeMode(device, NVML_COMPUTEMODE_PROHIBITED); + if (NVML_ERROR_NO_PERMISSION == result) + printf("\t\t Need root privileges to do that: %s\n", nvmlErrorString(result)); + else if (NVML_ERROR_NOT_SUPPORTED == result) + printf("\t\t Compute mode prohibited not supported. You might be running on\n" + "\t\t windows in WDDM driver model or on non-CUDA capable GPU\n"); + else if (NVML_SUCCESS != result) + { + printf("\t\t Failed to set compute mode for device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + else + { + printf("\t Restoring device's compute mode back to '%s'\n", + convertToComputeModeString(compute_mode)); + result = nvmlDeviceSetComputeMode(device, compute_mode); + if (NVML_SUCCESS != result) + { + printf("\t\t Failed to restore compute mode for device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + } + } + } + + result = nvmlShutdown(); + if (NVML_SUCCESS != result) + printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result)); + + printf("All done.\n"); + + printf("Press ENTER to continue...\n"); + getchar(); + return 0; + +Error: + result = nvmlShutdown(); + if (NVML_SUCCESS != result) + printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result)); + + printf("Press ENTER to continue...\n"); + getchar(); + return 1; +} diff --git a/pkgs/cuda-13.0/nvml/example/supportedVgpus.c b/pkgs/cuda-13.0/nvml/example/supportedVgpus.c new file mode 100644 index 0000000..fe9a094 --- /dev/null +++ b/pkgs/cuda-13.0/nvml/example/supportedVgpus.c @@ -0,0 +1,160 @@ + /***************************************************************************\ +|* *| +|* Copyright 2010-2016 NVIDIA Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: *| +|* *| +|* This source code is subject to NVIDIA ownership rights under U.S. *| +|* and international Copyright laws. Users and possessors of this *| +|* source code are hereby granted a nonexclusive, royalty-free *| +|* license to use this code in individual and commercial software. *| +|* *| +|* NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE *| +|* CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR *| +|* IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH *| +|* REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF *| +|* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR *| +|* PURPOSE. IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, *| +|* INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES *| +|* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN *| +|* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *| +|* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE *| +|* CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial item" *| +|* as that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting *| +|* of "commercial computer software" and "commercial computer software *| +|* documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) *| +|* and is provided to the U.S. Government only as a commercial end item. *| +|* Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through *| +|* 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the *| +|* source code with only those rights set forth herein. *| +|* *| +|* Any use of this source code in individual and commercial software must *| +|* include, in the user documentation and internal comments to the code, *| +|* the above Disclaimer and U.S. Government End Users Notice. *| +|* *| +|* *| + \***************************************************************************/ + +#include +#include +#include + +int main(void) +{ + nvmlReturn_t result; + unsigned int device_count, i; + + // First initialize NVML library + result = nvmlInit(); + if (NVML_SUCCESS != result) + { + printf("Failed to initialize NVML: %s\n", nvmlErrorString(result)); + return 1; + } + + result = nvmlDeviceGetCount(&device_count); + if (NVML_SUCCESS != result) + { + printf("Failed to query device count: %s\n", nvmlErrorString(result)); + goto Error; + } + + printf("Found %u device%s\n", device_count, device_count != 1 ? "s" : ""); + printf("Listing devices:\n"); + + for (i = 0; i < device_count; i++) + { + nvmlDevice_t device; + char name[NVML_DEVICE_NAME_BUFFER_SIZE]; + nvmlPciInfo_t pci; + + // Query for device handle to perform operations on a device + // You can also query device handle by other features like: + // nvmlDeviceGetHandleBySerial + // nvmlDeviceGetHandleByPciBusId + result = nvmlDeviceGetHandleByIndex(i, &device); + if (NVML_SUCCESS != result) + { + printf("Failed to get handle for device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + + result = nvmlDeviceGetName(device, name, NVML_DEVICE_NAME_BUFFER_SIZE); + if (NVML_SUCCESS != result) + { + printf("Failed to get name of device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + + // pci.busId is very useful to know which device physically you're talking to + // Using PCI identifier you can also match nvmlDevice handle to CUDA device. + result = nvmlDeviceGetPciInfo(device, &pci); + if (NVML_SUCCESS != result) + { + printf("Failed to get pci info for device %u: %s\n", i, nvmlErrorString(result)); + goto Error; + } + + printf("%u. %s [%s]\n", i, name, pci.busId); + + // This is an example to get the supported vGPUs type names + unsigned int vgpuCount = 0; + nvmlVgpuTypeId_t *vgpuTypeIds = NULL; + unsigned int j; + + result = nvmlDeviceGetSupportedVgpus(device, &vgpuCount, NULL); + if (NVML_ERROR_INSUFFICIENT_SIZE != result) + goto Error; + + if (vgpuCount != 0) + { + vgpuTypeIds = malloc(sizeof(nvmlVgpuTypeId_t) * vgpuCount); + if (!vgpuTypeIds) + { + printf("Memory allocation of %d bytes failed \n", (int)(sizeof(*vgpuTypeIds)*vgpuCount)); + goto Error; + } + + result = nvmlDeviceGetSupportedVgpus(device, &vgpuCount, vgpuTypeIds); + if (NVML_SUCCESS != result) + { + printf("Failed to get the supported vGPUs with status %d \n", (int)result); + goto Error; + } + + printf(" Displaying vGPU type names: \n"); + for (j = 0; j < vgpuCount; j++) + { + char vgpuTypeName[NVML_DEVICE_NAME_BUFFER_SIZE]; + unsigned int bufferSize = NVML_DEVICE_NAME_BUFFER_SIZE; + + if (NVML_SUCCESS == (result = nvmlVgpuTypeGetName(vgpuTypeIds[j], vgpuTypeName, &bufferSize))) + { + printf(" %s\n",vgpuTypeName); + } + else + { + printf("Failed to query the vGPU type name with status %d \n", (int)result); + } + } + } + if (vgpuTypeIds) + free(vgpuTypeIds); + } + + result = nvmlShutdown(); + if (NVML_SUCCESS != result) + printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result)); + + printf("All done.\n"); + return 0; + +Error: + result = nvmlShutdown(); + if (NVML_SUCCESS != result) + printf("Failed to shutdown NVML: %s\n", nvmlErrorString(result)); + + return 1; +} diff --git a/pkgs/cuda-13.0/targets/x86_64-linux/include/nvml.h b/pkgs/cuda-13.0/targets/x86_64-linux/include/nvml.h new file mode 100644 index 0000000..5f6b9cf --- /dev/null +++ b/pkgs/cuda-13.0/targets/x86_64-linux/include/nvml.h @@ -0,0 +1,13607 @@ +/* + * Copyright 1993-2025 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO USER: + * + * This source code is subject to NVIDIA ownership rights under U.S. and + * international Copyright laws. Users and possessors of this source code + * are hereby granted a nonexclusive, royalty-free license to use this code + * in individual and commercial software. + * + * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE + * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR + * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + * OR PERFORMANCE OF THIS SOURCE CODE. + * + * U.S. Government End Users. This source code is a "commercial item" as + * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of + * "commercial computer software" and "commercial computer software + * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) + * and is provided to the U.S. Government only as a commercial end item. + * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through + * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the + * source code with only those rights set forth herein. + * + * Any use of this source code in individual and commercial software must + * include, in the user documentation and internal comments to the code, + * the above Disclaimer and U.S. Government End Users Notice. + */ + +/* +NVML API Reference + +The NVIDIA Management Library (NVML) is a C-based programmatic interface for monitoring and +managing various states within NVIDIA Tesla &tm; GPUs. It is intended to be a platform for building +3rd party applications, and is also the underlying library for the NVIDIA-supported nvidia-smi +tool. NVML is thread-safe so it is safe to make simultaneous NVML calls from multiple threads. + +API Documentation + +Supported platforms: +- Windows: Windows Server 2008 R2 64bit, Windows Server 2012 R2 64bit, Windows 7 64bit, Windows 8 64bit, Windows 10 64bit +- Linux: 32-bit and 64-bit +- Hypervisors: Windows Server 2008R2/2012 Hyper-V 64bit, Citrix XenServer 6.2 SP1+, VMware ESX 5.1/5.5 + +Supported products: +- Full Support + - All Tesla products, starting with the Fermi architecture + - All Quadro products, starting with the Fermi architecture + - All vGPU Software products, starting with the Kepler architecture + - Selected GeForce Titan products +- Limited Support + - All Geforce products, starting with the Fermi architecture + +The NVML library can be found at \%ProgramW6432\%\\"NVIDIA Corporation"\\NVSMI\\ on Windows. It is +not be added to the system path by default. To dynamically link to NVML, add this path to the PATH +environmental variable. To dynamically load NVML, call LoadLibrary with this path. + +On Linux the NVML library will be found on the standard library path. For 64 bit Linux, both the 32 bit +and 64 bit NVML libraries will be installed. + +Online documentation for this library is available at http://docs.nvidia.com/deploy/nvml-api/index.html +*/ + +#ifndef __nvml_nvml_h__ +#define __nvml_nvml_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * On Windows, set up methods for DLL export + * define NVML_STATIC_IMPORT when using nvml_loader library + */ +#if defined _WINDOWS + #if !defined NVML_STATIC_IMPORT + #if defined NVML_LIB_EXPORT + #define DECLDIR __declspec(dllexport) + #else + #define DECLDIR __declspec(dllimport) + #endif + #else + #define DECLDIR + #endif +#else + #define DECLDIR +#endif + +/* + * Deprecation definition. Starting CUDA 13.1 this will change to: + * #if defined _WINDOWS + * #define DEPRECATED(ver) __declspec(deprecated) + * #else + * #define DEPRECATED(ver) __attribute__((deprecated)) + * #endif + */ +#define DEPRECATED(ver) /* nop in CUDA 13.0, enabled in CUDA 13.1 */ + + #define NVML_MCDM_SUPPORT + +/** + * NVML API versioning support + */ +#define NVML_API_VERSION 13 +#define NVML_API_VERSION_STR "13" +/** + * Defining NVML_NO_UNVERSIONED_FUNC_DEFS will disable "auto upgrading" of APIs. + * e.g. the user will have to call nvmlInit_v2 instead of nvmlInit. Enable this + * guard if you need to support older versions of the API + */ +#ifndef NVML_NO_UNVERSIONED_FUNC_DEFS + #define nvmlInit nvmlInit_v2 + #define nvmlDeviceGetPciInfo nvmlDeviceGetPciInfo_v3 + #define nvmlDeviceGetCount nvmlDeviceGetCount_v2 + #define nvmlDeviceGetHandleByIndex nvmlDeviceGetHandleByIndex_v2 + #define nvmlDeviceGetHandleByPciBusId nvmlDeviceGetHandleByPciBusId_v2 + #define nvmlDeviceGetNvLinkRemotePciInfo nvmlDeviceGetNvLinkRemotePciInfo_v2 + #define nvmlDeviceRemoveGpu nvmlDeviceRemoveGpu_v2 + #define nvmlDeviceGetGridLicensableFeatures nvmlDeviceGetGridLicensableFeatures_v4 + #define nvmlEventSetWait nvmlEventSetWait_v2 + #define nvmlDeviceGetAttributes nvmlDeviceGetAttributes_v2 + #define nvmlComputeInstanceGetInfo nvmlComputeInstanceGetInfo_v2 + #define nvmlDeviceGetComputeRunningProcesses nvmlDeviceGetComputeRunningProcesses_v3 + #define nvmlDeviceGetGraphicsRunningProcesses nvmlDeviceGetGraphicsRunningProcesses_v3 + #define nvmlDeviceGetMPSComputeRunningProcesses nvmlDeviceGetMPSComputeRunningProcesses_v3 + #define nvmlBlacklistDeviceInfo_t nvmlExcludedDeviceInfo_t + #define nvmlGetBlacklistDeviceCount nvmlGetExcludedDeviceCount + #define nvmlGetBlacklistDeviceInfoByIndex nvmlGetExcludedDeviceInfoByIndex + #define nvmlDeviceGetGpuInstancePossiblePlacements nvmlDeviceGetGpuInstancePossiblePlacements_v2 + #define nvmlVgpuInstanceGetLicenseInfo nvmlVgpuInstanceGetLicenseInfo_v2 + #define nvmlDeviceGetDriverModel nvmlDeviceGetDriverModel_v2 +#endif // #ifndef NVML_NO_UNVERSIONED_FUNC_DEFS + +#define NVML_STRUCT_VERSION(data, ver) (unsigned int)(sizeof(nvml ## data ## _v ## ver ## _t) | \ + (ver << 24U)) + +/***************************************************************************************************/ +/** @defgroup nvmlDeviceStructs Device Structs + * @{ + */ +/***************************************************************************************************/ + +/** + * Special constant that some fields take when they are not available. + * Used when only part of the struct is not available. + * + * Each structure explicitly states when to check for this value. + */ +#define NVML_VALUE_NOT_AVAILABLE (-1) + +typedef struct nvmlDevice_st* nvmlDevice_t; + +typedef struct nvmlGpuInstance_st* nvmlGpuInstance_t; + +/** + * Buffer size guaranteed to be large enough for pci bus id + */ +#define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE 32 + +/** + * Buffer size guaranteed to be large enough for pci bus id for \p busIdLegacy + */ +#define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE 16 + +/** + * PCI information about a GPU device. + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + unsigned int domain; //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff + unsigned int bus; //!< The bus on which the device resides, 0 to 0xff + unsigned int device; //!< The device's id on the bus, 0 to 31 + + unsigned int pciDeviceId; //!< The combined 16-bit device id and 16-bit vendor id + unsigned int pciSubSystemId; //!< The 32-bit Sub System Device ID + + unsigned int baseClass; //!< The 8-bit PCI base class code + unsigned int subClass; //!< The 8-bit PCI sub class code + + char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (& NULL terminator) +} nvmlPciInfoExt_v1_t; +typedef nvmlPciInfoExt_v1_t nvmlPciInfoExt_t; +#define nvmlPciInfoExt_v1 NVML_STRUCT_VERSION(PciInfoExt, 1) + +/** + * PCI information about a GPU device. + */ +typedef struct nvmlPciInfo_st +{ + char busIdLegacy[NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE]; //!< The legacy tuple domain:bus:device.function PCI identifier (& NULL terminator) + unsigned int domain; //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff + unsigned int bus; //!< The bus on which the device resides, 0 to 0xff + unsigned int device; //!< The device's id on the bus, 0 to 31 + unsigned int pciDeviceId; //!< The combined 16-bit device id and 16-bit vendor id + + // Added in NVML 2.285 API + unsigned int pciSubSystemId; //!< The 32-bit Sub System Device ID + + char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (& NULL terminator) +} nvmlPciInfo_t; + +/** + * PCI format string for \p busIdLegacy + */ +#define NVML_DEVICE_PCI_BUS_ID_LEGACY_FMT "%04X:%02X:%02X.0" + +/** + * PCI format string for \p busId + */ +#define NVML_DEVICE_PCI_BUS_ID_FMT "%08X:%02X:%02X.0" + +/** + * Utility macro for filling the pci bus id format from a nvmlPciInfo_t + */ +#define NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(pciInfo) (pciInfo)->domain, \ + (pciInfo)->bus, \ + (pciInfo)->device + +/** + * Detailed ECC error counts for a device. + * + * @deprecated Different GPU families can have different memory error counters + * See \ref nvmlDeviceGetMemoryErrorCounter + */ +typedef struct nvmlEccErrorCounts_st +{ + unsigned long long l1Cache; //!< L1 cache errors + unsigned long long l2Cache; //!< L2 cache errors + unsigned long long deviceMemory; //!< Device memory errors + unsigned long long registerFile; //!< Register file errors +} nvmlEccErrorCounts_t; + +/** + * Utilization information for a device. + * Each sample period may be between 1 second and 1/6 second, depending on the product being queried. + */ +typedef struct nvmlUtilization_st +{ + unsigned int gpu; //!< Percent of time over the past sample period during which one or more kernels was executing on the GPU + unsigned int memory; //!< Percent of time over the past sample period during which global (device) memory was being read or written +} nvmlUtilization_t; + +/** + * Memory allocation information for a device (v1). + * The total amount is equal to the sum of the amounts of free and used memory. + */ +typedef struct nvmlMemory_st +{ + unsigned long long total; //!< Total physical device memory (in bytes) + unsigned long long free; //!< Unallocated device memory (in bytes) + unsigned long long used; //!< Sum of Reserved and Allocated device memory (in bytes). + //!< Note that the driver/GPU always sets aside a small amount of memory for bookkeeping +} nvmlMemory_t; + +/** + * Memory allocation information for a device (v2). + * + * Version 2 adds versioning for the struct and the amount of system-reserved memory as an output. + */ +typedef struct nvmlMemory_v2_st +{ + unsigned int version; //!< Structure format version (must be 2) + unsigned long long total; //!< Total physical device memory (in bytes) + unsigned long long reserved; //!< Device memory (in bytes) reserved for system use (driver or firmware) + unsigned long long free; //!< Unallocated device memory (in bytes) + unsigned long long used; //!< Allocated device memory (in bytes). +} nvmlMemory_v2_t; + +#define nvmlMemory_v2 NVML_STRUCT_VERSION(Memory, 2) + +/** + * BAR1 Memory allocation Information for a device + */ +typedef struct nvmlBAR1Memory_st +{ + unsigned long long bar1Total; //!< Total BAR1 Memory (in bytes) + unsigned long long bar1Free; //!< Unallocated BAR1 Memory (in bytes) + unsigned long long bar1Used; //!< Allocated Used Memory (in bytes) +}nvmlBAR1Memory_t; + +/** + * Information about running compute processes on the GPU, legacy version + * for older versions of the API. + */ +typedef struct nvmlProcessInfo_v1_st +{ + unsigned int pid; //!< Process ID + unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. + //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported + //! because Windows KMD manages all the memory and not the NVIDIA driver +} nvmlProcessInfo_v1_t; + +/** + * Information about running compute processes on the GPU + */ +typedef struct nvmlProcessInfo_v2_st +{ + unsigned int pid; //!< Process ID + unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. + //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported + //! because Windows KMD manages all the memory and not the NVIDIA driver + unsigned int gpuInstanceId; //!< If MIG is enabled, stores a valid GPU instance ID. gpuInstanceId is set to + // 0xFFFFFFFF otherwise. + unsigned int computeInstanceId; //!< If MIG is enabled, stores a valid compute instance ID. computeInstanceId is set to + // 0xFFFFFFFF otherwise. +} nvmlProcessInfo_v2_t, nvmlProcessInfo_t; + +/** + * Information about running process on the GPU with protected memory + */ +typedef struct +{ + unsigned int pid; //!< Process ID + unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. + //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported + //! because Windows KMD manages all the memory and not the NVIDIA driver + unsigned int gpuInstanceId; //!< If MIG is enabled, stores a valid GPU instance ID. gpuInstanceId is + // set to 0xFFFFFFFF otherwise. + unsigned int computeInstanceId; //!< If MIG is enabled, stores a valid compute instance ID. computeInstanceId + // is set to 0xFFFFFFFF otherwise. + unsigned long long usedGpuCcProtectedMemory; //!< Amount of used GPU conf compute protected memory in bytes. +} nvmlProcessDetail_v1_t; + +/** + * Information about all running processes on the GPU for the given mode + */ +typedef struct +{ + unsigned int version; //!< Struct version, MUST be nvmlProcessDetailList_v1 + unsigned int mode; //!< Process mode(Compute/Graphics/MPSCompute) + unsigned int numProcArrayEntries; //!< Number of process entries in procArray + nvmlProcessDetail_v1_t *procArray; //!< Process array +} nvmlProcessDetailList_v1_t; + +typedef nvmlProcessDetailList_v1_t nvmlProcessDetailList_t; + +/** + * nvmlProcessDetailList version + */ +#define nvmlProcessDetailList_v1 NVML_STRUCT_VERSION(ProcessDetailList, 1) + +typedef struct nvmlDeviceAttributes_st +{ + unsigned int multiprocessorCount; //!< Streaming Multiprocessor count + unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count + unsigned int sharedDecoderCount; //!< Shared Decoder Engine count + unsigned int sharedEncoderCount; //!< Shared Encoder Engine count + unsigned int sharedJpegCount; //!< Shared JPEG Engine count + unsigned int sharedOfaCount; //!< Shared OFA Engine count + unsigned int gpuInstanceSliceCount; //!< GPU instance slice count + unsigned int computeInstanceSliceCount; //!< Compute instance slice count + unsigned long long memorySizeMB; //!< Device memory size (in MiB) +} nvmlDeviceAttributes_t; + +/** + * C2C Mode information for a device + */ +typedef struct +{ + unsigned int isC2cEnabled; +} nvmlC2cModeInfo_v1_t; + +#define nvmlC2cModeInfo_v1 NVML_STRUCT_VERSION(C2cModeInfo, 1) + +/** + * Enum to represent device addressing mode values + */ +typedef enum +{ + NVML_DEVICE_ADDRESSING_MODE_NONE = 0, //!< No active mode + NVML_DEVICE_ADDRESSING_MODE_HMM = 1, //!< Heterogeneous Memory Management mode + NVML_DEVICE_ADDRESSING_MODE_ATS = 2, //!< Address Translation Services mode +} nvmlDeviceAddressingModeType_t; + +/** + * Struct to represent device addressing mode information + */ +typedef struct +{ + unsigned int version; //!< API version + unsigned int value; //!< One of \ref nvmlDeviceAddressingModeType_t +} nvmlDeviceAddressingMode_v1_t; +typedef nvmlDeviceAddressingMode_v1_t nvmlDeviceAddressingMode_t; + +#define nvmlDeviceAddressingMode_v1 NVML_STRUCT_VERSION(DeviceAddressingMode, 1) + +/** + * Struct to represent the NVML repair status + */ +typedef struct +{ + unsigned int version; //!< API version number + unsigned int bChannelRepairPending; //!< Reference to \a unsigned int + unsigned int bTpcRepairPending; //!< Reference to \a unsigned int +} nvmlRepairStatus_v1_t; +typedef nvmlRepairStatus_v1_t nvmlRepairStatus_t; + +#define nvmlRepairStatus_v1 NVML_STRUCT_VERSION(RepairStatus, 1) + +/** + * Possible values that classify the remap availability for each bank. The max + * field will contain the number of banks that have maximum remap availability + * (all reserved rows are available). None means that there are no reserved + * rows available. + */ +typedef struct nvmlRowRemapperHistogramValues_st +{ + unsigned int max; + unsigned int high; + unsigned int partial; + unsigned int low; + unsigned int none; +} nvmlRowRemapperHistogramValues_t; + +/** + * Enum to represent type of bridge chip + */ +typedef enum nvmlBridgeChipType_enum +{ + NVML_BRIDGE_CHIP_PLX = 0, + NVML_BRIDGE_CHIP_BRO4 = 1 +}nvmlBridgeChipType_t; + +/** + * Maximum number of NvLink links supported + */ +#define NVML_NVLINK_MAX_LINKS 18 + +/** + * Enum to represent the NvLink utilization counter packet units + */ +typedef enum nvmlNvLinkUtilizationCountUnits_enum +{ + NVML_NVLINK_COUNTER_UNIT_CYCLES = 0, // count by cycles + NVML_NVLINK_COUNTER_UNIT_PACKETS = 1, // count by packets + NVML_NVLINK_COUNTER_UNIT_BYTES = 2, // count by bytes + NVML_NVLINK_COUNTER_UNIT_RESERVED = 3, // count reserved for internal use + // this must be last + NVML_NVLINK_COUNTER_UNIT_COUNT +} nvmlNvLinkUtilizationCountUnits_t; + +/** + * Enum to represent the NvLink utilization counter packet types to count + * ** this is ONLY applicable with the units as packets or bytes + * ** as specified in \a nvmlNvLinkUtilizationCountUnits_t + * ** all packet filter descriptions are target GPU centric + * ** these can be "OR'd" together + */ +typedef enum nvmlNvLinkUtilizationCountPktTypes_enum +{ + NVML_NVLINK_COUNTER_PKTFILTER_NOP = 0x1, // no operation packets + NVML_NVLINK_COUNTER_PKTFILTER_READ = 0x2, // read packets + NVML_NVLINK_COUNTER_PKTFILTER_WRITE = 0x4, // write packets + NVML_NVLINK_COUNTER_PKTFILTER_RATOM = 0x8, // reduction atomic requests + NVML_NVLINK_COUNTER_PKTFILTER_NRATOM = 0x10, // non-reduction atomic requests + NVML_NVLINK_COUNTER_PKTFILTER_FLUSH = 0x20, // flush requests + NVML_NVLINK_COUNTER_PKTFILTER_RESPDATA = 0x40, // responses with data + NVML_NVLINK_COUNTER_PKTFILTER_RESPNODATA = 0x80, // responses without data + NVML_NVLINK_COUNTER_PKTFILTER_ALL = 0xFF // all packets +} nvmlNvLinkUtilizationCountPktTypes_t; + +/** + * Struct to define the NVLINK counter controls + */ +typedef struct nvmlNvLinkUtilizationControl_st +{ + nvmlNvLinkUtilizationCountUnits_t units; + nvmlNvLinkUtilizationCountPktTypes_t pktfilter; +} nvmlNvLinkUtilizationControl_t; + +/** + * Enum to represent NvLink queryable capabilities + */ +typedef enum nvmlNvLinkCapability_enum +{ + NVML_NVLINK_CAP_P2P_SUPPORTED = 0, // P2P over NVLink is supported + NVML_NVLINK_CAP_SYSMEM_ACCESS = 1, // Access to system memory is supported + NVML_NVLINK_CAP_P2P_ATOMICS = 2, // P2P atomics are supported + NVML_NVLINK_CAP_SYSMEM_ATOMICS= 3, // System memory atomics are supported + NVML_NVLINK_CAP_SLI_BRIDGE = 4, // SLI is supported over this link + NVML_NVLINK_CAP_VALID = 5, // Link is supported on this device + // should be last + NVML_NVLINK_CAP_COUNT +} nvmlNvLinkCapability_t; + +/** + * Enum to represent NvLink queryable error counters + */ +typedef enum nvmlNvLinkErrorCounter_enum +{ + NVML_NVLINK_ERROR_DL_REPLAY = 0, // Data link transmit replay error counter + NVML_NVLINK_ERROR_DL_RECOVERY = 1, // Data link transmit recovery error counter + NVML_NVLINK_ERROR_DL_CRC_FLIT = 2, // Data link receive flow control digit CRC error counter + NVML_NVLINK_ERROR_DL_CRC_DATA = 3, // Data link receive data CRC error counter + NVML_NVLINK_ERROR_DL_ECC_DATA = 4, // Data link receive data ECC error counter + + // this must be last + NVML_NVLINK_ERROR_COUNT +} nvmlNvLinkErrorCounter_t; + +/** + * Enum to represent NvLink's remote device type + */ +typedef enum nvmlIntNvLinkDeviceType_enum +{ + NVML_NVLINK_DEVICE_TYPE_GPU = 0x00, + NVML_NVLINK_DEVICE_TYPE_IBMNPU = 0x01, + NVML_NVLINK_DEVICE_TYPE_SWITCH = 0x02, + NVML_NVLINK_DEVICE_TYPE_UNKNOWN = 0xFF +} nvmlIntNvLinkDeviceType_t; + +/** + * Represents level relationships within a system between two GPUs + * The enums are spaced to allow for future relationships + */ +typedef enum nvmlGpuLevel_enum +{ + NVML_TOPOLOGY_INTERNAL = 0, // e.g. Tesla K80 + NVML_TOPOLOGY_SINGLE = 10, // all devices that only need traverse a single PCIe switch + NVML_TOPOLOGY_MULTIPLE = 20, // all devices that need not traverse a host bridge + NVML_TOPOLOGY_HOSTBRIDGE = 30, // all devices that are connected to the same host bridge + NVML_TOPOLOGY_NODE = 40, // all devices that are connected to the same NUMA node but possibly multiple host bridges + NVML_TOPOLOGY_SYSTEM = 50 // all devices in the system + + // there is purposefully no COUNT here because of the need for spacing above +} nvmlGpuTopologyLevel_t; + +/* Compatibility for CPU->NODE renaming */ +#define NVML_TOPOLOGY_CPU NVML_TOPOLOGY_NODE + +/* P2P Capability Index Status*/ +typedef enum nvmlGpuP2PStatus_enum +{ + NVML_P2P_STATUS_OK = 0, + NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED, + NVML_P2P_STATUS_CHIPSET_NOT_SUPPORTED = NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED, + NVML_P2P_STATUS_GPU_NOT_SUPPORTED, + NVML_P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED, + NVML_P2P_STATUS_DISABLED_BY_REGKEY, + NVML_P2P_STATUS_NOT_SUPPORTED, + NVML_P2P_STATUS_UNKNOWN + +} nvmlGpuP2PStatus_t; + +/* P2P Capability Index*/ +typedef enum nvmlGpuP2PCapsIndex_enum +{ + NVML_P2P_CAPS_INDEX_READ = 0, + NVML_P2P_CAPS_INDEX_WRITE = 1, + NVML_P2P_CAPS_INDEX_NVLINK = 2, + NVML_P2P_CAPS_INDEX_ATOMICS = 3, + NVML_P2P_CAPS_INDEX_PCI = 4, + /* + * DO NOT USE! NVML_P2P_CAPS_INDEX_PROP is deprecated. + * Use NVML_P2P_CAPS_INDEX_PCI instead. + */ + NVML_P2P_CAPS_INDEX_PROP = NVML_P2P_CAPS_INDEX_PCI, + NVML_P2P_CAPS_INDEX_UNKNOWN = 5, +}nvmlGpuP2PCapsIndex_t; + +/** + * Maximum limit on Physical Bridges per Board + */ +#define NVML_MAX_PHYSICAL_BRIDGE (128) + +/** + * Information about the Bridge Chip Firmware + */ +typedef struct nvmlBridgeChipInfo_st +{ + nvmlBridgeChipType_t type; //!< Type of Bridge Chip + unsigned int fwVersion; //!< Firmware Version. 0=Version is unavailable +}nvmlBridgeChipInfo_t; + +/** + * This structure stores the complete Hierarchy of the Bridge Chip within the board. The immediate + * bridge is stored at index 0 of bridgeInfoList, parent to immediate bridge is at index 1 and so forth. + */ +typedef struct nvmlBridgeChipHierarchy_st +{ + unsigned char bridgeCount; //!< Number of Bridge Chips on the Board + nvmlBridgeChipInfo_t bridgeChipInfo[NVML_MAX_PHYSICAL_BRIDGE]; //!< Hierarchy of Bridge Chips on the board +}nvmlBridgeChipHierarchy_t; + +/** + * Represents Type of Sampling Event + */ +typedef enum nvmlSamplingType_enum +{ + NVML_TOTAL_POWER_SAMPLES = 0, //!< To represent total power drawn by GPU + NVML_GPU_UTILIZATION_SAMPLES = 1, //!< To represent percent of time during which one or more kernels was executing on the GPU + NVML_MEMORY_UTILIZATION_SAMPLES = 2, //!< To represent percent of time during which global (device) memory was being read or written + NVML_ENC_UTILIZATION_SAMPLES = 3, //!< To represent percent of time during which NVENC remains busy + NVML_DEC_UTILIZATION_SAMPLES = 4, //!< To represent percent of time during which NVDEC remains busy + NVML_PROCESSOR_CLK_SAMPLES = 5, //!< To represent processor clock samples + NVML_MEMORY_CLK_SAMPLES = 6, //!< To represent memory clock samples + NVML_MODULE_POWER_SAMPLES = 7, //!< To represent module power samples for total module starting Grace Hopper + NVML_JPG_UTILIZATION_SAMPLES = 8, //!< To represent percent of time during which NVJPG remains busy + NVML_OFA_UTILIZATION_SAMPLES = 9, //!< To represent percent of time during which NVOFA remains busy + + // Keep this last + NVML_SAMPLINGTYPE_COUNT +}nvmlSamplingType_t; + +/** + * Represents the queryable PCIe utilization counters + */ +typedef enum nvmlPcieUtilCounter_enum +{ + NVML_PCIE_UTIL_TX_BYTES = 0, // 1KB granularity + NVML_PCIE_UTIL_RX_BYTES = 1, // 1KB granularity + + // Keep this last + NVML_PCIE_UTIL_COUNT +} nvmlPcieUtilCounter_t; + +/** + * Represents the type for sample value returned + */ +typedef enum nvmlValueType_enum +{ + NVML_VALUE_TYPE_DOUBLE = 0, + NVML_VALUE_TYPE_UNSIGNED_INT = 1, + NVML_VALUE_TYPE_UNSIGNED_LONG = 2, + NVML_VALUE_TYPE_UNSIGNED_LONG_LONG = 3, + NVML_VALUE_TYPE_SIGNED_LONG_LONG = 4, + NVML_VALUE_TYPE_SIGNED_INT = 5, + NVML_VALUE_TYPE_UNSIGNED_SHORT = 6, + + // Keep this last + NVML_VALUE_TYPE_COUNT +}nvmlValueType_t; + +/** + * Union to represent different types of Value + */ +typedef union nvmlValue_st +{ + double dVal; //!< If the value is double + int siVal; //!< If the value is signed int + unsigned int uiVal; //!< If the value is unsigned int + unsigned long ulVal; //!< If the value is unsigned long + unsigned long long ullVal; //!< If the value is unsigned long long + signed long long sllVal; //!< If the value is signed long long + unsigned short usVal; //!< If the value is unsigned short +}nvmlValue_t; + +/** + * Information for Sample + */ +typedef struct nvmlSample_st +{ + unsigned long long timeStamp; //!< CPU Timestamp in microseconds + nvmlValue_t sampleValue; //!< Sample Value +}nvmlSample_t; + +/** + * Represents type of perf policy for which violation times can be queried + */ +typedef enum nvmlPerfPolicyType_enum +{ + NVML_PERF_POLICY_POWER = 0, //!< How long did power violations cause the GPU to be below application clocks + NVML_PERF_POLICY_THERMAL = 1, //!< How long did thermal violations cause the GPU to be below application clocks + NVML_PERF_POLICY_SYNC_BOOST = 2, //!< How long did sync boost cause the GPU to be below application clocks + NVML_PERF_POLICY_BOARD_LIMIT = 3, //!< How long did the board limit cause the GPU to be below application clocks + NVML_PERF_POLICY_LOW_UTILIZATION = 4, //!< How long did low utilization cause the GPU to be below application clocks + NVML_PERF_POLICY_RELIABILITY = 5, //!< How long did the board reliability limit cause the GPU to be below application clocks + + NVML_PERF_POLICY_TOTAL_APP_CLOCKS = 10, //!< Total time the GPU was held below application clocks by any limiter (0 - 5 above) + NVML_PERF_POLICY_TOTAL_BASE_CLOCKS = 11, //!< Total time the GPU was held below base clocks + + // Keep this last + NVML_PERF_POLICY_COUNT +}nvmlPerfPolicyType_t; + +/** + * Struct to hold perf policy violation status data + */ +typedef struct nvmlViolationTime_st +{ + unsigned long long referenceTime; //!< referenceTime represents CPU timestamp in microseconds + unsigned long long violationTime; //!< violationTime in Nanoseconds +}nvmlViolationTime_t; + +#define NVML_MAX_THERMAL_SENSORS_PER_GPU 3 + +/** + * Represents the thermal sensor targets + */ +typedef enum +{ + NVML_THERMAL_TARGET_NONE = 0, + NVML_THERMAL_TARGET_GPU = 1, //!< GPU core temperature requires NvPhysicalGpuHandle + NVML_THERMAL_TARGET_MEMORY = 2, //!< GPU memory temperature requires NvPhysicalGpuHandle + NVML_THERMAL_TARGET_POWER_SUPPLY = 4, //!< GPU power supply temperature requires NvPhysicalGpuHandle + NVML_THERMAL_TARGET_BOARD = 8, //!< GPU board ambient temperature requires NvPhysicalGpuHandle + NVML_THERMAL_TARGET_VCD_BOARD = 9, //!< Visual Computing Device Board temperature requires NvVisualComputingDeviceHandle + NVML_THERMAL_TARGET_VCD_INLET = 10, //!< Visual Computing Device Inlet temperature requires NvVisualComputingDeviceHandle + NVML_THERMAL_TARGET_VCD_OUTLET = 11, //!< Visual Computing Device Outlet temperature requires NvVisualComputingDeviceHandle + + NVML_THERMAL_TARGET_ALL = 15, + NVML_THERMAL_TARGET_UNKNOWN = -1, +} nvmlThermalTarget_t; + +/** + * Represents the thermal sensor controllers + */ +typedef enum +{ + NVML_THERMAL_CONTROLLER_NONE = 0, + NVML_THERMAL_CONTROLLER_GPU_INTERNAL, + NVML_THERMAL_CONTROLLER_ADM1032, + NVML_THERMAL_CONTROLLER_ADT7461, + NVML_THERMAL_CONTROLLER_MAX6649, + NVML_THERMAL_CONTROLLER_MAX1617, + NVML_THERMAL_CONTROLLER_LM99, + NVML_THERMAL_CONTROLLER_LM89, + NVML_THERMAL_CONTROLLER_LM64, + NVML_THERMAL_CONTROLLER_G781, + NVML_THERMAL_CONTROLLER_ADT7473, + NVML_THERMAL_CONTROLLER_SBMAX6649, + NVML_THERMAL_CONTROLLER_VBIOSEVT, + NVML_THERMAL_CONTROLLER_OS, + NVML_THERMAL_CONTROLLER_NVSYSCON_CANOAS, + NVML_THERMAL_CONTROLLER_NVSYSCON_E551, + NVML_THERMAL_CONTROLLER_MAX6649R, + NVML_THERMAL_CONTROLLER_ADT7473S, + NVML_THERMAL_CONTROLLER_UNKNOWN = -1, +} nvmlThermalController_t; + +/** + * Struct to hold the thermal sensor settings + */ +typedef struct +{ + unsigned int count; + struct + { + nvmlThermalController_t controller; + int defaultMinTemp; + int defaultMaxTemp; + int currentTemp; + nvmlThermalTarget_t target; + } sensor[NVML_MAX_THERMAL_SENSORS_PER_GPU]; + +} nvmlGpuThermalSettings_t; + +/** + * Cooler control type + */ +typedef enum nvmlCoolerControl_enum +{ + NVML_THERMAL_COOLER_SIGNAL_NONE = 0, //!< This cooler has no control signal. + NVML_THERMAL_COOLER_SIGNAL_TOGGLE = 1, //!< This cooler can only be toggled either ON or OFF (eg a switch). + NVML_THERMAL_COOLER_SIGNAL_VARIABLE = 2, //!< This cooler's level can be adjusted from some minimum to some maximum (eg a knob). + + // Keep this last + NVML_THERMAL_COOLER_SIGNAL_COUNT +} nvmlCoolerControl_t; + +/** + * Cooler's target + */ +typedef enum nvmlCoolerTarget_enum +{ + NVML_THERMAL_COOLER_TARGET_NONE = 1 << 0, //!< This cooler cools nothing. + NVML_THERMAL_COOLER_TARGET_GPU = 1 << 1, //!< This cooler can cool the GPU. + NVML_THERMAL_COOLER_TARGET_MEMORY = 1 << 2, //!< This cooler can cool the memory. + NVML_THERMAL_COOLER_TARGET_POWER_SUPPLY = 1 << 3, //!< This cooler can cool the power supply. + NVML_THERMAL_COOLER_TARGET_GPU_RELATED = (NVML_THERMAL_COOLER_TARGET_GPU | NVML_THERMAL_COOLER_TARGET_MEMORY | NVML_THERMAL_COOLER_TARGET_POWER_SUPPLY) //!< This cooler cools all of the components related to its target gpu. GPU_RELATED = GPU | MEMORY | POWER_SUPPLY +} nvmlCoolerTarget_t; + +typedef struct +{ + unsigned int version; //!< the API version number + unsigned int index; //!< the cooler index + nvmlCoolerControl_t signalType; //!< OUT: the cooler's control signal characteristics + nvmlCoolerTarget_t target; //!< OUT: the target that cooler cools +} nvmlCoolerInfo_v1_t; +typedef nvmlCoolerInfo_v1_t nvmlCoolerInfo_t; + +#define nvmlCoolerInfo_v1 NVML_STRUCT_VERSION(CoolerInfo, 1) + +/** + * UUID length in ASCII format + */ +#define NVML_DEVICE_UUID_ASCII_LEN 41 + +/** + * UUID length in binary format + */ +#define NVML_DEVICE_UUID_BINARY_LEN 16 + +/** + * Enum to represent different UUID types + */ +typedef enum +{ + NVML_UUID_TYPE_NONE = 0, //!< Undefined type + NVML_UUID_TYPE_ASCII = 1, //!< ASCII format type + NVML_UUID_TYPE_BINARY = 2, //!< Binary format type +} nvmlUUIDType_t; + +/** + * Union to represent different UUID values + */ +typedef union +{ + char str[NVML_DEVICE_UUID_ASCII_LEN]; //!< ASCII format value + unsigned char bytes[NVML_DEVICE_UUID_BINARY_LEN]; //!< Binary format value +} nvmlUUIDValue_t; + +/** + * Struct to represent NVML UUID information + */ +typedef struct +{ + unsigned int version; //!< API version number + unsigned int type; //!< One of \p nvmlUUIDType_t + nvmlUUIDValue_t value; //!< One of \p nvmlUUIDValue_t, to be set based on the UUID format +} nvmlUUID_v1_t; +typedef nvmlUUID_v1_t nvmlUUID_t; + +#define nvmlUUID_v1 NVML_STRUCT_VERSION(UUID, 1) + +/** + * Struct to represent the NVML PDI information + */ +typedef struct +{ + unsigned int version; //!< API version number + unsigned long long value; //!< 64-bit PDI value +} nvmlPdi_v1_t; +typedef nvmlPdi_v1_t nvmlPdi_t; + +#define nvmlPdi_v1 NVML_STRUCT_VERSION(Pdi, 1) + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlDeviceEnumvs Device Enums + * @{ + */ +/***************************************************************************************************/ + +/** + * Generic enable/disable enum. + */ +typedef enum nvmlEnableState_enum +{ + NVML_FEATURE_DISABLED = 0, //!< Feature disabled + NVML_FEATURE_ENABLED = 1 //!< Feature enabled +} nvmlEnableState_t; + +//! Generic flag used to specify the default behavior of some functions. See description of particular functions for details. +#define nvmlFlagDefault 0x00 +//! Generic flag used to force some behavior. See description of particular functions for details. +#define nvmlFlagForce 0x01 + +/** + * DRAM Encryption Info + */ +typedef struct +{ + unsigned int version; //!< IN - the API version number + nvmlEnableState_t encryptionState; //!< IN/OUT - DRAM Encryption state +} nvmlDramEncryptionInfo_v1_t; +typedef nvmlDramEncryptionInfo_v1_t nvmlDramEncryptionInfo_t; + +#define nvmlDramEncryptionInfo_v1 NVML_STRUCT_VERSION(DramEncryptionInfo, 1) + +/** + * * The Brand of the GPU + * */ +typedef enum nvmlBrandType_enum +{ + NVML_BRAND_UNKNOWN = 0, + NVML_BRAND_QUADRO = 1, + NVML_BRAND_TESLA = 2, + NVML_BRAND_NVS = 3, + NVML_BRAND_GRID = 4, // Deprecated from API reporting. Keeping definition for backward compatibility. + NVML_BRAND_GEFORCE = 5, + NVML_BRAND_TITAN = 6, + NVML_BRAND_NVIDIA_VAPPS = 7, // NVIDIA Virtual Applications + NVML_BRAND_NVIDIA_VPC = 8, // NVIDIA Virtual PC + NVML_BRAND_NVIDIA_VCS = 9, // NVIDIA Virtual Compute Server + NVML_BRAND_NVIDIA_VWS = 10, // NVIDIA RTX Virtual Workstation + NVML_BRAND_NVIDIA_CLOUD_GAMING = 11, // NVIDIA Cloud Gaming + NVML_BRAND_NVIDIA_VGAMING = NVML_BRAND_NVIDIA_CLOUD_GAMING, // Deprecated from API reporting. Keeping definition for backward compatibility. + NVML_BRAND_QUADRO_RTX = 12, + NVML_BRAND_NVIDIA_RTX = 13, + NVML_BRAND_NVIDIA = 14, + NVML_BRAND_GEFORCE_RTX = 15, // Unused + NVML_BRAND_TITAN_RTX = 16, // Unused + // Keep this last + NVML_BRAND_COUNT = 18, +} nvmlBrandType_t; + +/** + * Temperature thresholds. + */ +typedef enum nvmlTemperatureThresholds_enum +{ + NVML_TEMPERATURE_THRESHOLD_SHUTDOWN = 0, // Temperature at which the GPU will + // shut down for HW protection + NVML_TEMPERATURE_THRESHOLD_SLOWDOWN = 1, // Temperature at which the GPU will + // begin HW slowdown + NVML_TEMPERATURE_THRESHOLD_MEM_MAX = 2, // Memory Temperature at which the GPU will + // begin SW slowdown + NVML_TEMPERATURE_THRESHOLD_GPU_MAX = 3, // GPU Temperature at which the GPU + // can be throttled below base clock + NVML_TEMPERATURE_THRESHOLD_ACOUSTIC_MIN = 4, // Minimum GPU Temperature that can be + // set as acoustic threshold + NVML_TEMPERATURE_THRESHOLD_ACOUSTIC_CURR = 5, // Current temperature that is set as + // acoustic threshold. + NVML_TEMPERATURE_THRESHOLD_ACOUSTIC_MAX = 6, // Maximum GPU temperature that can be + // set as acoustic threshold. + NVML_TEMPERATURE_THRESHOLD_GPS_CURR = 7, // Current temperature that is set as + // gps threshold. + // Keep this last + NVML_TEMPERATURE_THRESHOLD_COUNT +} nvmlTemperatureThresholds_t; + +/** + * Temperature sensors. + */ +typedef enum nvmlTemperatureSensors_enum +{ + NVML_TEMPERATURE_GPU = 0, //!< Temperature sensor for the GPU die + + // Keep this last + NVML_TEMPERATURE_COUNT +} nvmlTemperatureSensors_t; + +/** + * Margin temperature values + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + int marginTemperature; //!< The margin temperature value +} nvmlMarginTemperature_v1_t; + +typedef nvmlMarginTemperature_v1_t nvmlMarginTemperature_t; + +#define nvmlMarginTemperature_v1 NVML_STRUCT_VERSION(MarginTemperature, 1) + +/** + * Compute mode. + * + * NVML_COMPUTEMODE_EXCLUSIVE_PROCESS was added in CUDA 4.0. + * Earlier CUDA versions supported a single exclusive mode, + * which is equivalent to NVML_COMPUTEMODE_EXCLUSIVE_THREAD in CUDA 4.0 and beyond. + */ +typedef enum nvmlComputeMode_enum +{ + NVML_COMPUTEMODE_DEFAULT = 0, //!< Default compute mode -- multiple contexts per device + NVML_COMPUTEMODE_EXCLUSIVE_THREAD = 1, //!< Support Removed + NVML_COMPUTEMODE_PROHIBITED = 2, //!< Compute-prohibited mode -- no contexts per device + NVML_COMPUTEMODE_EXCLUSIVE_PROCESS = 3, //!< Compute-exclusive-process mode -- only one context per device, usable from multiple threads at a time + + // Keep this last + NVML_COMPUTEMODE_COUNT +} nvmlComputeMode_t; + +/** + * Max Clock Monitors available + */ +#define MAX_CLK_DOMAINS 32 + +/** + * Clock Monitor error types + */ +typedef struct nvmlClkMonFaultInfo_struct { + /** + * The Domain which faulted + */ + unsigned int clkApiDomain; + + /** + * Faults Information + */ + unsigned int clkDomainFaultMask; +} nvmlClkMonFaultInfo_t; + +/** + * Clock Monitor Status + */ +typedef struct nvmlClkMonStatus_status { + /** + * Fault status Indicator + */ + unsigned int bGlobalStatus; + + /** + * Total faulted domain numbers + */ + unsigned int clkMonListSize; + + /** + * The fault Information structure + */ + nvmlClkMonFaultInfo_t clkMonList[MAX_CLK_DOMAINS]; +} nvmlClkMonStatus_t; + +/** + * ECC bit types. + * + * @deprecated See \ref nvmlMemoryErrorType_t for a more flexible type + */ +#define nvmlEccBitType_t nvmlMemoryErrorType_t + +/** + * Single bit ECC errors + * + * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_CORRECTED + */ +#define NVML_SINGLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_CORRECTED + +/** + * Double bit ECC errors + * + * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_UNCORRECTED + */ +#define NVML_DOUBLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_UNCORRECTED + +/** + * Memory error types + */ +typedef enum nvmlMemoryErrorType_enum +{ + /** + * A memory error that was corrected + * + * For ECC errors, these are single bit errors + * For Texture memory, these are errors fixed by resend + */ + NVML_MEMORY_ERROR_TYPE_CORRECTED = 0, + /** + * A memory error that was not corrected + * + * For ECC errors, these are double bit errors + * For Texture memory, these are errors where the resend fails + */ + NVML_MEMORY_ERROR_TYPE_UNCORRECTED = 1, + + // Keep this last + NVML_MEMORY_ERROR_TYPE_COUNT //!< Count of memory error types + +} nvmlMemoryErrorType_t; + +/** + * Represents Nvlink Version + */ +typedef enum nvmlNvlinkVersion_enum +{ + NVML_NVLINK_VERSION_INVALID = 0, + NVML_NVLINK_VERSION_1_0 = 1, + NVML_NVLINK_VERSION_2_0 = 2, + NVML_NVLINK_VERSION_2_2 = 3, + NVML_NVLINK_VERSION_3_0 = 4, + NVML_NVLINK_VERSION_3_1 = 5, + NVML_NVLINK_VERSION_4_0 = 6, + NVML_NVLINK_VERSION_5_0 = 7, +}nvmlNvlinkVersion_t; + +/** + * ECC counter types. + * + * Note: Volatile counts are reset each time the driver loads. On Windows this is once per boot. On Linux this can be more frequent. + * On Linux the driver unloads when no active clients exist. If persistence mode is enabled or there is always a driver + * client active (e.g. X11), then Linux also sees per-boot behavior. If not, volatile counts are reset each time a compute app + * is run. + */ +typedef enum nvmlEccCounterType_enum +{ + NVML_VOLATILE_ECC = 0, //!< Volatile counts are reset each time the driver loads. + NVML_AGGREGATE_ECC = 1, //!< Aggregate counts persist across reboots (i.e. for the lifetime of the device) + + // Keep this last + NVML_ECC_COUNTER_TYPE_COUNT //!< Count of memory counter types +} nvmlEccCounterType_t; + +/** + * Clock types. + * + * All speeds are in Mhz. + */ +typedef enum nvmlClockType_enum +{ + NVML_CLOCK_GRAPHICS = 0, //!< Graphics clock domain + NVML_CLOCK_SM = 1, //!< SM clock domain + NVML_CLOCK_MEM = 2, //!< Memory clock domain + NVML_CLOCK_VIDEO = 3, //!< Video encoder/decoder clock domain + + // Keep this last + NVML_CLOCK_COUNT //!< Count of clock types +} nvmlClockType_t; + +/** + * Clock Ids. These are used in combination with nvmlClockType_t + * to specify a single clock value. + */ +typedef enum nvmlClockId_enum +{ + NVML_CLOCK_ID_CURRENT = 0, //!< Current actual clock value + NVML_CLOCK_ID_APP_CLOCK_TARGET = 1, //!< Target application clock. + //!< Deprecated, do not use. + NVML_CLOCK_ID_APP_CLOCK_DEFAULT = 2, //!< Default application clock target + //!< Deprecated, do not use. + NVML_CLOCK_ID_CUSTOMER_BOOST_MAX = 3, //!< OEM-defined maximum clock rate + + //Keep this last + NVML_CLOCK_ID_COUNT //!< Count of Clock Ids. +} nvmlClockId_t; + +/** + * Driver models. + * + * Windows only. + */ + +typedef enum nvmlDriverModel_enum +{ + NVML_DRIVER_WDDM = 0, //!< WDDM driver model -- GPU treated as a display device + NVML_DRIVER_WDM = 1, //!< WDM (TCC) model (deprecated) -- GPU treated as a generic compute device + NVML_DRIVER_MCDM = 2 //!< MCDM driver model -- GPU treated as a Microsoft compute device +} nvmlDriverModel_t; + +#define NVML_MAX_GPU_PERF_PSTATES 16 + +/** + * Allowed PStates. + */ +typedef enum nvmlPStates_enum +{ + NVML_PSTATE_0 = 0, //!< Performance state 0 -- Maximum Performance + NVML_PSTATE_1 = 1, //!< Performance state 1 + NVML_PSTATE_2 = 2, //!< Performance state 2 + NVML_PSTATE_3 = 3, //!< Performance state 3 + NVML_PSTATE_4 = 4, //!< Performance state 4 + NVML_PSTATE_5 = 5, //!< Performance state 5 + NVML_PSTATE_6 = 6, //!< Performance state 6 + NVML_PSTATE_7 = 7, //!< Performance state 7 + NVML_PSTATE_8 = 8, //!< Performance state 8 + NVML_PSTATE_9 = 9, //!< Performance state 9 + NVML_PSTATE_10 = 10, //!< Performance state 10 + NVML_PSTATE_11 = 11, //!< Performance state 11 + NVML_PSTATE_12 = 12, //!< Performance state 12 + NVML_PSTATE_13 = 13, //!< Performance state 13 + NVML_PSTATE_14 = 14, //!< Performance state 14 + NVML_PSTATE_15 = 15, //!< Performance state 15 -- Minimum Performance + NVML_PSTATE_UNKNOWN = 32 //!< Unknown performance state +} nvmlPstates_t; + +/** + * Clock offset info. + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + nvmlClockType_t type; + nvmlPstates_t pstate; + int clockOffsetMHz; + int minClockOffsetMHz; + int maxClockOffsetMHz; +} nvmlClockOffset_v1_t; + +typedef nvmlClockOffset_v1_t nvmlClockOffset_t; + +#define nvmlClockOffset_v1 NVML_STRUCT_VERSION(ClockOffset, 1) + +/** + * Fan speed info. + */ +typedef struct +{ + unsigned int version; //!< the API version number + unsigned int fan; //!< the fan index + unsigned int speed; //!< OUT: the fan speed in RPM +} nvmlFanSpeedInfo_v1_t; +typedef nvmlFanSpeedInfo_v1_t nvmlFanSpeedInfo_t; + +#define nvmlFanSpeedInfo_v1 NVML_STRUCT_VERSION(FanSpeedInfo, 1) + +#define NVML_PERF_MODES_BUFFER_SIZE 2048 + +/** + * Device performance modes string + */ +typedef struct +{ + unsigned int version; //!< the API version number + char str[NVML_PERF_MODES_BUFFER_SIZE]; //!< OUT: the performance modes string. +} nvmlDevicePerfModes_v1_t; +typedef nvmlDevicePerfModes_v1_t nvmlDevicePerfModes_t; + +#define nvmlDevicePerfModes_v1 NVML_STRUCT_VERSION(DevicePerfModes, 1) + +/** + * Device current clocks string + */ +typedef struct +{ + unsigned int version; //!< the API version number + char str[NVML_PERF_MODES_BUFFER_SIZE]; //!< OUT: the current clock frequency string. +} nvmlDeviceCurrentClockFreqs_v1_t; +typedef nvmlDeviceCurrentClockFreqs_v1_t nvmlDeviceCurrentClockFreqs_t; + +#define nvmlDeviceCurrentClockFreqs_v1 NVML_STRUCT_VERSION(DeviceCurrentClockFreqs, 1) + +/** + * Device powerMizer modes + */ +#define NVML_POWER_MIZER_MODE_ADAPTIVE 0 //!< adjust GPU clocks based on GPU utilization +#define NVML_POWER_MIZER_MODE_PREFER_MAXIMUM_PERFORMANCE 1 //!< raise GPU clocks to favor maximum performance, + //!< to the extent that thermal and other constraints allow +#define NVML_POWER_MIZER_MODE_AUTO 2 //!< PowerMizer mode is driver controlled. +#define NVML_POWER_MIZER_MODE_PREFER_CONSISTENT_PERFORMANCE 3 //!< lock to GPU base clocks + +typedef struct +{ + unsigned int currentMode; //!< OUT: the current powermizer mode + unsigned int mode; //!< IN: the powermizer mode to set + unsigned int supportedPowerMizerModes; //!< OUT: Bitmask of supported powermizer modes +} nvmlDevicePowerMizerModes_v1_t; + +/** + * GPU Operation Mode + * + * GOM allows to reduce power usage and optimize GPU throughput by disabling GPU features. + * + * Each GOM is designed to meet specific user needs. + */ +typedef enum nvmlGom_enum +{ + NVML_GOM_ALL_ON = 0, //!< Everything is enabled and running at full speed + + NVML_GOM_COMPUTE = 1, //!< Designed for running only compute tasks. Graphics operations + //!< are not allowed + + NVML_GOM_LOW_DP = 2 //!< Designed for running graphics applications that don't require + //!< high bandwidth double precision +} nvmlGpuOperationMode_t; + +/** + * Available infoROM objects. + */ +typedef enum nvmlInforomObject_enum +{ + NVML_INFOROM_OEM = 0, //!< An object defined by OEM + NVML_INFOROM_ECC = 1, //!< The ECC object determining the level of ECC support + NVML_INFOROM_POWER = 2, //!< The power management object + NVML_INFOROM_DEN = 3, //!< DRAM Encryption object + // Keep this last + NVML_INFOROM_COUNT //!< This counts the number of infoROM objects the driver knows about +} nvmlInforomObject_t; + +/** + * Return values for NVML API calls. + */ +typedef enum nvmlReturn_enum +{ + // cppcheck-suppress * + NVML_SUCCESS = 0, //!< The operation was successful + NVML_ERROR_UNINITIALIZED = 1, //!< NVML was not first initialized with nvmlInit() + NVML_ERROR_INVALID_ARGUMENT = 2, //!< A supplied argument is invalid + NVML_ERROR_NOT_SUPPORTED = 3, //!< The requested operation is not available on target device + NVML_ERROR_NO_PERMISSION = 4, //!< The current user does not have permission for operation + NVML_ERROR_ALREADY_INITIALIZED = 5, //!< Deprecated: Multiple initializations are now allowed through ref counting + NVML_ERROR_NOT_FOUND = 6, //!< A query to find an object was unsuccessful + NVML_ERROR_INSUFFICIENT_SIZE = 7, //!< An input argument is not large enough + NVML_ERROR_INSUFFICIENT_POWER = 8, //!< A device's external power cables are not properly attached + NVML_ERROR_DRIVER_NOT_LOADED = 9, //!< NVIDIA driver is not loaded + NVML_ERROR_TIMEOUT = 10, //!< User provided timeout passed + NVML_ERROR_IRQ_ISSUE = 11, //!< NVIDIA Kernel detected an interrupt issue with a GPU + NVML_ERROR_LIBRARY_NOT_FOUND = 12, //!< NVML Shared Library couldn't be found or loaded + NVML_ERROR_FUNCTION_NOT_FOUND = 13, //!< Local version of NVML doesn't implement this function + NVML_ERROR_CORRUPTED_INFOROM = 14, //!< infoROM is corrupted + NVML_ERROR_GPU_IS_LOST = 15, //!< The GPU has fallen off the bus or has otherwise become inaccessible + NVML_ERROR_RESET_REQUIRED = 16, //!< The GPU requires a reset before it can be used again + NVML_ERROR_OPERATING_SYSTEM = 17, //!< The GPU control device has been blocked by the operating system/cgroups + NVML_ERROR_LIB_RM_VERSION_MISMATCH = 18, //!< RM detects a driver/library version mismatch + NVML_ERROR_IN_USE = 19, //!< An operation cannot be performed because the GPU is currently in use + NVML_ERROR_MEMORY = 20, //!< Insufficient memory + NVML_ERROR_NO_DATA = 21, //!< No data + NVML_ERROR_VGPU_ECC_NOT_SUPPORTED = 22, //!< The requested vgpu operation is not available on target device, becasue ECC is enabled + NVML_ERROR_INSUFFICIENT_RESOURCES = 23, //!< Ran out of critical resources, other than memory + NVML_ERROR_FREQ_NOT_SUPPORTED = 24, //!< Ran out of critical resources, other than memory + NVML_ERROR_ARGUMENT_VERSION_MISMATCH = 25, //!< The provided version is invalid/unsupported + NVML_ERROR_DEPRECATED = 26, //!< The requested functionality has been deprecated + NVML_ERROR_NOT_READY = 27, //!< The system is not ready for the request + NVML_ERROR_GPU_NOT_FOUND = 28, //!< No GPUs were found + NVML_ERROR_INVALID_STATE = 29, //!< Resource not in correct state to perform requested operation + NVML_ERROR_RESET_TYPE_NOT_SUPPORTED = 30, //!< Reset not supported for given device/parameters + NVML_ERROR_UNKNOWN = 999 //!< An internal driver error occurred +} nvmlReturn_t; + +/** + * See \ref nvmlDeviceGetMemoryErrorCounter + */ +typedef enum nvmlMemoryLocation_enum +{ + NVML_MEMORY_LOCATION_L1_CACHE = 0, //!< GPU L1 Cache + NVML_MEMORY_LOCATION_L2_CACHE = 1, //!< GPU L2 Cache + NVML_MEMORY_LOCATION_DRAM = 2, //!< Turing+ DRAM + NVML_MEMORY_LOCATION_DEVICE_MEMORY = 2, //!< GPU Device Memory + NVML_MEMORY_LOCATION_REGISTER_FILE = 3, //!< GPU Register File + NVML_MEMORY_LOCATION_TEXTURE_MEMORY = 4, //!< GPU Texture Memory + NVML_MEMORY_LOCATION_TEXTURE_SHM = 5, //!< Shared memory + NVML_MEMORY_LOCATION_CBU = 6, //!< CBU + NVML_MEMORY_LOCATION_SRAM = 7, //!< Turing+ SRAM + // Keep this last + NVML_MEMORY_LOCATION_COUNT //!< This counts the number of memory locations the driver knows about +} nvmlMemoryLocation_t; + +/** + * Causes for page retirement + */ +typedef enum nvmlPageRetirementCause_enum +{ + NVML_PAGE_RETIREMENT_CAUSE_MULTIPLE_SINGLE_BIT_ECC_ERRORS = 0, //!< Page was retired due to multiple single bit ECC error + NVML_PAGE_RETIREMENT_CAUSE_DOUBLE_BIT_ECC_ERROR = 1, //!< Page was retired due to double bit ECC error + + // Keep this last + NVML_PAGE_RETIREMENT_CAUSE_COUNT +} nvmlPageRetirementCause_t; + +/** + * API types that allow changes to default permission restrictions + */ +typedef enum nvmlRestrictedAPI_enum +{ + NVML_RESTRICTED_API_SET_APPLICATION_CLOCKS = 0, //!< APIs that change application clocks, see nvmlDeviceSetApplicationsClocks + //!< and see nvmlDeviceResetApplicationsClocks. + //!< Deprecated, keeping definition for backward compatibility. + NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS = 1, //!< APIs that enable/disable Auto Boosted clocks + //!< see nvmlDeviceSetAutoBoostedClocksEnabled + // Keep this last + NVML_RESTRICTED_API_COUNT +} nvmlRestrictedAPI_t; + +/** + * Structure to store utilization value and process Id + */ +typedef struct nvmlProcessUtilizationSample_st +{ + unsigned int pid; //!< PID of process + unsigned long long timeStamp; //!< CPU Timestamp in microseconds + unsigned int smUtil; //!< SM (3D/Compute) Util Value + unsigned int memUtil; //!< Frame Buffer Memory Util Value + unsigned int encUtil; //!< Encoder Util Value + unsigned int decUtil; //!< Decoder Util Value +} nvmlProcessUtilizationSample_t; + +/** + * Structure to store utilization value and process Id -- version 1 + */ +typedef struct +{ + unsigned long long timeStamp; //!< CPU Timestamp in microseconds + unsigned int pid; //!< PID of process + unsigned int smUtil; //!< SM (3D/Compute) Util Value + unsigned int memUtil; //!< Frame Buffer Memory Util Value + unsigned int encUtil; //!< Encoder Util Value + unsigned int decUtil; //!< Decoder Util Value + unsigned int jpgUtil; //!< Jpeg Util Value + unsigned int ofaUtil; //!< Ofa Util Value +} nvmlProcessUtilizationInfo_v1_t; + +/** + * Structure to store utilization and process ID for each running process -- version 1 + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + unsigned int processSamplesCount; //!< Caller-supplied array size, and returns number of processes running + unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp + nvmlProcessUtilizationInfo_v1_t *procUtilArray; //!< The array (allocated by caller) of the utilization of GPU SM, framebuffer, video encoder, video decoder, JPEG, and OFA +} nvmlProcessesUtilizationInfo_v1_t; +typedef nvmlProcessesUtilizationInfo_v1_t nvmlProcessesUtilizationInfo_t; +#define nvmlProcessesUtilizationInfo_v1 NVML_STRUCT_VERSION(ProcessesUtilizationInfo, 1) + +/** + * Structure to store SRAM uncorrectable error counters + */ +typedef struct +{ + unsigned int version; //!< the API version number + unsigned long long aggregateUncParity; //!< aggregate uncorrectable parity error count + unsigned long long aggregateUncSecDed; //!< aggregate uncorrectable SEC-DED error count + unsigned long long aggregateCor; //!< aggregate correctable error count + unsigned long long volatileUncParity; //!< volatile uncorrectable parity error count + unsigned long long volatileUncSecDed; //!< volatile uncorrectable SEC-DED error count + unsigned long long volatileCor; //!< volatile correctable error count + unsigned long long aggregateUncBucketL2; //!< aggregate uncorrectable error count for L2 cache bucket + unsigned long long aggregateUncBucketSm; //!< aggregate uncorrectable error count for SM bucket + unsigned long long aggregateUncBucketPcie; //!< aggregate uncorrectable error count for PCIE bucket + unsigned long long aggregateUncBucketMcu; //!< aggregate uncorrectable error count for Microcontroller bucket + unsigned long long aggregateUncBucketOther; //!< aggregate uncorrectable error count for Other bucket + unsigned int bThresholdExceeded; //!< if the error threshold of field diag is exceeded +} nvmlEccSramErrorStatus_v1_t; + +typedef nvmlEccSramErrorStatus_v1_t nvmlEccSramErrorStatus_t; +#define nvmlEccSramErrorStatus_v1 NVML_STRUCT_VERSION(EccSramErrorStatus, 1) + +/** + * Structure to store platform information + * + * @deprecated The nvmlPlatformInfo_v1_t will be deprecated in the subsequent releases. + * Use nvmlPlatformInfo_v2_t + */ +typedef struct +{ + unsigned int version; //!< the API version number + unsigned char ibGuid[16]; //!< Infiniband GUID reported by platform (for Blackwell, ibGuid is 8 bytes so indices 8-15 are zero) + unsigned char rackGuid[16]; //!< GUID of the rack containing this GPU (for Blackwell rackGuid is 13 bytes so indices 13-15 are zero) + unsigned char chassisPhysicalSlotNumber; //!< The slot number in the rack containing this GPU (includes switches) + unsigned char computeSlotIndex; //!< The index within the compute slots in the rack containing this GPU (does not include switches) + unsigned char nodeIndex; //!< Index of the node within the slot containing this GPU + unsigned char peerType; //!< Platform indicated NVLink-peer type (e.g. switch present or not) + unsigned char moduleId; //!< ID of this GPU within the node +} nvmlPlatformInfo_v1_t; +#define nvmlPlatformInfo_v1 NVML_STRUCT_VERSION(PlatformInfo, 1) + +/** + * Structure to store platform information (v2) + */ +typedef struct +{ + unsigned int version; //!< the API version number + unsigned char ibGuid[16]; //!< Infiniband GUID reported by platform (for Blackwell, ibGuid is 8 bytes so indices 8-15 are zero) + unsigned char chassisSerialNumber[16]; //!< Serial number of the chassis containing this GPU (for Blackwell it is 13 bytes so indices 13-15 are zero) + unsigned char slotNumber; //!< The slot number in the chassis containing this GPU (includes switches) + unsigned char trayIndex; //!< The tray index within the compute slots in the chassis containing this GPU (does not include switches) + unsigned char hostId; //!< Index of the node within the slot containing this GPU + unsigned char peerType; //!< Platform indicated NVLink-peer type (e.g. switch present or not) + unsigned char moduleId; //!< ID of this GPU within the node +} nvmlPlatformInfo_v2_t; + +typedef nvmlPlatformInfo_v2_t nvmlPlatformInfo_t; +#define nvmlPlatformInfo_v2 NVML_STRUCT_VERSION(PlatformInfo, 2) + +/** + * Structure to store hostname information + */ +#define NVML_DEVICE_HOSTNAME_BUFFER_SIZE 64 + +typedef struct +{ + char value[NVML_DEVICE_HOSTNAME_BUFFER_SIZE]; //!< null-terminated hostname string +} nvmlHostname_v1_t; + +typedef struct +{ + unsigned int unit; //!< the SRAM unit index + unsigned int location; //!< the error location within the SRAM unit + unsigned int sublocation; //!< the error sublocation within the SRAM unit + unsigned int extlocation; //!< the error extlocation within the SRAM unit + unsigned int address; //!< the error address within the SRAM unit + unsigned int isParity; //!< if the SRAM error is parity or not + unsigned int count; //!< the error count at the same SRAM address +} nvmlEccSramUniqueUncorrectedErrorEntry_v1_t; + +typedef struct +{ + unsigned int version; //!< the API version number + unsigned int entryCount; //!< the number of error count entries + nvmlEccSramUniqueUncorrectedErrorEntry_v1_t *entries; //!< pointer to caller-supplied buffer to return the SRAM unique uncorrected ECC error count entries +} nvmlEccSramUniqueUncorrectedErrorCounts_v1_t; + +typedef nvmlEccSramUniqueUncorrectedErrorCounts_v1_t nvmlEccSramUniqueUncorrectedErrorCounts_t; +#define nvmlEccSramUniqueUncorrectedErrorCounts_v1 NVML_STRUCT_VERSION(EccSramUniqueUncorrectedErrorCounts, 1) + +/** + * GSP firmware + */ +#define NVML_GSP_FIRMWARE_VERSION_BUF_SIZE 0x40 + +/** + * Simplified chip architecture + */ +#define NVML_DEVICE_ARCH_KEPLER 2 // Devices based on the NVIDIA Kepler architecture +#define NVML_DEVICE_ARCH_MAXWELL 3 // Devices based on the NVIDIA Maxwell architecture +#define NVML_DEVICE_ARCH_PASCAL 4 // Devices based on the NVIDIA Pascal architecture +#define NVML_DEVICE_ARCH_VOLTA 5 // Devices based on the NVIDIA Volta architecture +#define NVML_DEVICE_ARCH_TURING 6 // Devices based on the NVIDIA Turing architecture +#define NVML_DEVICE_ARCH_AMPERE 7 // Devices based on the NVIDIA Ampere architecture +#define NVML_DEVICE_ARCH_ADA 8 // Devices based on the NVIDIA Ada architecture +#define NVML_DEVICE_ARCH_HOPPER 9 // Devices based on the NVIDIA Hopper architecture + +#define NVML_DEVICE_ARCH_BLACKWELL 10 // Devices based on the NVIDIA Blackwell architecture + +#define NVML_DEVICE_ARCH_UNKNOWN 0xffffffff // Anything else, presumably something newer + +typedef unsigned int nvmlDeviceArchitecture_t; + +/** + * PCI bus types + */ +#define NVML_BUS_TYPE_UNKNOWN 0 +#define NVML_BUS_TYPE_PCI 1 +#define NVML_BUS_TYPE_PCIE 2 +#define NVML_BUS_TYPE_FPCI 3 +#define NVML_BUS_TYPE_AGP 4 + +typedef unsigned int nvmlBusType_t; + +/** + * Device Power Modes + */ + +/** + * Device Fan control policy + */ +#define NVML_FAN_POLICY_TEMPERATURE_CONTINOUS_SW 0 +#define NVML_FAN_POLICY_MANUAL 1 + +typedef unsigned int nvmlFanControlPolicy_t; + +/** + * Device Power Source + */ +#define NVML_POWER_SOURCE_AC 0x00000000 +#define NVML_POWER_SOURCE_BATTERY 0x00000001 +#define NVML_POWER_SOURCE_UNDERSIZED 0x00000002 + +typedef unsigned int nvmlPowerSource_t; + +/** + * Device PCIE link Max Speed + */ +#define NVML_PCIE_LINK_MAX_SPEED_INVALID 0x00000000 +#define NVML_PCIE_LINK_MAX_SPEED_2500MBPS 0x00000001 +#define NVML_PCIE_LINK_MAX_SPEED_5000MBPS 0x00000002 +#define NVML_PCIE_LINK_MAX_SPEED_8000MBPS 0x00000003 +#define NVML_PCIE_LINK_MAX_SPEED_16000MBPS 0x00000004 +#define NVML_PCIE_LINK_MAX_SPEED_32000MBPS 0x00000005 +#define NVML_PCIE_LINK_MAX_SPEED_64000MBPS 0x00000006 + +/** + * Adaptive clocking status + */ +#define NVML_ADAPTIVE_CLOCKING_INFO_STATUS_DISABLED 0x00000000 +#define NVML_ADAPTIVE_CLOCKING_INFO_STATUS_ENABLED 0x00000001 + +#define NVML_MAX_GPU_UTILIZATIONS 8 + +/** + * Represents the GPU utilization domains + */ +typedef enum nvmlGpuUtilizationDomainId_t +{ + NVML_GPU_UTILIZATION_DOMAIN_GPU = 0, //!< Graphics engine domain + NVML_GPU_UTILIZATION_DOMAIN_FB = 1, //!< Frame buffer domain + NVML_GPU_UTILIZATION_DOMAIN_VID = 2, //!< Video engine domain + NVML_GPU_UTILIZATION_DOMAIN_BUS = 3, //!< Bus interface domain +} nvmlGpuUtilizationDomainId_t; + +typedef struct nvmlGpuDynamicPstatesInfo_st +{ + unsigned int flags; //!< Reserved for future use + struct + { + unsigned int bIsPresent; //!< Set if this utilization domain is present on this GPU + unsigned int percentage; //!< Percentage of time where the domain is considered busy in the last 1-second interval + unsigned int incThreshold; //!< Utilization threshold that can trigger a perf-increasing P-State change when crossed + unsigned int decThreshold; //!< Utilization threshold that can trigger a perf-decreasing P-State change when crossed + } utilization[NVML_MAX_GPU_UTILIZATIONS]; +} nvmlGpuDynamicPstatesInfo_t; + +/* + * PCIe outbound/inbound atomic operations capability + */ +#define NVML_PCIE_ATOMICS_CAP_FETCHADD32 0x01 +#define NVML_PCIE_ATOMICS_CAP_FETCHADD64 0x02 +#define NVML_PCIE_ATOMICS_CAP_SWAP32 0x04 +#define NVML_PCIE_ATOMICS_CAP_SWAP64 0x08 +#define NVML_PCIE_ATOMICS_CAP_CAS32 0x10 +#define NVML_PCIE_ATOMICS_CAP_CAS64 0x20 +#define NVML_PCIE_ATOMICS_CAP_CAS128 0x40 +#define NVML_PCIE_ATOMICS_OPS_MAX 7 + +/** + * Device Scope - This is useful to retrieve the telemetry at GPU and module (e.g. GPU + CPU) level + */ +#define NVML_POWER_SCOPE_GPU 0U //!< Targets only GPU +#define NVML_POWER_SCOPE_MODULE 1U //!< Targets the whole module +#define NVML_POWER_SCOPE_MEMORY 2U //!< Targets the GPU Memory + +typedef unsigned char nvmlPowerScopeType_t; + +/** + * Contains the power management limit + */ +typedef struct +{ + unsigned int version; //!< Structure format version (must be 1) + nvmlPowerScopeType_t powerScope; //!< [in] Device type: GPU or Total Module + unsigned int powerValueMw; //!< [out] Power value to retrieve or set in milliwatts +} nvmlPowerValue_v2_t; + +#define nvmlPowerValue_v2 NVML_STRUCT_VERSION(PowerValue, 2) + +/** @} */ + +/***************************************************************************************************/ +/** @addtogroup virtualGPU vGPU Enums, Constants, Structs + * @{ + */ +/***************************************************************************************************/ +/** @defgroup nvmlVirtualGpuEnums vGPU Enums + * @{ + */ +/***************************************************************************************************/ + +/*! + * GPU virtualization mode types. + */ +typedef enum nvmlGpuVirtualizationMode { + NVML_GPU_VIRTUALIZATION_MODE_NONE = 0, //!< Represents Bare Metal GPU + NVML_GPU_VIRTUALIZATION_MODE_PASSTHROUGH = 1, //!< Device is associated with GPU-Passthorugh + NVML_GPU_VIRTUALIZATION_MODE_VGPU = 2, //!< Device is associated with vGPU inside virtual machine. + NVML_GPU_VIRTUALIZATION_MODE_HOST_VGPU = 3, //!< Device is associated with VGX hypervisor in vGPU mode + NVML_GPU_VIRTUALIZATION_MODE_HOST_VSGA = 4 //!< Device is associated with VGX hypervisor in vSGA mode +} nvmlGpuVirtualizationMode_t; + +/** + * Host vGPU modes + */ +typedef enum nvmlHostVgpuMode_enum +{ + NVML_HOST_VGPU_MODE_NON_SRIOV = 0, //!< Non SR-IOV mode + NVML_HOST_VGPU_MODE_SRIOV = 1 //!< SR-IOV mode +} nvmlHostVgpuMode_t; + +/*! + * Types of VM identifiers + */ +typedef enum nvmlVgpuVmIdType { + NVML_VGPU_VM_ID_DOMAIN_ID = 0, //!< VM ID represents DOMAIN ID + NVML_VGPU_VM_ID_UUID = 1 //!< VM ID represents UUID +} nvmlVgpuVmIdType_t; + +/** + * vGPU GUEST info state + */ +typedef enum nvmlVgpuGuestInfoState_enum +{ + NVML_VGPU_INSTANCE_GUEST_INFO_STATE_UNINITIALIZED = 0, //!< Guest-dependent fields uninitialized + NVML_VGPU_INSTANCE_GUEST_INFO_STATE_INITIALIZED = 1 //!< Guest-dependent fields initialized +} nvmlVgpuGuestInfoState_t; + +/** + * vGPU software licensable features + */ +typedef enum { + NVML_GRID_LICENSE_FEATURE_CODE_UNKNOWN = 0, //!< Unknown + NVML_GRID_LICENSE_FEATURE_CODE_VGPU = 1, //!< Virtual GPU + NVML_GRID_LICENSE_FEATURE_CODE_NVIDIA_RTX = 2, //!< Nvidia RTX + NVML_GRID_LICENSE_FEATURE_CODE_VWORKSTATION = NVML_GRID_LICENSE_FEATURE_CODE_NVIDIA_RTX, //!< Deprecated, do not use. + NVML_GRID_LICENSE_FEATURE_CODE_GAMING = 3, //!< Gaming + NVML_GRID_LICENSE_FEATURE_CODE_COMPUTE = 4 //!< Compute +} nvmlGridLicenseFeatureCode_t; + +/** + * Status codes for license expiry + */ +#define NVML_GRID_LICENSE_EXPIRY_NOT_AVAILABLE 0 //!< Expiry information not available +#define NVML_GRID_LICENSE_EXPIRY_INVALID 1 //!< Invalid expiry or error fetching expiry +#define NVML_GRID_LICENSE_EXPIRY_VALID 2 //!< Valid expiry +#define NVML_GRID_LICENSE_EXPIRY_NOT_APPLICABLE 3 //!< Expiry not applicable +#define NVML_GRID_LICENSE_EXPIRY_PERMANENT 4 //!< Permanent expiry + +/** + * vGPU queryable capabilities + */ +typedef enum nvmlVgpuCapability_enum +{ + NVML_VGPU_CAP_NVLINK_P2P = 0, //!< P2P over NVLink is supported + NVML_VGPU_CAP_GPUDIRECT = 1, //!< GPUDirect capability is supported + NVML_VGPU_CAP_MULTI_VGPU_EXCLUSIVE = 2, //!< vGPU profile cannot be mixed with other vGPU profiles in same VM + NVML_VGPU_CAP_EXCLUSIVE_TYPE = 3, //!< vGPU profile cannot run on a GPU alongside other profiles of different type + NVML_VGPU_CAP_EXCLUSIVE_SIZE = 4, //!< vGPU profile cannot run on a GPU alongside other profiles of different size + // Keep this last + NVML_VGPU_CAP_COUNT +} nvmlVgpuCapability_t; + +/** +* vGPU driver queryable capabilities +*/ +typedef enum nvmlVgpuDriverCapability_enum +{ + NVML_VGPU_DRIVER_CAP_HETEROGENEOUS_MULTI_VGPU = 0, //!< Supports mixing of different vGPU profiles within one guest VM + NVML_VGPU_DRIVER_CAP_WARM_UPDATE = 1, //!< Supports FSR and warm update of vGPU host driver without terminating the running guest VM + // Keep this last + NVML_VGPU_DRIVER_CAP_COUNT +} nvmlVgpuDriverCapability_t; + +/** +* Device vGPU queryable capabilities +*/ +typedef enum nvmlDeviceVgpuCapability_enum +{ + NVML_DEVICE_VGPU_CAP_FRACTIONAL_MULTI_VGPU = 0, //!< Query whether the fractional vGPU profiles on this GPU can be used in multi-vGPU configurations + NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_PROFILES = 1, //!< Query whether the GPU support concurrent execution of timesliced vGPU profiles of differing types + NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_SIZES = 2, //!< Query whether the GPU support concurrent execution of timesliced vGPU profiles of differing framebuffer sizes + NVML_DEVICE_VGPU_CAP_READ_DEVICE_BUFFER_BW = 3, //!< Query the GPU's read_device_buffer expected bandwidth capacity in megabytes per second + NVML_DEVICE_VGPU_CAP_WRITE_DEVICE_BUFFER_BW = 4, //!< Query the GPU's write_device_buffer expected bandwidth capacity in megabytes per second + NVML_DEVICE_VGPU_CAP_DEVICE_STREAMING = 5, //!< Query whether the vGPU profiles on the GPU supports migration data streaming + NVML_DEVICE_VGPU_CAP_MINI_QUARTER_GPU = 6, //!< Set/Get support for mini-quarter vGPU profiles + NVML_DEVICE_VGPU_CAP_COMPUTE_MEDIA_ENGINE_GPU = 7, //!< Set/Get support for compute media engine vGPU profiles + NVML_DEVICE_VGPU_CAP_WARM_UPDATE = 8, //!< Query whether the GPU supports FSR and warm update + NVML_DEVICE_VGPU_CAP_HOMOGENEOUS_PLACEMENTS = 9, //!< Query whether the GPU supports reporting of placements of timesliced vGPU profiles with identical framebuffer sizes + NVML_DEVICE_VGPU_CAP_MIG_TIMESLICING_SUPPORTED = 10, //!< Query whether the GPU supports timesliced vGPU on MIG + NVML_DEVICE_VGPU_CAP_MIG_TIMESLICING_ENABLED = 11, //!< Set/Get MIG timesliced mode reporting, without impacting the underlying functionality + // Keep this last + NVML_DEVICE_VGPU_CAP_COUNT +} nvmlDeviceVgpuCapability_t; + +/** @} */ + +/***************************************************************************************************/ + +/** @defgroup nvmlVgpuConstants vGPU Constants + * @{ + */ +/***************************************************************************************************/ + +/** + * Buffer size guaranteed to be large enough for \ref nvmlVgpuTypeGetLicense + */ +#define NVML_GRID_LICENSE_BUFFER_SIZE 128 + +#define NVML_VGPU_NAME_BUFFER_SIZE 64 + +#define NVML_GRID_LICENSE_FEATURE_MAX_COUNT 3 + +#define INVALID_GPU_INSTANCE_PROFILE_ID 0xFFFFFFFF + +#define INVALID_GPU_INSTANCE_ID 0xFFFFFFFF + +#define NVML_INVALID_VGPU_PLACEMENT_ID 0xFFFF + +/*! + * Macros for vGPU instance's virtualization capabilities bitfield. + */ +#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION 0:0 +#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION_NO 0x0 +#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION_YES 0x1 + +/*! + * Macros for pGPU's virtualization capabilities bitfield. + */ +#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION 0:0 +#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION_NO 0x0 +#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION_YES 0x1 + +/** + * Macros to indicate the vGPU mode of the GPU. + */ +#define NVML_VGPU_PGPU_HETEROGENEOUS_MODE 0 +#define NVML_VGPU_PGPU_HOMOGENEOUS_MODE 1 + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlVgpuStructs vGPU Structs + * @{ + */ +/***************************************************************************************************/ + +typedef unsigned int nvmlVgpuTypeId_t; + +typedef unsigned int nvmlVgpuInstance_t; + +/** + * Structure to store the vGPU heterogeneous mode of device -- version 1 + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + unsigned int mode; //!< The vGPU heterogeneous mode +} nvmlVgpuHeterogeneousMode_v1_t; +typedef nvmlVgpuHeterogeneousMode_v1_t nvmlVgpuHeterogeneousMode_t; +#define nvmlVgpuHeterogeneousMode_v1 NVML_STRUCT_VERSION(VgpuHeterogeneousMode, 1) + +/** + * Structure to store the placement ID of vGPU instance -- version 1 + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + unsigned int placementId; //!< Placement ID of the active vGPU instance +} nvmlVgpuPlacementId_v1_t; +typedef nvmlVgpuPlacementId_v1_t nvmlVgpuPlacementId_t; +#define nvmlVgpuPlacementId_v1 NVML_STRUCT_VERSION(VgpuPlacementId, 1) + +/** + * Structure to store the list of vGPU placements -- version 1 + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + unsigned int placementSize; //!< The number of slots occupied by the vGPU type + unsigned int count; //!< Count of placement IDs fetched + unsigned int *placementIds; //!< Placement IDs for the vGPU type +} nvmlVgpuPlacementList_v1_t; +#define nvmlVgpuPlacementList_v1 NVML_STRUCT_VERSION(VgpuPlacementList, 1) + +/** + * Structure to store the list of vGPU placements -- version 2 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + unsigned int placementSize; //!< OUT: The number of slots occupied by the vGPU type + unsigned int count; //!< IN/OUT: Count of the placement IDs + unsigned int *placementIds; //!< IN/OUT: Placement IDs for the vGPU type + unsigned int mode; //!< IN: The vGPU mode. Either NVML_VGPU_PGPU_HETEROGENEOUS_MODE or NVML_VGPU_PGPU_HOMOGENEOUS_MODE +} nvmlVgpuPlacementList_v2_t; +typedef nvmlVgpuPlacementList_v2_t nvmlVgpuPlacementList_t; +#define nvmlVgpuPlacementList_v2 NVML_STRUCT_VERSION(VgpuPlacementList, 2) + +/** + * Structure to store BAR1 size information of vGPU type -- Version 1 + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + unsigned long long bar1Size; //!< BAR1 size in megabytes +} nvmlVgpuTypeBar1Info_v1_t; +typedef nvmlVgpuTypeBar1Info_v1_t nvmlVgpuTypeBar1Info_t; +#define nvmlVgpuTypeBar1Info_v1 NVML_STRUCT_VERSION(VgpuTypeBar1Info, 1) + +/** + * Structure to store Utilization Value and vgpuInstance + */ +typedef struct nvmlVgpuInstanceUtilizationSample_st +{ + nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance + unsigned long long timeStamp; //!< CPU Timestamp in microseconds + nvmlValue_t smUtil; //!< SM (3D/Compute) Util Value + nvmlValue_t memUtil; //!< Frame Buffer Memory Util Value + nvmlValue_t encUtil; //!< Encoder Util Value + nvmlValue_t decUtil; //!< Decoder Util Value +} nvmlVgpuInstanceUtilizationSample_t; + +/** + * Structure to store Utilization Value and vgpuInstance Info -- Version 1 + */ +typedef struct +{ + unsigned long long timeStamp; //!< CPU Timestamp in microseconds + nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance + nvmlValue_t smUtil; //!< SM (3D/Compute) Util Value + nvmlValue_t memUtil; //!< Frame Buffer Memory Util Value + nvmlValue_t encUtil; //!< Encoder Util Value + nvmlValue_t decUtil; //!< Decoder Util Value + nvmlValue_t jpgUtil; //!< Jpeg Util Value + nvmlValue_t ofaUtil; //!< Ofa Util Value +} nvmlVgpuInstanceUtilizationInfo_v1_t; + +/** + * Structure to store recent utilization for vGPU instances running on a device -- version 1 + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + nvmlValueType_t sampleValType; //!< Hold the type of returned sample values + unsigned int vgpuInstanceCount; //!< Hold the number of vGPU instances + unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp + nvmlVgpuInstanceUtilizationInfo_v1_t *vgpuUtilArray; //!< The array (allocated by caller) in which vGPU utilization are returned +} nvmlVgpuInstancesUtilizationInfo_v1_t; +typedef nvmlVgpuInstancesUtilizationInfo_v1_t nvmlVgpuInstancesUtilizationInfo_t; +#define nvmlVgpuInstancesUtilizationInfo_v1 NVML_STRUCT_VERSION(VgpuInstancesUtilizationInfo, 1) + +/** + * Structure to store Utilization Value, vgpuInstance and subprocess information + */ +typedef struct nvmlVgpuProcessUtilizationSample_st +{ + nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance + unsigned int pid; //!< PID of process running within the vGPU VM + char processName[NVML_VGPU_NAME_BUFFER_SIZE]; //!< Name of process running within the vGPU VM + unsigned long long timeStamp; //!< CPU Timestamp in microseconds + unsigned int smUtil; //!< SM (3D/Compute) Util Value + unsigned int memUtil; //!< Frame Buffer Memory Util Value + unsigned int encUtil; //!< Encoder Util Value + unsigned int decUtil; //!< Decoder Util Value +} nvmlVgpuProcessUtilizationSample_t; + +/** + * Structure to store Utilization Value, vgpuInstance and subprocess information for process running on vGPU instance -- version 1 + */ +typedef struct +{ + char processName[NVML_VGPU_NAME_BUFFER_SIZE]; //!< Name of process running within the vGPU VM + unsigned long long timeStamp; //!< CPU Timestamp in microseconds + nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance + unsigned int pid; //!< PID of process running within the vGPU VM + unsigned int smUtil; //!< SM (3D/Compute) Util Value + unsigned int memUtil; //!< Frame Buffer Memory Util Value + unsigned int encUtil; //!< Encoder Util Value + unsigned int decUtil; //!< Decoder Util Value + unsigned int jpgUtil; //!< Jpeg Util Value + unsigned int ofaUtil; //!< Ofa Util Value +} nvmlVgpuProcessUtilizationInfo_v1_t; + +/** + * Structure to store recent utilization, vgpuInstance and subprocess information for processes running on vGPU instances active on a device -- version 1 + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + unsigned int vgpuProcessCount; //!< Hold the number of processes running on vGPU instances + unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp + nvmlVgpuProcessUtilizationInfo_v1_t *vgpuProcUtilArray; //!< The array (allocated by caller) in which utilization of processes running on vGPU instances are returned +} nvmlVgpuProcessesUtilizationInfo_v1_t; +typedef nvmlVgpuProcessesUtilizationInfo_v1_t nvmlVgpuProcessesUtilizationInfo_t; +#define nvmlVgpuProcessesUtilizationInfo_v1 NVML_STRUCT_VERSION(VgpuProcessesUtilizationInfo, 1) + +/** + * Structure to store the information of vGPU runtime state -- version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + unsigned long long size; //!< OUT: The runtime state size of the vGPU instance +} nvmlVgpuRuntimeState_v1_t; +typedef nvmlVgpuRuntimeState_v1_t nvmlVgpuRuntimeState_t; +#define nvmlVgpuRuntimeState_v1 NVML_STRUCT_VERSION(VgpuRuntimeState, 1) + +/** + * vGPU scheduler policies + */ +#define NVML_VGPU_SCHEDULER_POLICY_UNKNOWN 0 +#define NVML_VGPU_SCHEDULER_POLICY_BEST_EFFORT 1 +#define NVML_VGPU_SCHEDULER_POLICY_EQUAL_SHARE 2 +#define NVML_VGPU_SCHEDULER_POLICY_FIXED_SHARE 3 + +#define NVML_SUPPORTED_VGPU_SCHEDULER_POLICY_COUNT 3 + +#define NVML_SCHEDULER_SW_MAX_LOG_ENTRIES 200 + +#define NVML_VGPU_SCHEDULER_ARR_DEFAULT 0 +#define NVML_VGPU_SCHEDULER_ARR_DISABLE 1 +#define NVML_VGPU_SCHEDULER_ARR_ENABLE 2 + +/** + * vGPU scheduler engine types + */ +#define NVML_VGPU_SCHEDULER_ENGINE_TYPE_GRAPHICS 1 + +/** + * Union to represent the vGPU Scheduler Parameters + */ +typedef union +{ + struct + { + unsigned int avgFactor; //!< Average factor in compensating the timeslice for Adaptive Round Robin mode + unsigned int timeslice; //!< The timeslice in ns for each software run list as configured, or the default value otherwise + } vgpuSchedDataWithARR; + + struct + { + unsigned int timeslice; //!< The timeslice in ns for each software run list as configured, or the default value otherwise + } vgpuSchedData; + +} nvmlVgpuSchedulerParams_t; + +/** + * Structure to store the state and logs of a software runlist + */ +typedef struct nvmlVgpuSchedulerLogEntries_st +{ + unsigned long long timestamp; //!< Timestamp in ns when this software runlist was preeempted + unsigned long long timeRunTotal; //!< Total time in ns this software runlist has run + unsigned long long timeRun; //!< Time in ns this software runlist ran before preemption + unsigned int swRunlistId; //!< Software runlist Id + unsigned long long targetTimeSlice; //!< The actual timeslice after deduction + unsigned long long cumulativePreemptionTime; //!< Preemption time in ns for this SW runlist +} nvmlVgpuSchedulerLogEntry_t; + +/** + * Structure to store a vGPU software scheduler log + */ +typedef struct nvmlVgpuSchedulerLog_st +{ + unsigned int engineId; //!< Engine whose software runlist log entries are fetched + unsigned int schedulerPolicy; //!< Scheduler policy + unsigned int arrMode; //!< Adaptive Round Robin scheduler mode. One of the NVML_VGPU_SCHEDULER_ARR_*. + nvmlVgpuSchedulerParams_t schedulerParams; + unsigned int entriesCount; //!< Count of log entries fetched + nvmlVgpuSchedulerLogEntry_t logEntries[NVML_SCHEDULER_SW_MAX_LOG_ENTRIES]; +} nvmlVgpuSchedulerLog_t; + +/** + * Structure to store the vGPU scheduler state + */ +typedef struct nvmlVgpuSchedulerGetState_st +{ + unsigned int schedulerPolicy; //!< Scheduler policy + unsigned int arrMode; //!< Adaptive Round Robin scheduler mode. One of the NVML_VGPU_SCHEDULER_ARR_*. + nvmlVgpuSchedulerParams_t schedulerParams; +} nvmlVgpuSchedulerGetState_t; + +/** + * Union to represent the vGPU Scheduler set Parameters + */ +typedef union +{ + struct + { + unsigned int avgFactor; //!< Average factor in compensating the timeslice for Adaptive Round Robin mode + unsigned int frequency; //!< Frequency for Adaptive Round Robin mode + } vgpuSchedDataWithARR; + + struct + { + unsigned int timeslice; //!< The timeslice in ns(Nanoseconds) for each software run list as configured, or the default value otherwise + } vgpuSchedData; + +} nvmlVgpuSchedulerSetParams_t; + +/** + * Structure to set the vGPU scheduler state + */ +typedef struct nvmlVgpuSchedulerSetState_st +{ + unsigned int schedulerPolicy; //!< Scheduler policy + unsigned int enableARRMode; //!< Adaptive Round Robin scheduler + nvmlVgpuSchedulerSetParams_t schedulerParams; +} nvmlVgpuSchedulerSetState_t; + +/** + * Structure to store the vGPU scheduler capabilities + */ +typedef struct nvmlVgpuSchedulerCapabilities_st +{ + unsigned int supportedSchedulers[NVML_SUPPORTED_VGPU_SCHEDULER_POLICY_COUNT]; //!< List the supported vGPU schedulers on the device + unsigned int maxTimeslice; //!< Maximum timeslice value in ns + unsigned int minTimeslice; //!< Minimum timeslice value in ns + unsigned int isArrModeSupported; //!< Flag to check Adaptive Round Robin mode enabled/disabled. + unsigned int maxFrequencyForARR; //!< Maximum frequency for Adaptive Round Robin mode + unsigned int minFrequencyForARR; //!< Minimum frequency for Adaptive Round Robin mode + unsigned int maxAvgFactorForARR; //!< Maximum averaging factor for Adaptive Round Robin mode + unsigned int minAvgFactorForARR; //!< Minimum averaging factor for Adaptive Round Robin mode +} nvmlVgpuSchedulerCapabilities_t; + +/** + * Structure to store the vGPU license expiry details + */ +typedef struct nvmlVgpuLicenseExpiry_st +{ + unsigned int year; //!< Year of license expiry + unsigned short month; //!< Month of license expiry + unsigned short day; //!< Day of license expiry + unsigned short hour; //!< Hour of license expiry + unsigned short min; //!< Minutes of license expiry + unsigned short sec; //!< Seconds of license expiry + unsigned char status; //!< License expiry status +} nvmlVgpuLicenseExpiry_t; + +/** + * vGPU license state + */ +#define NVML_GRID_LICENSE_STATE_UNKNOWN 0 //!< Unknown state +#define NVML_GRID_LICENSE_STATE_UNINITIALIZED 1 //!< Uninitialized state +#define NVML_GRID_LICENSE_STATE_UNLICENSED_UNRESTRICTED 2 //!< Unlicensed unrestricted state +#define NVML_GRID_LICENSE_STATE_UNLICENSED_RESTRICTED 3 //!< Unlicensed restricted state +#define NVML_GRID_LICENSE_STATE_UNLICENSED 4 //!< Unlicensed state +#define NVML_GRID_LICENSE_STATE_LICENSED 5 //!< Licensed state + +typedef struct nvmlVgpuLicenseInfo_st +{ + unsigned char isLicensed; //!< License status + nvmlVgpuLicenseExpiry_t licenseExpiry; //!< License expiry information + unsigned int currentState; //!< Current license state +} nvmlVgpuLicenseInfo_t; + +/** + * Structure to store license expiry date and time values + */ +typedef struct nvmlGridLicenseExpiry_st +{ + unsigned int year; //!< Year value of license expiry + unsigned short month; //!< Month value of license expiry + unsigned short day; //!< Day value of license expiry + unsigned short hour; //!< Hour value of license expiry + unsigned short min; //!< Minutes value of license expiry + unsigned short sec; //!< Seconds value of license expiry + unsigned char status; //!< License expiry status +} nvmlGridLicenseExpiry_t; + +/** + * Structure containing vGPU software licensable feature information + */ +typedef struct nvmlGridLicensableFeature_st +{ + nvmlGridLicenseFeatureCode_t featureCode; //!< Licensed feature code + unsigned int featureState; //!< Non-zero if feature is currently licensed, otherwise zero + char licenseInfo[NVML_GRID_LICENSE_BUFFER_SIZE]; //!< Deprecated. + char productName[NVML_GRID_LICENSE_BUFFER_SIZE]; //!< Product name of feature + unsigned int featureEnabled; //!< Non-zero if feature is enabled, otherwise zero + nvmlGridLicenseExpiry_t licenseExpiry; //!< License expiry structure containing date and time +} nvmlGridLicensableFeature_t; + +/** + * Structure to store vGPU software licensable features + */ +typedef struct nvmlGridLicensableFeatures_st +{ + int isGridLicenseSupported; //!< Non-zero if vGPU Software Licensing is supported on the system, otherwise zero + unsigned int licensableFeaturesCount; //!< Entries returned in \a gridLicensableFeatures array + nvmlGridLicensableFeature_t gridLicensableFeatures[NVML_GRID_LICENSE_FEATURE_MAX_COUNT]; //!< Array of vGPU software licensable features. +} nvmlGridLicensableFeatures_t; + +/** + * Enum describing the GPU Recovery Action + */ +typedef enum nvmlDeviceGpuRecoveryAction_s { + NVML_GPU_RECOVERY_ACTION_NONE = 0, + NVML_GPU_RECOVERY_ACTION_GPU_RESET = 1, + NVML_GPU_RECOVERY_ACTION_NODE_REBOOT = 2, + NVML_GPU_RECOVERY_ACTION_DRAIN_P2P = 3, + NVML_GPU_RECOVERY_ACTION_DRAIN_AND_RESET = 4, +} nvmlDeviceGpuRecoveryAction_t; + +/** + * Structure to store the vGPU type IDs -- version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + unsigned int vgpuCount; //!< IN/OUT: Number of vGPU types + nvmlVgpuTypeId_t *vgpuTypeIds; //!< OUT: List of vGPU type IDs +} nvmlVgpuTypeIdInfo_v1_t; +typedef nvmlVgpuTypeIdInfo_v1_t nvmlVgpuTypeIdInfo_t; +#define nvmlVgpuTypeIdInfo_v1 NVML_STRUCT_VERSION(VgpuTypeIdInfo, 1) + +/** + * Structure to store the maximum number of possible vGPU type IDs -- version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + nvmlVgpuTypeId_t vgpuTypeId; //!< IN: Handle to vGPU type + unsigned int maxInstancePerGI; //!< OUT: Maximum number of vGPU instances per GPU instance +} nvmlVgpuTypeMaxInstance_v1_t; +typedef nvmlVgpuTypeMaxInstance_v1_t nvmlVgpuTypeMaxInstance_t; +#define nvmlVgpuTypeMaxInstance_v1 NVML_STRUCT_VERSION(VgpuTypeMaxInstance, 1) + +/** + * Structure to store active vGPU instance information -- Version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + unsigned int vgpuCount; //!< IN/OUT: Count of the active vGPU instances + nvmlVgpuInstance_t *vgpuInstances; //!< IN/OUT: list of active vGPU instances +} nvmlActiveVgpuInstanceInfo_v1_t; +typedef nvmlActiveVgpuInstanceInfo_v1_t nvmlActiveVgpuInstanceInfo_t; +#define nvmlActiveVgpuInstanceInfo_v1 NVML_STRUCT_VERSION(ActiveVgpuInstanceInfo, 1) + +/** + * Structure to set vGPU scheduler state information -- version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + unsigned int engineId; //!< IN: One of NVML_VGPU_SCHEDULER_ENGINE_TYPE_*. + unsigned int schedulerPolicy; //!< IN: Scheduler policy + unsigned int enableARRMode; //!< IN: Adaptive Round Robin scheduler + nvmlVgpuSchedulerSetParams_t schedulerParams; //!< IN: vGPU Scheduler Parameters +} nvmlVgpuSchedulerState_v1_t; +typedef nvmlVgpuSchedulerState_v1_t nvmlVgpuSchedulerState_t; +#define nvmlVgpuSchedulerState_v1 NVML_STRUCT_VERSION(VgpuSchedulerState, 1) + +/** + * Structure to store vGPU scheduler state information -- Version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + unsigned int engineId; //!< IN: Engine whose software scheduler state info is fetched. One of NVML_VGPU_SCHEDULER_ENGINE_TYPE_*. + unsigned int schedulerPolicy; //!< OUT: Scheduler policy + unsigned int arrMode; //!< OUT: Adaptive Round Robin scheduler mode. One of the NVML_VGPU_SCHEDULER_ARR_*. + nvmlVgpuSchedulerParams_t schedulerParams; //!< OUT: vGPU Scheduler Parameters +} nvmlVgpuSchedulerStateInfo_v1_t; +typedef nvmlVgpuSchedulerStateInfo_v1_t nvmlVgpuSchedulerStateInfo_t; +#define nvmlVgpuSchedulerStateInfo_v1 NVML_STRUCT_VERSION(VgpuSchedulerStateInfo, 1) + +/** + * Structure to store vGPU scheduler log information -- Version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + unsigned int engineId; //!< IN: Engine whose software runlist log entries are fetched. One of One of NVML_VGPU_SCHEDULER_ENGINE_TYPE_*. + unsigned int schedulerPolicy; //!< OUT: Scheduler policy + unsigned int arrMode; //!< OUT: Adaptive Round Robin scheduler mode. One of the NVML_VGPU_SCHEDULER_ARR_*. + nvmlVgpuSchedulerParams_t schedulerParams; //!< OUT: vGPU Scheduler Parameters + unsigned int entriesCount; //!< OUT: Count of log entries fetched + nvmlVgpuSchedulerLogEntry_t logEntries[NVML_SCHEDULER_SW_MAX_LOG_ENTRIES]; //!< OUT: Structure to store the state and logs of a software runlist +} nvmlVgpuSchedulerLogInfo_v1_t; +typedef nvmlVgpuSchedulerLogInfo_v1_t nvmlVgpuSchedulerLogInfo_t; +#define nvmlVgpuSchedulerLogInfo_v1 NVML_STRUCT_VERSION(VgpuSchedulerLogInfo, 1) + +/** + * Structure to store creatable vGPU placement information -- version 1 + */ +typedef struct +{ + unsigned int version; //!< IN: The version number of this struct + nvmlVgpuTypeId_t vgpuTypeId; //!< IN: Handle to vGPU type + unsigned int count; //!< IN/OUT: Count of the placement IDs + unsigned int *placementIds; //!< IN/OUT: Placement IDs for the vGPU type + unsigned int placementSize; //!< OUT: The number of slots occupied by the vGPU type +} nvmlVgpuCreatablePlacementInfo_v1_t; +typedef nvmlVgpuCreatablePlacementInfo_v1_t nvmlVgpuCreatablePlacementInfo_t; +#define nvmlVgpuCreatablePlacementInfo_v1 NVML_STRUCT_VERSION(VgpuCreatablePlacementInfo, 1) + +/** @} */ +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlFieldValueEnums Field Value Enums + * @{ + */ +/***************************************************************************************************/ + +/** + * Field Identifiers. + * + * All Identifiers pertain to a device. Each ID is only used once and is guaranteed never to change. + */ +#define NVML_FI_DEV_ECC_CURRENT 1 //!< Current ECC mode. 1=Active. 0=Inactive +#define NVML_FI_DEV_ECC_PENDING 2 //!< Pending ECC mode. 1=Active. 0=Inactive +/* ECC Count Totals */ +#define NVML_FI_DEV_ECC_SBE_VOL_TOTAL 3 //!< Total single bit volatile ECC errors +#define NVML_FI_DEV_ECC_DBE_VOL_TOTAL 4 //!< Total double bit volatile ECC errors +#define NVML_FI_DEV_ECC_SBE_AGG_TOTAL 5 //!< Total single bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_DBE_AGG_TOTAL 6 //!< Total double bit aggregate (persistent) ECC errors +/* Individual ECC locations */ +#define NVML_FI_DEV_ECC_SBE_VOL_L1 7 //!< L1 cache single bit volatile ECC errors +#define NVML_FI_DEV_ECC_DBE_VOL_L1 8 //!< L1 cache double bit volatile ECC errors +#define NVML_FI_DEV_ECC_SBE_VOL_L2 9 //!< L2 cache single bit volatile ECC errors +#define NVML_FI_DEV_ECC_DBE_VOL_L2 10 //!< L2 cache double bit volatile ECC errors +#define NVML_FI_DEV_ECC_SBE_VOL_DEV 11 //!< Device memory single bit volatile ECC errors +#define NVML_FI_DEV_ECC_DBE_VOL_DEV 12 //!< Device memory double bit volatile ECC errors +#define NVML_FI_DEV_ECC_SBE_VOL_REG 13 //!< Register file single bit volatile ECC errors +#define NVML_FI_DEV_ECC_DBE_VOL_REG 14 //!< Register file double bit volatile ECC errors +#define NVML_FI_DEV_ECC_SBE_VOL_TEX 15 //!< Texture memory single bit volatile ECC errors +#define NVML_FI_DEV_ECC_DBE_VOL_TEX 16 //!< Texture memory double bit volatile ECC errors +#define NVML_FI_DEV_ECC_DBE_VOL_CBU 17 //!< CBU double bit volatile ECC errors +#define NVML_FI_DEV_ECC_SBE_AGG_L1 18 //!< L1 cache single bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_DBE_AGG_L1 19 //!< L1 cache double bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_SBE_AGG_L2 20 //!< L2 cache single bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_DBE_AGG_L2 21 //!< L2 cache double bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_SBE_AGG_DEV 22 //!< Device memory single bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_DBE_AGG_DEV 23 //!< Device memory double bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_SBE_AGG_REG 24 //!< Register File single bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_DBE_AGG_REG 25 //!< Register File double bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_SBE_AGG_TEX 26 //!< Texture memory single bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_DBE_AGG_TEX 27 //!< Texture memory double bit aggregate (persistent) ECC errors +#define NVML_FI_DEV_ECC_DBE_AGG_CBU 28 //!< CBU double bit aggregate ECC errors + +/* Page Retirement */ +#define NVML_FI_DEV_RETIRED_SBE 29 //!< Number of retired pages because of single bit errors +#define NVML_FI_DEV_RETIRED_DBE 30 //!< Number of retired pages because of double bit errors +#define NVML_FI_DEV_RETIRED_PENDING 31 //!< If any pages are pending retirement. 1=yes. 0=no. + +/** + * NVLink Flit Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L0 32 //!< NVLink flow control CRC Error Counter for Lane 0 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L1 33 //!< NVLink flow control CRC Error Counter for Lane 1 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L2 34 //!< NVLink flow control CRC Error Counter for Lane 2 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L3 35 //!< NVLink flow control CRC Error Counter for Lane 3 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L4 36 //!< NVLink flow control CRC Error Counter for Lane 4 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L5 37 //!< NVLink flow control CRC Error Counter for Lane 5 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL 38 //!< NVLink flow control CRC Error Counter total for all Lanes + +/** + * NVLink CRC Data Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L0 39 //!< NVLink data CRC Error Counter for Lane 0 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L1 40 //!< NVLink data CRC Error Counter for Lane 1 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L2 41 //!< NVLink data CRC Error Counter for Lane 2 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L3 42 //!< NVLink data CRC Error Counter for Lane 3 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L4 43 //!< NVLink data CRC Error Counter for Lane 4 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L5 44 //!< NVLink data CRC Error Counter for Lane 5 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL 45 //!< NvLink data CRC Error Counter total for all Lanes + +/** + * NVLink Replay Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L0 46 //!< NVLink Replay Error Counter for Lane 0 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L1 47 //!< NVLink Replay Error Counter for Lane 1 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L2 48 //!< NVLink Replay Error Counter for Lane 2 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L3 49 //!< NVLink Replay Error Counter for Lane 3 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L4 50 //!< NVLink Replay Error Counter for Lane 4 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L5 51 //!< NVLink Replay Error Counter for Lane 5 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL 52 //!< NVLink Replay Error Counter total for all Lanes + +/** + * NVLink Recovery Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L0 53 //!< NVLink Recovery Error Counter for Lane 0 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L1 54 //!< NVLink Recovery Error Counter for Lane 1 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L2 55 //!< NVLink Recovery Error Counter for Lane 2 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L3 56 //!< NVLink Recovery Error Counter for Lane 3 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L4 57 //!< NVLink Recovery Error Counter for Lane 4 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L5 58 //!< NVLink Recovery Error Counter for Lane 5 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL 59 //!< NVLink Recovery Error Counter total for all Lanes + +/* NvLink Bandwidth Counters */ +/* + * NVML_FI_DEV_NVLINK_BANDWIDTH_* field values are now deprecated. + * Please use the following field values instead: + * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_TX + * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_RX + * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_TX + * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_RX + */ +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L0 60 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 0 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L1 61 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 1 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L2 62 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 2 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L3 63 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 3 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L4 64 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 4 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L5 65 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 5 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_TOTAL 66 //!< NVLink Bandwidth Counter Total for Counter Set 0, All Lanes + +/* NvLink Bandwidth Counters */ +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L0 67 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 0 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L1 68 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 1 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L2 69 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 2 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L3 70 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 3 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L4 71 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 4 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L5 72 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 5 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_TOTAL 73 //!< NVLink Bandwidth Counter Total for Counter Set 1, All Lanes + +/* NVML Perf Policy Counters */ +#define NVML_FI_DEV_PERF_POLICY_POWER 74 //!< Perf Policy Counter for Power Policy +#define NVML_FI_DEV_PERF_POLICY_THERMAL 75 //!< Perf Policy Counter for Thermal Policy +#define NVML_FI_DEV_PERF_POLICY_SYNC_BOOST 76 //!< Perf Policy Counter for Sync boost Policy +#define NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT 77 //!< Perf Policy Counter for Board Limit +#define NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION 78 //!< Perf Policy Counter for Low GPU Utilization Policy +#define NVML_FI_DEV_PERF_POLICY_RELIABILITY 79 //!< Perf Policy Counter for Reliability Policy +#define NVML_FI_DEV_PERF_POLICY_TOTAL_APP_CLOCKS 80 //!< Perf Policy Counter for Total App Clock Policy +#define NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS 81 //!< Perf Policy Counter for Total Base Clocks Policy + +/* Memory temperatures */ +#define NVML_FI_DEV_MEMORY_TEMP 82 //!< Memory temperature for the device + +/* Energy Counter */ +#define NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION 83 //!< Total energy consumption for the GPU in mJ since the driver was last reloaded + +/** + * NVLink Speed + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L0 84 //!< NVLink Speed in MBps for Link 0 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L1 85 //!< NVLink Speed in MBps for Link 1 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L2 86 //!< NVLink Speed in MBps for Link 2 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L3 87 //!< NVLink Speed in MBps for Link 3 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L4 88 //!< NVLink Speed in MBps for Link 4 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L5 89 //!< NVLink Speed in MBps for Link 5 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_COMMON 90 //!< Common NVLink Speed in MBps for active links + +#define NVML_FI_DEV_NVLINK_LINK_COUNT 91 //!< Number of NVLinks present on the device + +#define NVML_FI_DEV_RETIRED_PENDING_SBE 92 //!< If any pages are pending retirement due to SBE. 1=yes. 0=no. +#define NVML_FI_DEV_RETIRED_PENDING_DBE 93 //!< If any pages are pending retirement due to DBE. 1=yes. 0=no. + +#define NVML_FI_DEV_PCIE_REPLAY_COUNTER 94 //!< PCIe replay counter +#define NVML_FI_DEV_PCIE_REPLAY_ROLLOVER_COUNTER 95 //!< PCIe replay rollover counter + +/** + * NVLink Flit Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L6 96 //!< NVLink flow control CRC Error Counter for Lane 6 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L7 97 //!< NVLink flow control CRC Error Counter for Lane 7 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L8 98 //!< NVLink flow control CRC Error Counter for Lane 8 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L9 99 //!< NVLink flow control CRC Error Counter for Lane 9 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L10 100 //!< NVLink flow control CRC Error Counter for Lane 10 +#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L11 101 //!< NVLink flow control CRC Error Counter for Lane 11 + +/** + * NVLink CRC Data Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L6 102 //!< NVLink data CRC Error Counter for Lane 6 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L7 103 //!< NVLink data CRC Error Counter for Lane 7 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L8 104 //!< NVLink data CRC Error Counter for Lane 8 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L9 105 //!< NVLink data CRC Error Counter for Lane 9 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L10 106 //!< NVLink data CRC Error Counter for Lane 10 +#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L11 107 //!< NVLink data CRC Error Counter for Lane 11 + +/** + * NVLink Replay Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L6 108 //!< NVLink Replay Error Counter for Lane 6 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L7 109 //!< NVLink Replay Error Counter for Lane 7 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L8 110 //!< NVLink Replay Error Counter for Lane 8 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L9 111 //!< NVLink Replay Error Counter for Lane 9 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L10 112 //!< NVLink Replay Error Counter for Lane 10 +#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L11 113 //!< NVLink Replay Error Counter for Lane 11 + +/** + * NVLink Recovery Error Counters + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L6 114 //!< NVLink Recovery Error Counter for Lane 6 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L7 115 //!< NVLink Recovery Error Counter for Lane 7 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L8 116 //!< NVLink Recovery Error Counter for Lane 8 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L9 117 //!< NVLink Recovery Error Counter for Lane 9 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L10 118 //!< NVLink Recovery Error Counter for Lane 10 +#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L11 119 //!< NVLink Recovery Error Counter for Lane 11 + +/* NvLink Bandwidth Counters */ +/* + * NVML_FI_DEV_NVLINK_BANDWIDTH_* field values are now deprecated. + * Please use the following field values instead: + * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_TX + * NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_RX + * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_TX + * NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_RX + */ +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L6 120 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 6 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L7 121 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 7 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L8 122 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 8 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L9 123 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 9 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L10 124 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 10 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L11 125 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 11 + +/* NvLink Bandwidth Counters */ +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L6 126 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 6 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L7 127 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 7 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L8 128 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 8 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L9 129 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 9 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L10 130 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 10 +#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L11 131 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 11 + +/** + * NVLink Speed + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L6 132 //!< NVLink Speed in MBps for Link 6 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L7 133 //!< NVLink Speed in MBps for Link 7 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L8 134 //!< NVLink Speed in MBps for Link 8 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L9 135 //!< NVLink Speed in MBps for Link 9 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L10 136 //!< NVLink Speed in MBps for Link 10 +#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L11 137 //!< NVLink Speed in MBps for Link 11 + +/** + * NVLink throughput counters field values + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + * A scopeId of UINT_MAX returns aggregate value summed up across all links + * for the specified counter type in fieldId. + */ +#define NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_TX 138 //!< NVLink TX Data throughput in KiB +#define NVML_FI_DEV_NVLINK_THROUGHPUT_DATA_RX 139 //!< NVLink RX Data throughput in KiB +#define NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_TX 140 //!< NVLink TX Data + protocol overhead in KiB +#define NVML_FI_DEV_NVLINK_THROUGHPUT_RAW_RX 141 //!< NVLink RX Data + protocol overhead in KiB + +/* Row Remapper */ +#define NVML_FI_DEV_REMAPPED_COR 142 //!< Number of remapped rows due to correctable errors +#define NVML_FI_DEV_REMAPPED_UNC 143 //!< Number of remapped rows due to uncorrectable errors +#define NVML_FI_DEV_REMAPPED_PENDING 144 //!< If any rows are pending remapping. 1=yes 0=no +#define NVML_FI_DEV_REMAPPED_FAILURE 145 //!< If any rows failed to be remapped 1=yes 0=no + +/** + * Remote device NVLink ID + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_REMOTE_NVLINK_ID 146 //!< Remote device NVLink ID + +/** + * NVSwitch: connected NVLink count + */ +#define NVML_FI_DEV_NVSWITCH_CONNECTED_LINK_COUNT 147 //!< Number of NVLinks connected to NVSwitch + +/* NvLink ECC Data Error Counters + * + * Lane ID needs to be specified in the scopeId field in nvmlFieldValue_t. + * + */ +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L0 148 //!< NVLink data ECC Error Counter for Link 0 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L1 149 //!< NVLink data ECC Error Counter for Link 1 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L2 150 //!< NVLink data ECC Error Counter for Link 2 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L3 151 //!< NVLink data ECC Error Counter for Link 3 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L4 152 //!< NVLink data ECC Error Counter for Link 4 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L5 153 //!< NVLink data ECC Error Counter for Link 5 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L6 154 //!< NVLink data ECC Error Counter for Link 6 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L7 155 //!< NVLink data ECC Error Counter for Link 7 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L8 156 //!< NVLink data ECC Error Counter for Link 8 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L9 157 //!< NVLink data ECC Error Counter for Link 9 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L10 158 //!< NVLink data ECC Error Counter for Link 10 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_L11 159 //!< NVLink data ECC Error Counter for Link 11 +#define NVML_FI_DEV_NVLINK_ECC_DATA_ERROR_COUNT_TOTAL 160 //!< NVLink data ECC Error Counter total for all Links + +/** + * NVLink Error Replay + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_ERROR_DL_REPLAY 161 //!< NVLink Replay Error Counter + //!< This is unsupported for Blackwell+. + //!< Please use NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_* +/** + * NVLink Recovery Error Counter + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_ERROR_DL_RECOVERY 162 //!< NVLink Recovery Error Counter + //!< This is unsupported for Blackwell+ + //!< Please use NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_* + +/** + * NVLink Recovery Error CRC Counter + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_ERROR_DL_CRC 163 //!< NVLink CRC Error Counter + //!< This is unsupported for Blackwell+ + //!< Please use NVML_FI_DEV_NVLINK_COUNT_LINK_RECOVERY_* + +/** + * NVLink Speed, State and Version field id 164, 165, and 166 + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_GET_SPEED 164 //!< NVLink Speed in MBps +#define NVML_FI_DEV_NVLINK_GET_STATE 165 //!< NVLink State - Active,Inactive +#define NVML_FI_DEV_NVLINK_GET_VERSION 166 //!< NVLink Version + +#define NVML_FI_DEV_NVLINK_GET_POWER_STATE 167 //!< NVLink Power state. 0=HIGH_SPEED 1=LOW_SPEED +#define NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD 168 //!< NVLink length of idle period (units can be found from + //!< NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_UNITS) before + //!< transitioning links to sleep state + +#define NVML_FI_DEV_PCIE_L0_TO_RECOVERY_COUNTER 169 //!< Device PEX error recovery counter + +#define NVML_FI_DEV_C2C_LINK_COUNT 170 //!< Number of C2C Links present on the device +#define NVML_FI_DEV_C2C_LINK_GET_STATUS 171 //!< C2C Link Status 0=INACTIVE 1=ACTIVE +#define NVML_FI_DEV_C2C_LINK_GET_MAX_BW 172 //!< C2C Link Speed in MBps for active links + +#define NVML_FI_DEV_PCIE_COUNT_CORRECTABLE_ERRORS 173 //!< PCIe Correctable Errors Counter +#define NVML_FI_DEV_PCIE_COUNT_NAKS_RECEIVED 174 //!< PCIe NAK Receive Counter +#define NVML_FI_DEV_PCIE_COUNT_RECEIVER_ERROR 175 //!< PCIe Receiver Error Counter +#define NVML_FI_DEV_PCIE_COUNT_BAD_TLP 176 //!< PCIe Bad TLP Counter +#define NVML_FI_DEV_PCIE_COUNT_NAKS_SENT 177 //!< PCIe NAK Send Counter +#define NVML_FI_DEV_PCIE_COUNT_BAD_DLLP 178 //!< PCIe Bad DLLP Counter +#define NVML_FI_DEV_PCIE_COUNT_NON_FATAL_ERROR 179 //!< PCIe Non Fatal Error Counter +#define NVML_FI_DEV_PCIE_COUNT_FATAL_ERROR 180 //!< PCIe Fatal Error Counter +#define NVML_FI_DEV_PCIE_COUNT_UNSUPPORTED_REQ 181 //!< PCIe Unsupported Request Counter +#define NVML_FI_DEV_PCIE_COUNT_LCRC_ERROR 182 //!< PCIe LCRC Error Counter +#define NVML_FI_DEV_PCIE_COUNT_LANE_ERROR 183 //!< PCIe Per Lane Error Counter. + +#define NVML_FI_DEV_IS_RESETLESS_MIG_SUPPORTED 184 //!< Device's Restless MIG Capability + +/** + * Retrieves power usage for this GPU in milliwatts. + * It is only available if power management mode is supported. See \ref nvmlDeviceGetPowerManagementMode and + * \ref nvmlDeviceGetPowerUsage. + * + * scopeId needs to be specified. It signifies: + * 0 - GPU Only Scope - Metrics for GPU are retrieved + * 1 - Module scope - Metrics for the module (e.g. CPU + GPU) are retrieved. + * Note: CPU here refers to NVIDIA CPU (e.g. Grace). x86 or non-NVIDIA ARM is not supported + */ +#define NVML_FI_DEV_POWER_AVERAGE 185 //!< GPU power averaged over 1 sec interval, supported on Ampere (except GA100) or newer architectures. +#define NVML_FI_DEV_POWER_INSTANT 186 //!< Current GPU power, supported on all architectures. +#define NVML_FI_DEV_POWER_MIN_LIMIT 187 //!< Minimum power limit in milliwatts. +#define NVML_FI_DEV_POWER_MAX_LIMIT 188 //!< Maximum power limit in milliwatts. +#define NVML_FI_DEV_POWER_DEFAULT_LIMIT 189 //!< Default power limit in milliwatts (limit which device boots with). +#define NVML_FI_DEV_POWER_CURRENT_LIMIT 190 //!< Limit currently enforced in milliwatts (This includes other limits set elsewhere. E.g. Out-of-band). +#define NVML_FI_DEV_ENERGY 191 //!< Total energy consumption (in mJ) since the driver was last reloaded. Same as \ref NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION for the GPU. +#define NVML_FI_DEV_POWER_REQUESTED_LIMIT 192 //!< Power limit requested by NVML or any other userspace client. + +/** + * GPU T.Limit temperature thresholds in degree Celsius + * + * These fields are supported on Ada and later architectures and supersedes \ref nvmlDeviceGetTemperatureThreshold. + */ +#define NVML_FI_DEV_TEMPERATURE_SHUTDOWN_TLIMIT 193 //!< T.Limit temperature after which GPU may shut down for HW protection +#define NVML_FI_DEV_TEMPERATURE_SLOWDOWN_TLIMIT 194 //!< T.Limit temperature after which GPU may begin HW slowdown +#define NVML_FI_DEV_TEMPERATURE_MEM_MAX_TLIMIT 195 //!< T.Limit temperature after which GPU may begin SW slowdown due to memory temperature +#define NVML_FI_DEV_TEMPERATURE_GPU_MAX_TLIMIT 196 //!< T.Limit temperature after which GPU may be throttled below base clock + +#define NVML_FI_DEV_PCIE_COUNT_TX_BYTES 197 //!< PCIe transmit bytes. Value can be wrapped. +#define NVML_FI_DEV_PCIE_COUNT_RX_BYTES 198 //!< PCIe receive bytes. Value can be wrapped. + +#define NVML_FI_DEV_IS_MIG_MODE_INDEPENDENT_MIG_QUERY_CAPABLE 199 //!< MIG mode independent, MIG query capable device. 1=yes. 0=no. + +#define NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD_MAX 200 //!< Max Nvlink Power Threshold. See NVML_FI_DEV_NVLINK_GET_POWER_THRESHOLD + +/** + * NVLink counter field id 201-225 + * + * Link ID needs to be specified in the scopeId field in nvmlFieldValue_t. + */ +#define NVML_FI_DEV_NVLINK_COUNT_XMIT_PACKETS 201 //!usedGpuMemory is not supported + + + unsigned long long time; //!< Amount of time in ms during which the compute context was active. The time is reported as 0 if + //!< the process is not terminated + + unsigned long long startTime; //!< CPU Timestamp in usec representing start time for the process + + unsigned int isRunning; //!< Flag to represent if the process is running (1 for running, 0 for terminated) + + unsigned int reserved[5]; //!< Reserved for future use +} nvmlAccountingStats_t; + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlEncoderStructs Encoder Structs + * @{ + */ +/***************************************************************************************************/ + +/** + * Represents type of encoder for capacity can be queried + */ +typedef enum nvmlEncoderQueryType_enum +{ + NVML_ENCODER_QUERY_H264 = 0x00, //!< H264 encoder + NVML_ENCODER_QUERY_HEVC = 0x01, //!< HEVC encoder + NVML_ENCODER_QUERY_AV1 = 0x02, //!< AV1 encoder + NVML_ENCODER_QUERY_UNKNOWN = 0xFF //!< Unknown encoder +}nvmlEncoderType_t; + +/** + * Structure to hold encoder session data + */ +typedef struct nvmlEncoderSessionInfo_st +{ + unsigned int sessionId; //!< Unique session ID + unsigned int pid; //!< Owning process ID + nvmlVgpuInstance_t vgpuInstance; //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero) + nvmlEncoderType_t codecType; //!< Video encoder type + unsigned int hResolution; //!< Current encode horizontal resolution + unsigned int vResolution; //!< Current encode vertical resolution + unsigned int averageFps; //!< Moving average encode frames per second + unsigned int averageLatency; //!< Moving average encode latency in microseconds +}nvmlEncoderSessionInfo_t; + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlFBCStructs Frame Buffer Capture Structures +* @{ +*/ +/***************************************************************************************************/ + +/** + * Represents frame buffer capture session type + */ +typedef enum nvmlFBCSessionType_enum +{ + NVML_FBC_SESSION_TYPE_UNKNOWN = 0, //!< Unknown + NVML_FBC_SESSION_TYPE_TOSYS, //!< ToSys + NVML_FBC_SESSION_TYPE_CUDA, //!< Cuda + NVML_FBC_SESSION_TYPE_VID, //!< Vid + NVML_FBC_SESSION_TYPE_HWENC //!< HEnc +} nvmlFBCSessionType_t; + +/** + * Structure to hold frame buffer capture sessions stats + */ +typedef struct nvmlFBCStats_st +{ + unsigned int sessionsCount; //!< Total no of sessions + unsigned int averageFPS; //!< Moving average new frames captured per second + unsigned int averageLatency; //!< Moving average new frame capture latency in microseconds +} nvmlFBCStats_t; + +#define NVML_NVFBC_SESSION_FLAG_DIFFMAP_ENABLED 0x00000001 //!< Bit specifying differential map state. +#define NVML_NVFBC_SESSION_FLAG_CLASSIFICATIONMAP_ENABLED 0x00000002 //!< Bit specifying classification map state. +#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_NO_WAIT 0x00000004 //!< Bit specifying if capture was requested as non-blocking call. +#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_INFINITE 0x00000008 //!< Bit specifying if capture was requested as blocking call. +#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_TIMEOUT 0x00000010 //!< Bit specifying if capture was requested as blocking call with timeout period. + +/** + * Structure to hold FBC session data + */ +typedef struct nvmlFBCSessionInfo_st +{ + unsigned int sessionId; //!< Unique session ID + unsigned int pid; //!< Owning process ID + nvmlVgpuInstance_t vgpuInstance; //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero) + unsigned int displayOrdinal; //!< Display identifier + nvmlFBCSessionType_t sessionType; //!< Type of frame buffer capture session + unsigned int sessionFlags; //!< Session flags (one or more of NVML_NVFBC_SESSION_FLAG_XXX). + unsigned int hMaxResolution; //!< Max horizontal resolution supported by the capture session + unsigned int vMaxResolution; //!< Max vertical resolution supported by the capture session + unsigned int hResolution; //!< Horizontal resolution requested by caller in capture call + unsigned int vResolution; //!< Vertical resolution requested by caller in capture call + unsigned int averageFPS; //!< Moving average new frames captured per second + unsigned int averageLatency; //!< Moving average new frame capture latency in microseconds +} nvmlFBCSessionInfo_t; + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlDrainDefs Drain State definitions + * @{ + */ +/***************************************************************************************************/ + +/** + * Is the GPU device to be removed from the kernel by nvmlDeviceRemoveGpu() + */ +typedef enum nvmlDetachGpuState_enum +{ + NVML_DETACH_GPU_KEEP = 0, + NVML_DETACH_GPU_REMOVE +} nvmlDetachGpuState_t; + +/** + * Parent bridge PCIe link state requested by nvmlDeviceRemoveGpu() + */ +typedef enum nvmlPcieLinkState_enum +{ + NVML_PCIE_LINK_KEEP = 0, + NVML_PCIE_LINK_SHUT_DOWN +} nvmlPcieLinkState_t; + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlConfidentialComputingDefs Confidential Computing definitions + * @{ + */ +/***************************************************************************************************/ +/** + * Confidential Compute CPU Capabilities values + */ +#define NVML_CC_SYSTEM_CPU_CAPS_NONE 0 +#define NVML_CC_SYSTEM_CPU_CAPS_AMD_SEV 1 +#define NVML_CC_SYSTEM_CPU_CAPS_INTEL_TDX 2 +#define NVML_CC_SYSTEM_CPU_CAPS_AMD_SEV_SNP 3 +#define NVML_CC_SYSTEM_CPU_CAPS_AMD_SNP_VTOM 4 + +/** + * Confidenial Compute GPU Capabilities values + */ +#define NVML_CC_SYSTEM_GPUS_CC_NOT_CAPABLE 0 +#define NVML_CC_SYSTEM_GPUS_CC_CAPABLE 1 + +typedef struct nvmlConfComputeSystemCaps_st { + unsigned int cpuCaps; + unsigned int gpusCaps; +} nvmlConfComputeSystemCaps_t; + +/** + * Confidential Compute DevTools Mode values + */ +#define NVML_CC_SYSTEM_DEVTOOLS_MODE_OFF 0 +#define NVML_CC_SYSTEM_DEVTOOLS_MODE_ON 1 + +/** + * Confidential Compute Environment values + */ +#define NVML_CC_SYSTEM_ENVIRONMENT_UNAVAILABLE 0 +#define NVML_CC_SYSTEM_ENVIRONMENT_SIM 1 +#define NVML_CC_SYSTEM_ENVIRONMENT_PROD 2 + +/** + * Confidential Compute Feature Status values + */ +#define NVML_CC_SYSTEM_FEATURE_DISABLED 0 +#define NVML_CC_SYSTEM_FEATURE_ENABLED 1 + +typedef struct nvmlConfComputeSystemState_st { + unsigned int environment; + unsigned int ccFeature; + unsigned int devToolsMode; +} nvmlConfComputeSystemState_t; + +/** + * Confidential Compute Multigpu mode values + */ +#define NVML_CC_SYSTEM_MULTIGPU_NONE 0 +#define NVML_CC_SYSTEM_MULTIGPU_PROTECTED_PCIE 1 +#define NVML_CC_SYSTEM_MULTIGPU_NVLE 2 + +/** + * Confidential Compute System settings + */ +typedef struct { + unsigned int version; + unsigned int environment; + unsigned int ccFeature; + unsigned int devToolsMode; + unsigned int multiGpuMode; +} nvmlSystemConfComputeSettings_v1_t; + +typedef nvmlSystemConfComputeSettings_v1_t nvmlSystemConfComputeSettings_t; +#define nvmlSystemConfComputeSettings_v1 NVML_STRUCT_VERSION(SystemConfComputeSettings, 1) + +/** + * Protected memory size + */ +typedef struct +nvmlConfComputeMemSizeInfo_st +{ + unsigned long long protectedMemSizeKib; + unsigned long long unprotectedMemSizeKib; +} nvmlConfComputeMemSizeInfo_t; + +/** + * Confidential Compute GPUs/System Ready State values + */ +#define NVML_CC_ACCEPTING_CLIENT_REQUESTS_FALSE 0 +#define NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE 1 + +/** + * GPU Certificate Details + */ +#define NVML_GPU_CERT_CHAIN_SIZE 0x1000 +#define NVML_GPU_ATTESTATION_CERT_CHAIN_SIZE 0x1400 + +typedef struct nvmlConfComputeGpuCertificate_st { + unsigned int certChainSize; + unsigned int attestationCertChainSize; + unsigned char certChain[NVML_GPU_CERT_CHAIN_SIZE]; + unsigned char attestationCertChain[NVML_GPU_ATTESTATION_CERT_CHAIN_SIZE]; +} nvmlConfComputeGpuCertificate_t; + +/** + * GPU Attestation Report + */ +#define NVML_CC_GPU_CEC_NONCE_SIZE 0x20 +#define NVML_CC_GPU_ATTESTATION_REPORT_SIZE 0x2000 +#define NVML_CC_GPU_CEC_ATTESTATION_REPORT_SIZE 0x1000 +#define NVML_CC_CEC_ATTESTATION_REPORT_NOT_PRESENT 0 +#define NVML_CC_CEC_ATTESTATION_REPORT_PRESENT 1 +#define NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MIN 50 +#define NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MAX 65 + +typedef struct nvmlConfComputeGpuAttestationReport_st { + unsigned int isCecAttestationReportPresent; //!< output + unsigned int attestationReportSize; //!< output + unsigned int cecAttestationReportSize; //!< output + unsigned char nonce[NVML_CC_GPU_CEC_NONCE_SIZE]; //!< input: spdm supports 32 bytes on nonce + unsigned char attestationReport[NVML_CC_GPU_ATTESTATION_REPORT_SIZE]; //!< output + unsigned char cecAttestationReport[NVML_CC_GPU_CEC_ATTESTATION_REPORT_SIZE]; //!< output +} nvmlConfComputeGpuAttestationReport_t; + +typedef struct nvmlConfComputeSetKeyRotationThresholdInfo_st { + unsigned int version; + unsigned long long maxAttackerAdvantage; +} nvmlConfComputeSetKeyRotationThresholdInfo_v1_t; + +typedef nvmlConfComputeSetKeyRotationThresholdInfo_v1_t nvmlConfComputeSetKeyRotationThresholdInfo_t; +#define nvmlConfComputeSetKeyRotationThresholdInfo_v1 \ + NVML_STRUCT_VERSION(ConfComputeSetKeyRotationThresholdInfo, 1) + +typedef struct nvmlConfComputeGetKeyRotationThresholdInfo_st { + unsigned int version; + unsigned long long attackerAdvantage; +} nvmlConfComputeGetKeyRotationThresholdInfo_v1_t; + +typedef nvmlConfComputeGetKeyRotationThresholdInfo_v1_t nvmlConfComputeGetKeyRotationThresholdInfo_t; +#define nvmlConfComputeGetKeyRotationThresholdInfo_v1 \ + NVML_STRUCT_VERSION(ConfComputeGetKeyRotationThresholdInfo, 1) + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlFabricDefs Fabric definitions + * @{ + */ +/***************************************************************************************************/ + +#define NVML_GPU_FABRIC_UUID_LEN 16 //!< Length of Fabric UUID + +/** + * Fabric Probe States + */ +#define NVML_GPU_FABRIC_STATE_NOT_SUPPORTED 0 //!< Fabric Probe State not supported +#define NVML_GPU_FABRIC_STATE_NOT_STARTED 1 //!< Fabric Probe has not started +#define NVML_GPU_FABRIC_STATE_IN_PROGRESS 2 //!< Fabric Probe in progress +#define NVML_GPU_FABRIC_STATE_COMPLETED 3 //!< Fabric Probe State completed + +/** + * Probe State of GPU registration process + */ +typedef unsigned char nvmlGpuFabricState_t; + +/** + * Contains the device fabric information + */ +typedef struct +{ + unsigned char clusterUuid[NVML_GPU_FABRIC_UUID_LEN]; //!< Uuid of the cluster to which this GPU belongs + nvmlReturn_t status; //!< Error status, if any. Must be checked only if state returns "complete". + unsigned int cliqueId; //!< ID of the fabric clique to which this GPU belongs + nvmlGpuFabricState_t state; //!< Current state of GPU registration process. See NVML_GPU_FABRIC_STATE_* +} nvmlGpuFabricInfo_t; + +/** + * Fabric Degraded BW + */ +#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_NOT_SUPPORTED 0 //!< Fabric Health Mask: Degraded Bandwidth not supported +#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_TRUE 1 //!< Fabric Health Mask: Bandwidth degraded +#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_FALSE 2 //!< Fabric Health Mask: Bandwidth not degraded + +#define NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_DEGRADED_BW 0 //!< Fabric Health Mask Bit Shift for Degraded Bandwidth +#define NVML_GPU_FABRIC_HEALTH_MASK_WIDTH_DEGRADED_BW 0x3 //!< Fabric Health Mask Width for Degraded Bandwidth + +/** + * Fabric Route Recovery + */ +#define NVML_GPU_FABRIC_HEALTH_MASK_ROUTE_RECOVERY_NOT_SUPPORTED 0 //!< Fabric Health Mask: Route Recovery not supported +#define NVML_GPU_FABRIC_HEALTH_MASK_ROUTE_RECOVERY_TRUE 1 //!< Fabric Health Mask: Route Recovery in progress +#define NVML_GPU_FABRIC_HEALTH_MASK_ROUTE_RECOVERY_FALSE 2 //!< Fabric Health Mask: Route Recovery not in progress + +#define NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ROUTE_RECOVERY 2 //!< Fabric Health Mask Bit Shift for Route Recovery +#define NVML_GPU_FABRIC_HEALTH_MASK_WIDTH_ROUTE_RECOVERY 0x3 //!< Fabric Health Mask Width for Route Recovery + +/** + * Nvlink Fabric Route Unhealthy + */ +#define NVML_GPU_FABRIC_HEALTH_MASK_ROUTE_UNHEALTHY_NOT_SUPPORTED 0 //!< Fabric Health Mask: Route Unhealthy not supported +#define NVML_GPU_FABRIC_HEALTH_MASK_ROUTE_UNHEALTHY_TRUE 1 //!< Fabric Health Mask: Route is unhealthy +#define NVML_GPU_FABRIC_HEALTH_MASK_ROUTE_UNHEALTHY_FALSE 2 //!< Fabric Health Mask: Route is healthy + +#define NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ROUTE_UNHEALTHY 4 //!< Fabric Health Mask Bit Shift for Route Unhealthy +#define NVML_GPU_FABRIC_HEALTH_MASK_WIDTH_ROUTE_UNHEALTHY 0x3 //!< Fabric Health Mask Width for Route Unhealthy + +/** + * Fabric Access Timeout Recovery + */ +#define NVML_GPU_FABRIC_HEALTH_MASK_ACCESS_TIMEOUT_RECOVERY_NOT_SUPPORTED 0 //!< Fabric Health Mask: Access Timeout Recovery not supported +#define NVML_GPU_FABRIC_HEALTH_MASK_ACCESS_TIMEOUT_RECOVERY_TRUE 1 //!< Fabric Health Mask: Access Timeout Recovery in progress +#define NVML_GPU_FABRIC_HEALTH_MASK_ACCESS_TIMEOUT_RECOVERY_FALSE 2 //!< Fabric Health Mask: Access Timeout Recovery not in progress + +#define NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_ACCESS_TIMEOUT_RECOVERY 6 //!< Fabric Health Mask Bit Shift for Access Timeout Recovery +#define NVML_GPU_FABRIC_HEALTH_MASK_WIDTH_ACCESS_TIMEOUT_RECOVERY 0x3 //!< Fabric Health Mask Width for Access Timeout Recovery + +/** + * Fabric Incorrect Configuration + */ +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_NOT_SUPPORTED 0 //!< Fabric Health Mask: Incorrect Configuration not supported +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_NONE 1 //!< Fabric Health Mask: Correct Configuration +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INCORRECT_SYSGUID 2 //!< Fabric Health Mask: Incorrect Configuration - SysGUID +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INCORRECT_CHASSIS_SN 3 //!< Fabric Health Mask: Incorrect Configuration - Chassis Serial Number +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_NO_PARTITION 4 //!< Fabric Health Mask: Incorrect Configuration - No Partition +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INSUFFICIENT_NVLINKS 5 //!< Fabric Health Mask: Incorrect Configuration - Insufficient Nvlinks +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INCOMPATIBLE_GPU_FW 6 //!< Fabric Health Mask: Incorrect Configuration - Incompatible GPU Firmware +#define NVML_GPU_FABRIC_HEALTH_MASK_INCORRECT_CONFIGURATION_INVALID_LOCATION 7 //!< Fabric Health Mask: Incorrect Configuration - Invalid Location + +#define NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_INCORRECT_CONFIGURATION 8 //!< Fabric Health Mask Bit Shift for Incorrect Configuration +#define NVML_GPU_FABRIC_HEALTH_MASK_WIDTH_INCORRECT_CONFIGURATION 0xf //!< Fabric Health Mask Width for Incorrect Configuration + +/** + * Fabric Health + */ +#define NVML_GPU_FABRIC_HEALTH_SUMMARY_NOT_SUPPORTED 0 //!< Fabric Health Summary: Not supported +#define NVML_GPU_FABRIC_HEALTH_SUMMARY_HEALTHY 1 //!< Fabric Health Summary: Healthy +#define NVML_GPU_FABRIC_HEALTH_SUMMARY_UNHEALTHY 2 //!< Fabric Health Summary: Unhealthy +#define NVML_GPU_FABRIC_HEALTH_SUMMARY_LIMITED_CAPACITY 3 //!< Fabric Health Summary: Limited Capacity + +/** + * GPU Fabric Health Status Mask for various fields can be obtained + * using the below macro. + * Ex - NVML_GPU_FABRIC_HEALTH_GET(var, _DEGRADED_BW) + */ +#define NVML_GPU_FABRIC_HEALTH_GET(var, type) \ + (((var) >> NVML_GPU_FABRIC_HEALTH_MASK_SHIFT##type) & \ + (NVML_GPU_FABRIC_HEALTH_MASK_WIDTH##type)) + +/** + * GPU Fabric Health Status Mask for various fields can be tested + * using the below macro. + * Ex - NVML_GPU_FABRIC_HEALTH_TEST(var, _DEGRADED_BW, _TRUE) + */ +#define NVML_GPU_FABRIC_HEALTH_TEST(var, type, val) \ + (NVML_GPU_FABRIC_HEALTH_GET(var, type) == \ + NVML_GPU_FABRIC_HEALTH_MASK##type##val) + +/** +* GPU Fabric information (v2). +* +* @deprecated nvmlGpuFabricInfo_v2_t is deprecated and will be removed in a future release. +* Use nvmlGpuFabricInfo_v3_t instead +* +* Version 2 adds the \ref nvmlGpuFabricInfo_v2_t.version field +* to the start of the structure, and the \ref nvmlGpuFabricInfo_v2_t.healthMask +* field to the end. This structure is not backwards-compatible with +* \ref nvmlGpuFabricInfo_t. +*/ +typedef struct +{ + unsigned int version; //!< Structure version identifier (set to nvmlGpuFabricInfo_v2) + unsigned char clusterUuid[NVML_GPU_FABRIC_UUID_LEN]; //!< Uuid of the cluster to which this GPU belongs + nvmlReturn_t status; //!< Probe Error status, if any. Must be checked only if Probe state returns "complete". + unsigned int cliqueId; //!< ID of the fabric clique to which this GPU belongs + nvmlGpuFabricState_t state; //!< Current Probe State of GPU registration process. See NVML_GPU_FABRIC_STATE_* + unsigned int healthMask; //!< GPU Fabric health Status Mask. See NVML_GPU_FABRIC_HEALTH_MASK_* +} nvmlGpuFabricInfo_v2_t; + +/** +* Version identifier value for \ref nvmlGpuFabricInfo_v2_t.version. +*/ +#define nvmlGpuFabricInfo_v2 NVML_STRUCT_VERSION(GpuFabricInfo, 2) + +/** +* GPU Fabric information (v3). +*/ +typedef struct +{ + unsigned int version; //!< Structure version identifier (set to nvmlGpuFabricInfo_v2) + unsigned char clusterUuid[NVML_GPU_FABRIC_UUID_LEN]; //!< Uuid of the cluster to which this GPU belongs + nvmlReturn_t status; //!< Probe Error status, if any. Must be checked only if Probe state returns "complete". + unsigned int cliqueId; //!< ID of the fabric clique to which this GPU belongs + nvmlGpuFabricState_t state; //!< Current Probe State of GPU registration process. See NVML_GPU_FABRIC_STATE_* + unsigned int healthMask; //!< GPU Fabric health Status Mask. See NVML_GPU_FABRIC_HEALTH_MASK_* + unsigned char healthSummary; //!< GPU Fabric health summary. See NVML_GPU_FABRIC_HEALTH_SUMMARY_* +} nvmlGpuFabricInfo_v3_t; + +typedef nvmlGpuFabricInfo_v3_t nvmlGpuFabricInfoV_t; + +/** +* Version identifier value for \ref nvmlGpuFabricInfo_v3_t.version. +*/ +#define nvmlGpuFabricInfo_v3 NVML_STRUCT_VERSION(GpuFabricInfo, 3) + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlInitializationAndCleanup Initialization and Cleanup + * This chapter describes the methods that handle NVML initialization and cleanup. + * It is the user's responsibility to call \ref nvmlInit_v2() before calling any other methods, and + * nvmlShutdown() once NVML is no longer being used. + * @{ + */ +/***************************************************************************************************/ + +#define NVML_INIT_FLAG_NO_GPUS 1 //!< Don't fail nvmlInit() when no GPUs are found +#define NVML_INIT_FLAG_NO_ATTACH 2 //!< Don't attach GPUs + +/** + * Initialize NVML, but don't initialize any GPUs yet. + * + * \note nvmlInit_v3 introduces a "flags" argument, that allows passing boolean values + * modifying the behaviour of nvmlInit(). + * \note In NVML 5.319 new nvmlInit_v2 has replaced nvmlInit"_v1" (default in NVML 4.304 and older) that + * did initialize all GPU devices in the system. + * + * This allows NVML to communicate with a GPU + * when other GPUs in the system are unstable or in a bad state. When using this API, GPUs are + * discovered and initialized in nvmlDeviceGetHandleBy* functions instead. + * + * \note To contrast nvmlInit_v2 with nvmlInit"_v1", NVML 4.304 nvmlInit"_v1" will fail when any detected GPU is in + * a bad or unstable state. + * + * For all products. + * + * This method, should be called once before invoking any other methods in the library. + * A reference count of the number of initializations is maintained. Shutdown only occurs + * when the reference count reaches zero. + * + * @return + * - \ref NVML_SUCCESS if NVML has been properly initialized + * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running + * - \ref NVML_ERROR_NO_PERMISSION if NVML does not have permission to talk to the driver + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlInit_v2(void); + +/** + * nvmlInitWithFlags is a variant of nvmlInit(), that allows passing a set of boolean values + * modifying the behaviour of nvmlInit(). + * Other than the "flags" parameter it is completely similar to \ref nvmlInit_v2. + * + * For all products. + * + * @param flags behaviour modifier flags + * + * @return + * - \ref NVML_SUCCESS if NVML has been properly initialized + * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running + * - \ref NVML_ERROR_NO_PERMISSION if NVML does not have permission to talk to the driver + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlInitWithFlags(unsigned int flags); + +/** + * Shut down NVML by releasing all GPU resources previously allocated with \ref nvmlInit_v2(). + * + * For all products. + * + * This method should be called after NVML work is done, once for each call to \ref nvmlInit_v2() + * A reference count of the number of initializations is maintained. Shutdown only occurs + * when the reference count reaches zero. For backwards compatibility, no error is reported if + * nvmlShutdown() is called more times than nvmlInit(). + * + * @return + * - \ref NVML_SUCCESS if NVML has been properly shut down + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlShutdown(void); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlErrorReporting Error reporting + * This chapter describes helper functions for error reporting routines. + * @{ + */ +/***************************************************************************************************/ + +/** + * Helper method for converting NVML error codes into readable strings. + * + * For all products. + * + * @param result NVML error code to convert + * + * @return String representation of the error. + * + */ +const DECLDIR char* nvmlErrorString(nvmlReturn_t result); +/** @} */ + + +/***************************************************************************************************/ +/** @defgroup nvmlConstants Constants + * @{ + */ +/***************************************************************************************************/ + +/** + * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetInforomVersion and \ref nvmlDeviceGetInforomImageVersion + */ +#define NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE 16 + +/** + * Buffer size guaranteed to be large enough for storing GPU identifiers. + */ +#define NVML_DEVICE_UUID_BUFFER_SIZE 80 + +/** + * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetUUID + */ +#define NVML_DEVICE_UUID_V2_BUFFER_SIZE 96 + +/** + * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetBoardPartNumber + */ +#define NVML_DEVICE_PART_NUMBER_BUFFER_SIZE 80 + +/** + * Buffer size guaranteed to be large enough for \ref nvmlSystemGetDriverVersion + */ +#define NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE 80 + +/** + * Buffer size guaranteed to be large enough for \ref nvmlSystemGetNVMLVersion + */ +#define NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE 80 + +/** + * Buffer size guaranteed to be large enough for storing GPU device names. + */ +#define NVML_DEVICE_NAME_BUFFER_SIZE 64 + +/** + * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetName + */ +#define NVML_DEVICE_NAME_V2_BUFFER_SIZE 96 + +/** + * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetSerial + */ +#define NVML_DEVICE_SERIAL_BUFFER_SIZE 30 + +/** + * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetVbiosVersion + */ +#define NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE 32 + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlSystemQueries System Queries + * This chapter describes the queries that NVML can perform against the local system. These queries + * are not device-specific. + * @{ + */ +/***************************************************************************************************/ + +/** + * Retrieves the version of the system's graphics driver. + * + * For all products. + * + * The version identifier is an alphanumeric string. It will not exceed 80 characters in length + * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. + * + * @param version Reference in which to return the version identifier + * @param length The maximum allowed length of the string returned in \a version + * + * @return + * - \ref NVML_SUCCESS if \a version has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + */ +nvmlReturn_t DECLDIR nvmlSystemGetDriverVersion(char *version, unsigned int length); + +/** + * Retrieves the version of the NVML library. + * + * For all products. + * + * The version identifier is an alphanumeric string. It will not exceed 80 characters in length + * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE. + * + * @param version Reference in which to return the version identifier + * @param length The maximum allowed length of the string returned in \a version + * + * @return + * - \ref NVML_SUCCESS if \a version has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + */ +nvmlReturn_t DECLDIR nvmlSystemGetNVMLVersion(char *version, unsigned int length); + +/** + * Retrieves the version of the CUDA driver. + * + * For all products. + * + * The CUDA driver version returned will be retreived from the currently installed version of CUDA. + * If the cuda library is not found, this function will return a known supported version number. + * + * @param cudaDriverVersion Reference in which to return the version identifier + * + * @return + * - \ref NVML_SUCCESS if \a cudaDriverVersion has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cudaDriverVersion is NULL + */ +nvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion(int *cudaDriverVersion); + +/** + * Retrieves the version of the CUDA driver from the shared library. + * + * For all products. + * + * The returned CUDA driver version by calling cuDriverGetVersion() + * + * @param cudaDriverVersion Reference in which to return the version identifier + * + * @return + * - \ref NVML_SUCCESS if \a cudaDriverVersion has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cudaDriverVersion is NULL + * - \ref NVML_ERROR_LIBRARY_NOT_FOUND if \a libcuda.so.1 or libcuda.dll is not found + * - \ref NVML_ERROR_FUNCTION_NOT_FOUND if \a cuDriverGetVersion() is not found in the shared library + */ +nvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion_v2(int *cudaDriverVersion); + +/** + * Macros for converting the CUDA driver version number to Major and Minor version numbers. + */ +#define NVML_CUDA_DRIVER_VERSION_MAJOR(v) ((v)/1000) +#define NVML_CUDA_DRIVER_VERSION_MINOR(v) (((v)%1000)/10) + +/** + * Gets name of the process with provided process id + * + * For all products. + * + * Returned process name is cropped to provided length. + * name string is encoded in ANSI. + * + * @param pid The identifier of the process + * @param name Reference in which to return the process name + * @param length The maximum allowed length of the string returned in \a name + * + * @return + * - \ref NVML_SUCCESS if \a name has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a name is NULL or \a length is 0. + * - \ref NVML_ERROR_NOT_FOUND if process doesn't exists + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlSystemGetProcessName(unsigned int pid, char *name, unsigned int length); + +/** + * Retrieves the IDs and firmware versions for any Host Interface Cards (HICs) in the system. + * + * For S-class products. + * + * The \a hwbcCount argument is expected to be set to the size of the input \a hwbcEntries array. + * The HIC must be connected to an S-class system for it to be reported by this function. + * + * @param hwbcCount Size of hwbcEntries array + * @param hwbcEntries Array holding information about hwbc + * + * @return + * - \ref NVML_SUCCESS if \a hwbcCount and \a hwbcEntries have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if either \a hwbcCount or \a hwbcEntries is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a hwbcCount indicates that the \a hwbcEntries array is too small + */ +nvmlReturn_t DECLDIR nvmlSystemGetHicVersion(unsigned int *hwbcCount, nvmlHwbcEntry_t *hwbcEntries); + +/** + * Retrieve the set of GPUs that have a CPU affinity with the given CPU number + * For all products. + * Supported on Linux only. + * + * @param cpuNumber The CPU number + * @param count When zero, is set to the number of matching GPUs such that \a deviceArray + * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count + * number of device handles. + * @param deviceArray An array of device handles for GPUs found with affinity to \a cpuNumber + * + * @return + * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cpuNumber, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count + * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature + * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery + */ +nvmlReturn_t DECLDIR nvmlSystemGetTopologyGpuSet(unsigned int cpuNumber, unsigned int *count, nvmlDevice_t *deviceArray); + +/** + * Structure to store Driver branch information + */ +typedef struct +{ + unsigned int version; //!< The version number of this struct + char branch[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< driver branch +} nvmlSystemDriverBranchInfo_v1_t; +typedef nvmlSystemDriverBranchInfo_v1_t nvmlSystemDriverBranchInfo_t; +#define nvmlSystemDriverBranchInfo_v1 NVML_STRUCT_VERSION(SystemDriverBranchInfo, 1) + +/** + * Retrieves the driver branch of the NVIDIA driver installed on the system. + * + * For all products. + * + * The branch identifier is an alphanumeric string. It will not exceed 80 characters in length + * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. + * + * @param branchInfo Pointer to the driver branch information structure \a nvmlSystemDriverBranchInfo_t + * @param length The maximum allowed length of the driver branch string + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a branchInfo is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlSystemGetDriverBranch(nvmlSystemDriverBranchInfo_t *branchInfo, unsigned int length); + + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlUnitQueries Unit Queries + * This chapter describes that queries that NVML can perform against each unit. For S-class systems only. + * In each case the device is identified with an nvmlUnit_t handle. This handle is obtained by + * calling \ref nvmlUnitGetHandleByIndex(). + * @{ + */ +/***************************************************************************************************/ + + /** + * Retrieves the number of units in the system. + * + * For S-class products. + * + * @param unitCount Reference in which to return the number of units + * + * @return + * - \ref NVML_SUCCESS if \a unitCount has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unitCount is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlUnitGetCount(unsigned int *unitCount); + +/** + * Acquire the handle for a particular unit, based on its index. + * + * For S-class products. + * + * Valid indices are derived from the \a unitCount returned by \ref nvmlUnitGetCount(). + * For example, if \a unitCount is 2 the valid indices are 0 and 1, corresponding to UNIT 0 and UNIT 1. + * + * The order in which NVML enumerates units has no guarantees of consistency between reboots. + * + * @param index The index of the target unit, >= 0 and < \a unitCount + * @param unit Reference in which to return the unit handle + * + * @return + * - \ref NVML_SUCCESS if \a unit has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a unit is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlUnitGetHandleByIndex(unsigned int index, nvmlUnit_t *unit); + +/** + * Retrieves the static information associated with a unit. + * + * For S-class products. + * + * See \ref nvmlUnitInfo_t for details on available unit info. + * + * @param unit The identifier of the target unit + * @param info Reference in which to return the unit information + * + * @return + * - \ref NVML_SUCCESS if \a info has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a info is NULL + */ +nvmlReturn_t DECLDIR nvmlUnitGetUnitInfo(nvmlUnit_t unit, nvmlUnitInfo_t *info); + +/** + * Retrieves the LED state associated with this unit. + * + * For S-class products. + * + * See \ref nvmlLedState_t for details on allowed states. + * + * @param unit The identifier of the target unit + * @param state Reference in which to return the current LED state + * + * @return + * - \ref NVML_SUCCESS if \a state has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a state is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlUnitSetLedState() + */ +nvmlReturn_t DECLDIR nvmlUnitGetLedState(nvmlUnit_t unit, nvmlLedState_t *state); + +/** + * Retrieves the PSU stats for the unit. + * + * For S-class products. + * + * See \ref nvmlPSUInfo_t for details on available PSU info. + * + * @param unit The identifier of the target unit + * @param psu Reference in which to return the PSU information + * + * @return + * - \ref NVML_SUCCESS if \a psu has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a psu is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlUnitGetPsuInfo(nvmlUnit_t unit, nvmlPSUInfo_t *psu); + +/** + * Retrieves the temperature readings for the unit, in degrees C. + * + * For S-class products. + * + * Depending on the product, readings may be available for intake (type=0), + * exhaust (type=1) and board (type=2). + * + * @param unit The identifier of the target unit + * @param type The type of reading to take + * @param temp Reference in which to return the intake temperature + * + * @return + * - \ref NVML_SUCCESS if \a temp has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a type is invalid or \a temp is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlUnitGetTemperature(nvmlUnit_t unit, unsigned int type, unsigned int *temp); + +/** + * Retrieves the fan speed readings for the unit. + * + * For S-class products. + * + * See \ref nvmlUnitFanSpeeds_t for details on available fan speed info. + * + * @param unit The identifier of the target unit + * @param fanSpeeds Reference in which to return the fan speed information + * + * @return + * - \ref NVML_SUCCESS if \a fanSpeeds has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a fanSpeeds is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlUnitGetFanSpeedInfo(nvmlUnit_t unit, nvmlUnitFanSpeeds_t *fanSpeeds); + +/** + * Retrieves the set of GPU devices that are attached to the specified unit. + * + * For S-class products. + * + * The \a deviceCount argument is expected to be set to the size of the input \a devices array. + * + * @param unit The identifier of the target unit + * @param deviceCount Reference in which to provide the \a devices array size, and + * to return the number of attached GPU devices + * @param devices Reference in which to return the references to the attached GPU devices + * + * @return + * - \ref NVML_SUCCESS if \a deviceCount and \a devices have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a deviceCount indicates that the \a devices array is too small + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid, either of \a deviceCount or \a devices is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlUnitGetDevices(nvmlUnit_t unit, unsigned int *deviceCount, nvmlDevice_t *devices); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlDeviceQueries Device Queries + * This chapter describes that queries that NVML can perform against each device. + * In each case the device is identified with an nvmlDevice_t handle. This handle is obtained by + * calling one of \ref nvmlDeviceGetHandleByIndex_v2(), \ref nvmlDeviceGetHandleBySerial(), + * \ref nvmlDeviceGetHandleByPciBusId_v2(). or \ref nvmlDeviceGetHandleByUUID(). + * @{ + */ +/***************************************************************************************************/ + + /** + * Retrieves the number of compute devices in the system. A compute device is a single GPU. + * + * For all products. + * + * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system + * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. + * Update your code to handle this error, or use NVML 4.304 or older nvml header file. + * For backward binary compatibility reasons _v1 version of the API is still present in the shared + * library. + * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. + * + * @param deviceCount Reference in which to return the number of accessible devices + * + * @return + * - \ref NVML_SUCCESS if \a deviceCount has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a deviceCount is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCount_v2(unsigned int *deviceCount); + +/** + * Get attributes (engine counts etc.) for the given NVML device handle. + * + * @note This API currently only supports MIG device handles. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device NVML device handle + * @param attributes Device attributes + * + * @return + * - \ref NVML_SUCCESS if \a device attributes were successfully retrieved + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device handle is invalid + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAttributes_v2(nvmlDevice_t device, nvmlDeviceAttributes_t *attributes); + +/** + * Acquire the handle for a particular device, based on its index. + * + * For all products. + * + * Valid indices are derived from the \a accessibleDevices count returned by + * \ref nvmlDeviceGetCount_v2(). For example, if \a accessibleDevices is 2 the valid indices + * are 0 and 1, corresponding to GPU 0 and GPU 1. + * + * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it + * is recommended that devices be looked up by their PCI ids or UUID. See + * \ref nvmlDeviceGetHandleByUUID() and \ref nvmlDeviceGetHandleByPciBusId_v2(). + * + * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. + * + * Starting from NVML 5, this API causes NVML to initialize the target GPU + * NVML may initialize additional GPUs if: + * - The target GPU is an SLI slave + * + * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system + * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. + * Update your code to handle this error, or use NVML 4.304 or older nvml header file. + * For backward binary compatibility reasons _v1 version of the API is still present in the shared + * library. + * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. + * + * This means that nvmlDeviceGetHandleByIndex_v2 and _v1 can return different devices for the same index. + * If you don't touch macros that map old (_v1) versions to _v2 versions at the top of the file you don't + * need to worry about that. + * + * @param index The index of the target GPU, >= 0 and < \a accessibleDevices + * @param device Reference in which to return the device handle + * + * @return + * - \ref NVML_SUCCESS if \a device has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a device is NULL + * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device + * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetIndex + * @see nvmlDeviceGetCount + */ +nvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex_v2(unsigned int index, nvmlDevice_t *device); + +/** + * Acquire the handle for a particular device, based on its board serial number. + * + * For Fermi &tm; or newer fully supported devices. + * + * This number corresponds to the value printed directly on the board, and to the value returned by + * \ref nvmlDeviceGetSerial(). + * + * @deprecated Since more than one GPU can exist on a single board this function is deprecated in favor + * of \ref nvmlDeviceGetHandleByUUID. + * For dual GPU boards this function will return NVML_ERROR_INVALID_ARGUMENT. + * + * Starting from NVML 5, this API causes NVML to initialize the target GPU + * NVML may initialize additional GPUs as it searches for the target GPU + * + * @param serial The board serial number of the target GPU + * @param device Reference in which to return the device handle + * + * @return + * - \ref NVML_SUCCESS if \a device has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a serial is invalid, \a device is NULL or more than one + * device has the same serial (dual GPU boards) + * - \ref NVML_ERROR_NOT_FOUND if \a serial does not match a valid device on the system + * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables + * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs + * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetSerial + * @see nvmlDeviceGetHandleByUUID + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetHandleBySerial(const char *serial, nvmlDevice_t *device); + +/** + * Acquire the handle for a particular device, based on its globally unique immutable UUID (in ASCII format) associated with each device. + * + * For all products. + * + * @param uuid The UUID of the target GPU or MIG instance + * @param device Reference in which to return the device handle or MIG device handle + * + * Starting from NVML 5, this API causes NVML to initialize the target GPU + * NVML may initialize additional GPUs as it searches for the target GPU + * + * @return + * - \ref NVML_SUCCESS if \a device has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a uuid is invalid or \a device is null + * - \ref NVML_ERROR_NOT_FOUND if \a uuid does not match a valid device on the system + * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables + * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs + * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetUUID + */ +nvmlReturn_t DECLDIR nvmlDeviceGetHandleByUUID(const char *uuid, nvmlDevice_t *device); + +/** + * Acquire the handle for a particular device, based on its globally unique immutable UUID (in either ASCII or binary format) associated with each device. + * See \ref nvmlUUID_v1_t for more information on the UUID struct. The caller must set the appropriate version prior to calling this API. + * + * For all products. + * + * @param[in] uuid The UUID of the target GPU or MIG instance + * @param[out] device Reference in which to return the device handle or MIG device handle + * + * This API causes NVML to initialize the target GPU + * NVML may initialize additional GPUs as it searches for the target GPU + * + * @return + * - \ref NVML_SUCCESS if \a device has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a uuid is invalid, \a device is null or \a uuid->type is invalid + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported + * - \ref NVML_ERROR_NOT_FOUND if \a uuid does not match a valid device on the system + * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetHandleByUUIDV(const nvmlUUID_t *uuid, nvmlDevice_t *device); + +/** + * Acquire the handle for a particular device, based on its PCI bus id. + * + * For all products. + * + * This value corresponds to the nvmlPciInfo_t::busId returned by \ref nvmlDeviceGetPciInfo_v3(). + * + * Starting from NVML 5, this API causes NVML to initialize the target GPU + * NVML may initialize additional GPUs if: + * - The target GPU is an SLI slave + * + * \note NVML 4.304 and older version of nvmlDeviceGetHandleByPciBusId"_v1" returns NVML_ERROR_NOT_FOUND + * instead of NVML_ERROR_NO_PERMISSION. + * + * @param pciBusId The PCI bus id of the target GPU + * Accept the following formats (all numbers in hexadecimal): + * domain:bus:device.function in format %x:%x:%x.%x + * domain:bus:device in format %x:%x:%x + * bus:device.function in format %x:%x.%x + * + * @param device Reference in which to return the device handle + * + * @return + * - \ref NVML_SUCCESS if \a device has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciBusId is invalid or \a device is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a pciBusId does not match a valid device on the system + * - \ref NVML_ERROR_INSUFFICIENT_POWER if the attached device has improperly attached external power cables + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device + * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId_v2(const char *pciBusId, nvmlDevice_t *device); + +/** + * Retrieves the name of this device. + * + * For all products. + * + * The name is an alphanumeric string that denotes a particular product, e.g. Tesla &tm; C2070. It will not + * exceed 96 characters in length (including the NULL terminator). See \ref + * nvmlConstants::NVML_DEVICE_NAME_V2_BUFFER_SIZE. + * + * When used with MIG device handles the API returns MIG device names which can be used to identify devices + * based on their attributes. + * + * @param device The identifier of the target device + * @param name Reference in which to return the product name + * @param length The maximum allowed length of the string returned in \a name + * + * @return + * - \ref NVML_SUCCESS if \a name has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a name is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetName(nvmlDevice_t device, char *name, unsigned int length); + +/** + * Retrieves the brand of this device. + * + * For all products. + * + * The type is a member of \ref nvmlBrandType_t defined above. + * + * @param device The identifier of the target device + * @param type Reference in which to return the product brand type + * + * @return + * - \ref NVML_SUCCESS if \a name has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a type is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t *type); + +/** + * Retrieves the NVML index of this device. + * + * For all products. + * + * Valid indices are derived from the \a accessibleDevices count returned by + * \ref nvmlDeviceGetCount_v2(). For example, if \a accessibleDevices is 2 the valid indices + * are 0 and 1, corresponding to GPU 0 and GPU 1. + * + * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it + * is recommended that devices be looked up by their PCI ids or GPU UUID. See + * \ref nvmlDeviceGetHandleByPciBusId_v2() and \ref nvmlDeviceGetHandleByUUID(). + * + * When used with MIG device handles this API returns indices that can be + * passed to \ref nvmlDeviceGetMigDeviceHandleByIndex to retrieve an identical handle. + * MIG device indices are unique within a device. + * + * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. + * + * @param device The identifier of the target device + * @param index Reference in which to return the NVML index of the device + * + * @return + * - \ref NVML_SUCCESS if \a index has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a index is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetHandleByIndex() + * @see nvmlDeviceGetCount() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int *index); + +/** + * Retrieves the globally unique board serial number associated with this device's board. + * + * For all products with an inforom. + * + * The serial number is an alphanumeric string that will not exceed 30 characters (including the NULL terminator). + * This number matches the serial number tag that is physically attached to the board. See \ref + * nvmlConstants::NVML_DEVICE_SERIAL_BUFFER_SIZE. + * + * @param device The identifier of the target device + * @param serial Reference in which to return the board/module serial number + * @param length The maximum allowed length of the string returned in \a serial + * + * @return + * - \ref NVML_SUCCESS if \a serial has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a serial is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSerial(nvmlDevice_t device, char *serial, unsigned int length); + +/** + * Get a unique identifier for the device module on the baseboard + * + * This API retrieves a unique identifier for each GPU module that exists on a given baseboard. + * For non-baseboard products, this ID would always be 0. + * + * @param device The identifier of the target device + * @param moduleId Unique identifier for the GPU module + * + * @return + * - \ref NVML_SUCCESS if \a moduleId has been successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a moduleId is invalid + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetModuleId(nvmlDevice_t device, unsigned int *moduleId); + +/** + * Retrieves the Device's C2C Mode information + * + * @param device The identifier of the target device + * @param c2cModeInfo Output struct containing the device's C2C Mode info + * + * @return + * - \ref NVML_SUCCESS if \a C2C Mode Infor query is successful + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a serial is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetC2cModeInfoV(nvmlDevice_t device, nvmlC2cModeInfo_v1_t *c2cModeInfo); + +/***************************************************************************************************/ + +/** @defgroup nvmlAffinity CPU and Memory Affinity + * This chapter describes NVML operations that are associated with CPU and memory + * affinity. + * @{ + */ +/***************************************************************************************************/ + +//! Scope of NUMA node for affinity queries +#define NVML_AFFINITY_SCOPE_NODE 0 +//! Scope of processor socket for affinity queries +#define NVML_AFFINITY_SCOPE_SOCKET 1 + +typedef unsigned int nvmlAffinityScope_t; + +/** + * Retrieves an array of unsigned ints (sized to nodeSetSize) of bitmasks with + * the ideal memory affinity within node or socket for the device. + * For example, if NUMA node 0, 1 are ideal within the socket for the device and nodeSetSize == 1, + * result[0] = 0x3 + * + * \note If requested scope is not applicable to the target topology, the API + * will fall back to reporting the memory affinity for the immediate non-I/O + * ancestor of the device. + * + * For Kepler &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * @param nodeSetSize The size of the nodeSet array that is safe to access + * @param nodeSet Array reference in which to return a bitmask of NODEs, 64 NODEs per + * unsigned long on 64-bit machines, 32 on 32-bit machines + * @param scope Scope that change the default behavior + * + * @return + * - \ref NVML_SUCCESS if \a NUMA node Affinity has been filled + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, nodeSetSize == 0, nodeSet is NULL or scope is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ + +nvmlReturn_t DECLDIR nvmlDeviceGetMemoryAffinity(nvmlDevice_t device, unsigned int nodeSetSize, unsigned long *nodeSet, nvmlAffinityScope_t scope); + +/** + * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the + * ideal CPU affinity within node or socket for the device. + * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2, + * result[0] = 0x3, result[1] = 0x3 + * + * \note If requested scope is not applicable to the target topology, the API + * will fall back to reporting the CPU affinity for the immediate non-I/O + * ancestor of the device. + * + * For Kepler &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * @param cpuSetSize The size of the cpuSet array that is safe to access + * @param cpuSet Array reference in which to return a bitmask of CPUs, 64 CPUs per + * unsigned long on 64-bit machines, 32 on 32-bit machines + * @param scope Scope that change the default behavior + * + * @return + * - \ref NVML_SUCCESS if \a cpuAffinity has been filled + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, cpuSetSize == 0, cpuSet is NULL or sope is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ + +nvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinityWithinScope(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet, nvmlAffinityScope_t scope); + +/** + * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the ideal CPU affinity for the device + * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2, + * result[0] = 0x3, result[1] = 0x3 + * This is equivalent to calling \ref nvmlDeviceGetCpuAffinityWithinScope with \ref NVML_AFFINITY_SCOPE_NODE. + * + * For Kepler &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * @param cpuSetSize The size of the cpuSet array that is safe to access + * @param cpuSet Array reference in which to return a bitmask of CPUs, 64 CPUs per + * unsigned long on 64-bit machines, 32 on 32-bit machines + * + * @return + * - \ref NVML_SUCCESS if \a cpuAffinity has been filled + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, cpuSetSize == 0, or cpuSet is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinity(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet); + +/** + * Sets the ideal affinity for the calling thread and device using the guidelines + * given in nvmlDeviceGetCpuAffinity(). Note, this is a change as of version 8.0. + * Older versions set the affinity for a calling process and all children. + * Currently supports up to 1024 processors. + * + * For Kepler &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * + * @return + * - \ref NVML_SUCCESS if the calling process has been successfully bound + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetCpuAffinity(nvmlDevice_t device); + +/** + * Clear all affinity bindings for the calling thread. Note, this is a change as of version + * 8.0 as older versions cleared the affinity for a calling process and all children. + * + * For Kepler &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * + * @return + * - \ref NVML_SUCCESS if the calling process has been successfully unbound + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceClearCpuAffinity(nvmlDevice_t device); + +/** + * Get the NUMA node of the given GPU device. + * This only applies to platforms where the GPUs are NUMA nodes. + * + * @param[in] device The device handle + * @param[out] node NUMA node ID of the device + * + * @returns + * - \ref NVML_SUCCESS if the NUMA node is retrieved successfully + * - \ref NVML_ERROR_NOT_SUPPORTED if request is not supported on the current platform + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device \a node is invalid + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNumaNodeId(nvmlDevice_t device, unsigned int *node); + +/** + * Get the addressing mode for a given GPU. Addressing modes can be one of: + * 1. HMM: System allocated memory (malloc, mmap) is addressable from the device (GPU), + * via software-based mirroring of the CPU's page tables, on the GPU. + * 2. ATS: System allocated memory (malloc, mmap) is addressable from the device (GPU), + * via Address Translation Services. This means that there is (effectively) + * a single set of page tables, and the CPU and GPU both use them. + * 3. None: Neither HMM nor ATS is active. + * + * For Turing &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param[in] device The device handle + * @param[out] mode Pointer to addressing mode of the device + * + * @returns + * - \ref NVML_SUCCESS if \a mode is retrieved successfully + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported + * - \ref NVML_ERROR_NOT_SUPPORTED if request is not supported on the current platform + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device \a node is invalid + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAddressingMode(nvmlDevice_t device, nvmlDeviceAddressingMode_t *mode); + +/** + * Get the repair status for TPC/Channel repair + * + * For Ampere &tm; or newer fully supported devices. + * + * @param[in] device The identifier of the target device + * @param[out] repairStatus Reference to \a nvmlRepairStatus_t + * + * @return + * - \ref NVML_SUCCESS if the query was successful + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetRepairStatus(nvmlDevice_t device, nvmlRepairStatus_t *repairStatus); + +/** + * Retrieve the common ancestor for two devices + * For all products. + * Supported on Linux only. + * + * @param device1 The identifier of the first device + * @param device2 The identifier of the second device + * @param pathInfo A \ref nvmlGpuTopologyLevel_t that gives the path type + * + * @return + * - \ref NVML_SUCCESS if \a pathInfo has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1, or \a device2 is invalid, or \a pathInfo is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature + * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery + */ + +/** @} */ +nvmlReturn_t DECLDIR nvmlDeviceGetTopologyCommonAncestor(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuTopologyLevel_t *pathInfo); + +/** + * Retrieve the set of GPUs that are nearest to a given device at a specific interconnectivity level + * For all products. + * Supported on Linux only. + * + * @param device The identifier of the first device + * @param level The \ref nvmlGpuTopologyLevel_t level to search for other GPUs + * @param count When zero, is set to the number of matching GPUs such that \a deviceArray + * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count + * number of device handles. + * @param deviceArray An array of device handles for GPUs found at \a level + * + * @return + * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a level, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count + * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature + * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery + */ +nvmlReturn_t DECLDIR nvmlDeviceGetTopologyNearestGpus(nvmlDevice_t device, nvmlGpuTopologyLevel_t level, unsigned int *count, nvmlDevice_t *deviceArray); + +/** + * Retrieve the status for a given p2p capability index between a given pair of GPU + * + * @param device1 The first device + * @param device2 The second device + * @param p2pIndex p2p Capability Index being looked for between \a device1 and \a device2 + * @param p2pStatus Reference in which to return the status of the \a p2pIndex + * between \a device1 and \a device2 + * @return + * - \ref NVML_SUCCESS if \a p2pStatus has been populated + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1 or \a device2 or \a p2pIndex is invalid or \a p2pStatus is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetP2PStatus(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuP2PCapsIndex_t p2pIndex,nvmlGpuP2PStatus_t *p2pStatus); + +/** + * Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string, + * that augments the immutable, board serial identifier. + * + * For all products. + * + * The UUID is a globally unique identifier. It is the only available identifier for pre-Fermi-architecture products. + * It does NOT correspond to any identifier printed on the board. It will not exceed 96 characters in length + * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_UUID_V2_BUFFER_SIZE. + * + * When used with MIG device handles the API returns globally unique UUIDs which can be used to identify MIG + * devices across both GPU and MIG devices. UUIDs are immutable for the lifetime of a MIG device. + * + * @param device The identifier of the target device + * @param uuid Reference in which to return the GPU UUID + * @param length The maximum allowed length of the string returned in \a uuid + * + * @return + * - \ref NVML_SUCCESS if \a uuid has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a uuid is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetUUID(nvmlDevice_t device, char *uuid, unsigned int length); + +/** + * Retrieves minor number for the device. The minor number for the device is such that the Nvidia device node file for + * each GPU will have the form /dev/nvidia[minor number]. + * + * For all products. + * Supported only for Linux + * + * @param device The identifier of the target device + * @param minorNumber Reference in which to return the minor number for the device + * @return + * - \ref NVML_SUCCESS if the minor number is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minorNumber is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMinorNumber(nvmlDevice_t device, unsigned int *minorNumber); + +/** + * Retrieves the the device board part number which is programmed into the board's InfoROM + * + * For all products. + * + * @param device Identifier of the target device + * @param partNumber Reference to the buffer to return + * @param length Length of the buffer reference + * + * @return + * - \ref NVML_SUCCESS if \a partNumber has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_NOT_SUPPORTED if the needed VBIOS fields have not been filled + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a serial is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetBoardPartNumber(nvmlDevice_t device, char* partNumber, unsigned int length); + +/** + * Retrieves the version information for the device's infoROM object. + * + * For all products with an inforom. + * + * Fermi and higher parts have non-volatile on-board memory for persisting device info, such as aggregate + * ECC counts. The version of the data structures in this memory may change from time to time. It will not + * exceed 16 characters in length (including the NULL terminator). + * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. + * + * See \ref nvmlInforomObject_t for details on the available infoROM objects. + * + * @param device The identifier of the target device + * @param object The target infoROM object + * @param version Reference in which to return the infoROM version + * @param length The maximum allowed length of the string returned in \a version + * + * @return + * - \ref NVML_SUCCESS if \a version has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetInforomImageVersion + */ +nvmlReturn_t DECLDIR nvmlDeviceGetInforomVersion(nvmlDevice_t device, nvmlInforomObject_t object, char *version, unsigned int length); + +/** + * Retrieves the global infoROM image version + * + * For all products with an inforom. + * + * Image version just like VBIOS version uniquely describes the exact version of the infoROM flashed on the board + * in contrast to infoROM object version which is only an indicator of supported features. + * Version string will not exceed 16 characters in length (including the NULL terminator). + * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. + * + * @param device The identifier of the target device + * @param version Reference in which to return the infoROM image version + * @param length The maximum allowed length of the string returned in \a version + * + * @return + * - \ref NVML_SUCCESS if \a version has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetInforomVersion + */ +nvmlReturn_t DECLDIR nvmlDeviceGetInforomImageVersion(nvmlDevice_t device, char *version, unsigned int length); + +/** + * Retrieves the checksum of the configuration stored in the device's infoROM. + * + * For all products with an inforom. + * + * Can be used to make sure that two GPUs have the exact same configuration. + * Current checksum takes into account configuration stored in PWR and ECC infoROM objects. + * Checksum can change between driver releases or when user changes configuration (e.g. disable/enable ECC) + * + * @param device The identifier of the target device + * @param checksum Reference in which to return the infoROM configuration checksum + * + * @return + * - \ref NVML_SUCCESS if \a checksum has been set + * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's checksum couldn't be retrieved due to infoROM corruption + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a checksum is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetInforomConfigurationChecksum(nvmlDevice_t device, unsigned int *checksum); + +/** + * Reads the infoROM from the flash and verifies the checksums. + * + * For all products with an inforom. + * + * @param device The identifier of the target device + * + * @return + * - \ref NVML_SUCCESS if infoROM is not corrupted + * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's infoROM is corrupted + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceValidateInforom(nvmlDevice_t device); + +/** + * Retrieves the timestamp and the duration of the last flush of the BBX (blackbox) infoROM object during the current run. + * + * For all products with an inforom. + * + * @param device The identifier of the target device + * @param timestamp The start timestamp of the last BBX Flush + * @param durationUs The duration (us) of the last BBX Flush + * + * @return + * - \ref NVML_SUCCESS if \a timestamp and \a durationUs are successfully retrieved + * - \ref NVML_ERROR_NOT_READY if the BBX object has not been flushed yet + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetInforomVersion + */ +nvmlReturn_t DECLDIR nvmlDeviceGetLastBBXFlushTime(nvmlDevice_t device, unsigned long long *timestamp, + unsigned long *durationUs); + +/** + * Retrieves the display mode for the device. + * + * For all products. + * + * This method indicates whether a physical display (e.g. monitor) is currently connected to + * any of the device's connectors. + * + * See \ref nvmlEnableState_t for details on allowed modes. + * + * @param device The identifier of the target device + * @param display Reference in which to return the display mode + * + * @return + * - \ref NVML_SUCCESS if \a display has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a display is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDisplayMode(nvmlDevice_t device, nvmlEnableState_t *display); + +/** + * Retrieves the display active state for the device. + * + * For all products. + * + * This method indicates whether a display is initialized on the device. + * For example whether X Server is attached to this device and has allocated memory for the screen. + * + * Display can be active even when no monitor is physically attached. + * + * See \ref nvmlEnableState_t for details on allowed modes. + * + * @param device The identifier of the target device + * @param isActive Reference in which to return the display active state + * + * @return + * - \ref NVML_SUCCESS if \a isActive has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isActive is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDisplayActive(nvmlDevice_t device, nvmlEnableState_t *isActive); + +/** + * Retrieves the persistence mode associated with this device. + * + * For all products. + * For Linux only. + * + * When driver persistence mode is enabled the driver software state is not torn down when the last + * client disconnects. By default this feature is disabled. + * + * See \ref nvmlEnableState_t for details on allowed modes. + * + * @param device The identifier of the target device + * @param mode Reference in which to return the current driver persistence mode + * + * @return + * - \ref NVML_SUCCESS if \a mode has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetPersistenceMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t *mode); + +/** + * Retrieves PCI attributes of this device. + * + * For all products. + * + * See \ref nvmlPciInfoExt_v1_t for details on the available PCI info. + * + * @param device The identifier of the target device + * @param pci Reference in which to return the PCI info + * + * @return + * - \ref NVML_SUCCESS if \a pci has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pci is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPciInfoExt(nvmlDevice_t device, nvmlPciInfoExt_t *pci); + +/** + * Retrieves the PCI attributes of this device. + * + * For all products. + * + * See \ref nvmlPciInfo_t for details on the available PCI info. + * + * @param device The identifier of the target device + * @param pci Reference in which to return the PCI info + * + * @return + * - \ref NVML_SUCCESS if \a pci has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pci is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo_v3(nvmlDevice_t device, nvmlPciInfo_t *pci); + +/** + * Retrieves the maximum PCIe link generation possible with this device and system + * + * I.E. for a generation 2 PCIe device attached to a generation 1 PCIe bus the max link generation this function will + * report is generation 1. + * + * For Fermi &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param maxLinkGen Reference in which to return the max PCIe link generation + * + * @return + * - \ref NVML_SUCCESS if \a maxLinkGen has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkGen is null + * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGen); + +/** + * Retrieves the maximum PCIe link generation supported by this device + * + * For Fermi &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param maxLinkGenDevice Reference in which to return the max PCIe link generation + * + * @return + * - \ref NVML_SUCCESS if \a maxLinkGenDevice has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkGenDevice is null + * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGenDevice); + +/** + * Retrieves the maximum PCIe link width possible with this device and system + * + * I.E. for a device with a 16x PCIe bus width attached to a 8x PCIe system bus this function will report + * a max link width of 8. + * + * For Fermi &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param maxLinkWidth Reference in which to return the max PCIe link generation + * + * @return + * - \ref NVML_SUCCESS if \a maxLinkWidth has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkWidth is null + * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int *maxLinkWidth); + +/** + * Retrieves the current PCIe link generation + * + * For Fermi &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param currLinkGen Reference in which to return the current PCIe link generation + * + * @return + * - \ref NVML_SUCCESS if \a currLinkGen has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkGen is null + * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int *currLinkGen); + +/** + * Retrieves the current PCIe link width + * + * For Fermi &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param currLinkWidth Reference in which to return the current PCIe link generation + * + * @return + * - \ref NVML_SUCCESS if \a currLinkWidth has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkWidth is null + * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int *currLinkWidth); + +/** + * Retrieve PCIe utilization information. + * This function is querying a byte counter over a 20ms interval and thus is the + * PCIe throughput over that interval. + * + * For Maxwell &tm; or newer fully supported devices. + * + * This method is not supported in virtual machines running virtual GPU (vGPU). + * + * @param device The identifier of the target device + * @param counter The specific counter that should be queried \ref nvmlPcieUtilCounter_t + * @param value Reference in which to return throughput in KB/s + * + * @return + * - \ref NVML_SUCCESS if \a value has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a counter is invalid, or \a value is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPcieThroughput(nvmlDevice_t device, nvmlPcieUtilCounter_t counter, unsigned int *value); + +/** + * Retrieve the PCIe replay counter. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param value Reference in which to return the counter's value + * + * @return + * - \ref NVML_SUCCESS if \a value has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a value is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPcieReplayCounter(nvmlDevice_t device, unsigned int *value); + +/** + * Retrieves the current clock speeds for the device. + * + * For Fermi &tm; or newer fully supported devices. + * + * See \ref nvmlClockType_t for details on available clock information. + * + * @param device The identifier of the target device + * @param type Identify which clock domain to query + * @param clock Reference in which to return the clock speed in MHz + * + * @return + * - \ref NVML_SUCCESS if \a clock has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); + +/** + * Retrieves the maximum clock speeds for the device. + * + * For Fermi &tm; or newer fully supported devices. + * + * See \ref nvmlClockType_t for details on available clock information. + * + * \note Current P0 clocks (reported by \ref nvmlDeviceGetClockInfo) can differ from max clocks + * by a few MHz. + * + * @param device The identifier of the target device + * @param type Identify which clock domain to query + * @param clock Reference in which to return the clock speed in MHz + * + * @return + * - \ref NVML_SUCCESS if \a clock has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); + +/** + * Retrieve the GPCCLK VF offset value + * @param[in] device The identifier of the target device + * @param[out] offset The retrieved GPCCLK VF offset value + * + * @return + * - \ref NVML_SUCCESS if \a offset has been successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpcClkVfOffset(nvmlDevice_t device, int *offset); + +/** + * @deprecated Applications clocks are deprecated and will be removed in CUDA 14.0. + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); + +/** + * @deprecated Applications clocks are deprecated and will be removed in CUDA 14.0. + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetDefaultApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); + +/** + * Retrieves the clock speed for the clock specified by the clock type and clock ID. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param clockType Identify which clock domain to query + * @param clockId Identify which clock in the domain to query + * @param clockMHz Reference in which to return the clock in MHz + * + * @return + * - \ref NVML_SUCCESS if \a clockMHz has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetClock(nvmlDevice_t device, nvmlClockType_t clockType, nvmlClockId_t clockId, unsigned int *clockMHz); + +/** + * Retrieves the customer defined maximum boost clock speed specified by the given clock type. + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param clockType Identify which clock domain to query + * @param clockMHz Reference in which to return the clock in MHz + * + * @return + * - \ref NVML_SUCCESS if \a clockMHz has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device or the \a clockType on this device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMaxCustomerBoostClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); + +/** + * Retrieves the list of possible memory clocks that can be used as an argument for \ref nvmlDeviceSetMemoryLockedClocks. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param count Reference in which to provide the \a clocksMHz array size, and + * to return the number of elements + * @param clocksMHz Reference in which to return the clock in MHz + * + * @return + * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to the number of + * required elements) + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetMemoryLockedClocks + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSupportedMemoryClocks(nvmlDevice_t device, unsigned int *count, unsigned int *clocksMHz); + +/** + * Retrieves the list of possible graphics clocks that can be used as an argument for \ref nvmlDeviceSetGpuLockedClocks. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param memoryClockMHz Memory clock for which to return possible graphics clocks + * @param count Reference in which to provide the \a clocksMHz array size, and + * to return the number of elements + * @param clocksMHz Reference in which to return the clocks in MHz + * + * @return + * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_NOT_FOUND if the specified \a memoryClockMHz is not a supported frequency + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetGpuLockedClocks + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSupportedGraphicsClocks(nvmlDevice_t device, unsigned int memoryClockMHz, unsigned int *count, unsigned int *clocksMHz); + +/** + * Retrieve the current state of Auto Boosted clocks on a device and store it in \a isEnabled + * + * For Kepler &tm; or newer fully supported devices. + * + * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates + * to maximize performance as thermal limits allow. + * + * On Pascal and newer hardware, Auto Aoosted clocks are controlled through application clocks. + * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost + * behavior. + * + * @param device The identifier of the target device + * @param isEnabled Where to store the current state of Auto Boosted clocks of the target device + * @param defaultIsEnabled Where to store the default Auto Boosted clocks behavior of the target device that the device will + * revert to when no applications are using the GPU + * + * @return + * - \ref NVML_SUCCESS If \a isEnabled has been been set with the Auto Boosted clocks state of \a device + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isEnabled is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t *isEnabled, nvmlEnableState_t *defaultIsEnabled); + +/** + * Retrieves the intended operating speed of the device's fan. + * + * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the + * output will not match the actual fan speed. + * + * For all discrete products with dedicated fans. + * + * The fan speed is expressed as a percentage of the product's maximum noise tolerance fan speed. + * This value may exceed 100% in certain cases. + * + * @param device The identifier of the target device + * @param speed Reference in which to return the fan speed percentage + * + * @return + * - \ref NVML_SUCCESS if \a speed has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a speed is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed(nvmlDevice_t device, unsigned int *speed); + +/** + * Retrieves the intended operating speed of the device's specified fan. + * + * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the + * output will not match the actual fan speed. + * + * For all discrete products with dedicated fans. + * + * The fan speed is expressed as a percentage of the product's maximum noise tolerance fan speed. + * This value may exceed 100% in certain cases. + * + * @param device The identifier of the target device + * @param fan The index of the target fan, zero indexed. + * @param speed Reference in which to return the fan speed percentage + * + * @return + * - \ref NVML_SUCCESS if \a speed has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a fan is not an acceptable index, or \a speed is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan or is newer than Maxwell + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed_v2(nvmlDevice_t device, unsigned int fan, unsigned int * speed); + +/** + * Retrieves the intended operating speed in rotations per minute (RPM) of the device's specified fan. + * + * For Maxwell &tm; or newer fully supported devices. + * + * For all discrete products with dedicated fans. + * + * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the + * output will not match the actual fan speed. + * + * @param device The identifier of the target device + * @param fanSpeed Structure specifying the index of the target fan (input) and + * retrieved fan speed value (output) + * + * @return + * - \ref NVML_SUCCESS If everything worked + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, \a fan is not an acceptable + * index, or \a speed is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the provided version is invalid/unsupported + * - \ref NVML_ERROR_NOT_SUPPORTED If the \a device does not support this feature + */ +nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeedRPM(nvmlDevice_t device, nvmlFanSpeedInfo_t *fanSpeed); + +/** + * Retrieves the intended target speed of the device's specified fan. + * + * Normally, the driver dynamically adjusts the fan based on + * the needs of the GPU. But when user set fan speed using nvmlDeviceSetFanSpeed_v2, + * the driver will attempt to make the fan achieve the setting in + * nvmlDeviceSetFanSpeed_v2. The actual current speed of the fan + * is reported in nvmlDeviceGetFanSpeed_v2. + * + * For all discrete products with dedicated fans. + * + * The fan speed is expressed as a percentage of the product's maximum noise tolerance fan speed. + * This value may exceed 100% in certain cases. + * + * @param device The identifier of the target device + * @param fan The index of the target fan, zero indexed. + * @param targetSpeed Reference in which to return the fan speed percentage + * + * @return + * - \ref NVML_SUCCESS if \a speed has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a fan is not an acceptable index, or \a speed is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan or is newer than Maxwell + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetTargetFanSpeed(nvmlDevice_t device, unsigned int fan, unsigned int *targetSpeed); + +/** + * Retrieves the min and max fan speed that user can set for the GPU fan. + * + * For all cuda-capable discrete products with fans + * + * @param device The identifier of the target device + * @param minSpeed The minimum speed allowed to set + * @param maxSpeed The maximum speed allowed to set + * + * return + * NVML_SUCCESS if speed has been adjusted + * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * NVML_ERROR_INVALID_ARGUMENT if device is invalid + * NVML_ERROR_NOT_SUPPORTED if the device does not support this + * (doesn't have fans) + * NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMinMaxFanSpeed(nvmlDevice_t device, unsigned int * minSpeed, + unsigned int * maxSpeed); + +/** + * Gets current fan control policy. + * + * For Maxwell &tm; or newer fully supported devices. + * + * For all cuda-capable discrete products with fans + * + * device The identifier of the target \a device + * policy Reference in which to return the fan control \a policy + * + * return + * NVML_SUCCESS if \a policy has been populated + * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a policy is null or the \a fan given doesn't reference + * a fan that exists. + * NVML_ERROR_NOT_SUPPORTED if the \a device is older than Maxwell + * NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetFanControlPolicy_v2(nvmlDevice_t device, unsigned int fan, + nvmlFanControlPolicy_t *policy); + +/** + * Retrieves the number of fans on the device. + * + * For all discrete products with dedicated fans. + * + * @param device The identifier of the target device + * @param numFans The number of fans + * + * @return + * - \ref NVML_SUCCESS if \a fan number query was successful + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a numFans is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNumFans(nvmlDevice_t device, unsigned int *numFans); + +/** + * @deprecated Use \ref nvmlDeviceGetTemperatureV instead + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp); + +/** + * Retrieves the cooler's information. + * Returns a cooler's control signal characteristics. The possible types are restricted, Variable and Toggle. + * See \ref nvmlCoolerControl_t for details on available signal types. + * Returns objects that cooler cools. Targets may be GPU, Memory, Power Supply or All of these. + * See \ref nvmlCoolerTarget_t for details on available targets. + * + * For Maxwell &tm; or newer fully supported devices. + * + * For all discrete products with dedicated fans. + * + * @param[in] device The identifier of the target device + * @param[out] coolerInfo Structure specifying the cooler's control signal characteristics (out) + * and the target that cooler cools (out) + * + * @return + * - \ref NVML_SUCCESS If everything worked + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, \a signalType or \a target is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the provided version is invalid/unsupported + * - \ref NVML_ERROR_NOT_SUPPORTED If the \a device does not support this feature + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCoolerInfo(nvmlDevice_t device, nvmlCoolerInfo_t *coolerInfo); + +/** + * Structure used to encapsulate temperature info + */ +typedef struct +{ + unsigned int version; + nvmlTemperatureSensors_t sensorType; + int temperature; +} nvmlTemperature_v1_t; + +typedef nvmlTemperature_v1_t nvmlTemperature_t; + +#define nvmlTemperature_v1 NVML_STRUCT_VERSION(Temperature, 1) + +/** + * Retrieves the current temperature readings (in degrees C) for the given device. + * + * For all products. + * + * @param[in] device Target device identifier. + * @param[in,out] temperature Structure specifying the sensor type (input) and retrieved + * temperature value (output). + * + * @return + * - \ref NVML_SUCCESS if \a temp has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a sensorType is invalid or \a temp is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have the specified sensor + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetTemperatureV(nvmlDevice_t device, nvmlTemperature_t *temperature); + + +/** + * Retrieves the temperature threshold for the GPU with the specified threshold type in degrees C. + * + * For Kepler &tm; or newer fully supported devices. + * + * See \ref nvmlTemperatureThresholds_t for details on available temperature thresholds. + * + * Note: This API is no longer the preferred interface for retrieving the following temperature thresholds + * on Ada and later architectures: NVML_TEMPERATURE_THRESHOLD_SHUTDOWN, NVML_TEMPERATURE_THRESHOLD_SLOWDOWN, + * NVML_TEMPERATURE_THRESHOLD_MEM_MAX and NVML_TEMPERATURE_THRESHOLD_GPU_MAX. + * + * Support for reading these temperature thresholds for Ada and later architectures would be removed from this + * API in future releases. Please use \ref nvmlDeviceGetFieldValues with NVML_FI_DEV_TEMPERATURE_* fields to retrieve + * temperature thresholds on these architectures. + * + * @param device The identifier of the target device + * @param thresholdType The type of threshold value queried + * @param temp Reference in which to return the temperature reading + * @return + * - \ref NVML_SUCCESS if \a temp has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a thresholdType is invalid or \a temp is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a temperature sensor or is unsupported + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, unsigned int *temp); + +/** + * Retrieves the thermal margin temperature (distance to nearest slowdown threshold). + * + * @param[in] device The identifier of the target device + * @param[in,out] marginTempInfo Versioned structure in which to return the temperature reading + * + * @returns + * - \ref NVML_SUCCESS if the margin temperature was retrieved successfully + * - \ref NVML_ERROR_NOT_SUPPORTED if request is not supported on the current platform + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a temperature is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the right versioned structure is not used + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMarginTemperature(nvmlDevice_t device, nvmlMarginTemperature_t *marginTempInfo); + +/** + * Used to execute a list of thermal system instructions. + * + * @param device The identifier of the target device + * @param sensorIndex The index of the thermal sensor + * @param pThermalSettings Reference in which to return the thermal sensor information + * + * @return + * - \ref NVML_SUCCESS if \a pThermalSettings has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pThermalSettings is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetThermalSettings(nvmlDevice_t device, unsigned int sensorIndex, nvmlGpuThermalSettings_t *pThermalSettings); + +/** + * Retrieves the current performance state for the device. + * + * For Fermi &tm; or newer fully supported devices. + * + * See \ref nvmlPstates_t for details on allowed performance states. + * + * @param device The identifier of the target device + * @param pState Reference in which to return the performance state reading + * + * @return + * - \ref NVML_SUCCESS if \a pState has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPerformanceState(nvmlDevice_t device, nvmlPstates_t *pState); + +/** + * Retrieves current clocks event reasons. + * + * For all fully supported products. + * + * \note More than one bit can be enabled at the same time. Multiple reasons can be affecting clocks at once. + * + * @param device The identifier of the target device + * @param clocksEventReasons Reference in which to return bitmask of active clocks event + * reasons + * + * @return + * - \ref NVML_SUCCESS if \a clocksEventReasons has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clocksEventReasons is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlClocksEventReasons + * @see nvmlDeviceGetSupportedClocksEventReasons + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksEventReasons(nvmlDevice_t device, unsigned long long *clocksEventReasons); + +/** + * @deprecated Use \ref nvmlDeviceGetCurrentClocksEventReasons instead + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksThrottleReasons(nvmlDevice_t device, unsigned long long *clocksThrottleReasons); + +/** + * Retrieves bitmask of supported clocks event reasons that can be returned by + * \ref nvmlDeviceGetCurrentClocksEventReasons + * + * For all fully supported products. + * + * This method is not supported in virtual machines running virtual GPU (vGPU). + * + * @param device The identifier of the target device + * @param supportedClocksEventReasons Reference in which to return bitmask of supported + * clocks event reasons + * + * @return + * - \ref NVML_SUCCESS if \a supportedClocksEventReasons has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a supportedClocksEventReasons is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlClocksEventReasons + * @see nvmlDeviceGetCurrentClocksEventReasons + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksEventReasons(nvmlDevice_t device, unsigned long long *supportedClocksEventReasons); + +/** + * @deprecated Use \ref nvmlDeviceGetSupportedClocksEventReasons instead + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksThrottleReasons(nvmlDevice_t device, unsigned long long *supportedClocksThrottleReasons); + +/** + * @deprecated Use \ref nvmlDeviceGetPerformanceState. This function exposes an incorrect generalization. + * + * Retrieve the current performance state for the device. + * + * For Fermi &tm; or newer fully supported devices. + * + * See \ref nvmlPstates_t for details on allowed performance states. + * + * @param device The identifier of the target device + * @param pState Reference in which to return the performance state reading + * + * @return + * - \ref NVML_SUCCESS if \a pState has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetPowerState(nvmlDevice_t device, nvmlPstates_t *pState); + +/** + * Retrieve performance monitor samples from the associated subdevice. + * + * @param device + * @param pDynamicPstatesInfo + * + * @return + * - \ref NVML_SUCCESS if \a pDynamicPstatesInfo has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pDynamicPstatesInfo is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDynamicPstatesInfo(nvmlDevice_t device, nvmlGpuDynamicPstatesInfo_t *pDynamicPstatesInfo); + +/** + * Retrieve the MemClk (Memory Clock) VF offset value. + * @param[in] device The identifier of the target device + * @param[out] offset The retrieved MemClk VF offset value + * + * @return + * - \ref NVML_SUCCESS if \a offset has been successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMemClkVfOffset(nvmlDevice_t device, int *offset); + +/** + * Retrieve min and max clocks of some clock domain for a given PState + * + * @param device The identifier of the target device + * @param type Clock domain + * @param pstate PState to query + * @param minClockMHz Reference in which to return min clock frequency + * @param maxClockMHz Reference in which to return max clock frequency + * + * @return + * - \ref NVML_SUCCESS if everything worked + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a type or \a minClockMHz and \a maxClockMHz are NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_UNKNOWN if \a type or \a pstate are invalid or any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMinMaxClockOfPState(nvmlDevice_t device, nvmlClockType_t type, nvmlPstates_t pstate, + unsigned int * minClockMHz, unsigned int * maxClockMHz); + +/** + * Get all supported Performance States (P-States) for the device. + * + * The returned array would contain a contiguous list of valid P-States supported by + * the device. If the number of supported P-States is fewer than the size of the array + * supplied missing elements would contain \a NVML_PSTATE_UNKNOWN. + * + * The number of elements in the returned list will never exceed \a NVML_MAX_GPU_PERF_PSTATES. + * + * @param device The identifier of the target device + * @param pstates Container to return the list of performance states + * supported by device + * @param size Size of the supplied \a pstates array in bytes + * + * @return + * - \ref NVML_SUCCESS if \a pstates array has been retrieved + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if the the container supplied was not large enough to + * hold the resulting list + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a pstates is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support performance state readings + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSupportedPerformanceStates(nvmlDevice_t device, + nvmlPstates_t *pstates, unsigned int size); + +/** + * Retrieve the GPCCLK min max VF offset value. + * @param[in] device The identifier of the target device + * @param[out] minOffset The retrieved GPCCLK VF min offset value + * @param[out] maxOffset The retrieved GPCCLK VF max offset value + * + * @return + * - \ref NVML_SUCCESS if \a offset has been successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpcClkMinMaxVfOffset(nvmlDevice_t device, + int *minOffset, int *maxOffset); + +/** + * Retrieve the MemClk (Memory Clock) min max VF offset value. + * @param[in] device The identifier of the target device + * @param[out] minOffset The retrieved MemClk VF min offset value + * @param[out] maxOffset The retrieved MemClk VF max offset value + * + * @return + * - \ref NVML_SUCCESS if \a offset has been successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMemClkMinMaxVfOffset(nvmlDevice_t device, + int *minOffset, int *maxOffset); + +/** + * Retrieve min, max and current clock offset of some clock domain for a given PState + * + * For Maxwell &tm; or newer fully supported devices. + * + * Note: \ref nvmlDeviceGetGpcClkVfOffset, \ref nvmlDeviceGetMemClkVfOffset, \ref nvmlDeviceGetGpcClkMinMaxVfOffset and + * \ref nvmlDeviceGetMemClkMinMaxVfOffset will be deprecated in a future release. + Use \ref nvmlDeviceGetClockOffsets instead. + * + * @param device The identifier of the target device + * @param info Structure specifying the clock type (input) and the pstate (input) + * retrieved clock offset value (output), min clock offset (output) + * and max clock offset (output) + * + * @return + * - \ref NVML_SUCCESS If everything worked + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a type or \a pstate are invalid or both + * \a minClockOffsetMHz and \a maxClockOffsetMHz are NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the provided version is invalid/unsupported + * - \ref NVML_ERROR_NOT_SUPPORTED If the device does not support this feature + */ +nvmlReturn_t DECLDIR nvmlDeviceGetClockOffsets(nvmlDevice_t device, nvmlClockOffset_t *info); + +/** + * Control current clock offset of some clock domain for a given PState + * + * For Maxwell &tm; or newer fully supported devices. + * + * Requires privileged user. + * + * @param device The identifier of the target device + * @param info Structure specifying the clock type (input), the pstate (input) + * and clock offset value (input) + * + * @return + * - \ref NVML_SUCCESS If everything worked + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_NO_PERMISSION If the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a type or \a pstate are invalid or both + * \a clockOffsetMHz is out of allowed range. + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the provided version is invalid/unsupported + * - \ref NVML_ERROR_NOT_SUPPORTED If the device does not support this feature + */ +nvmlReturn_t DECLDIR nvmlDeviceSetClockOffsets(nvmlDevice_t device, nvmlClockOffset_t *info); + +/** + * Retrieves a performance mode string with all the + * performance modes defined for this device along with their associated + * GPU Clock and Memory Clock values. + * Not all tokens will be reported on all GPUs, and additional tokens + * may be added in the future. + * For backwards compatibility we still provide nvclock and memclock; + * those are the same as nvclockmin and memclockmin. + * + * Note: These clock values take into account the offset + * set by clients through /ref nvmlDeviceSetClockOffsets. + * + * Maximum available Pstate (P15) shows the minimum performance level (0) and vice versa. + * + * Each performance modes are returned as a comma-separated list of + * "token=value" pairs. Each set of performance mode tokens are separated + * by a ";". Valid tokens: + * + * Token Value + * "perf" unsigned int - the Performance level + * "nvclock" unsigned int - the GPU clocks (in MHz) for the perf level + * "nvclockmin" unsigned int - the GPU clocks min (in MHz) for the perf level + * "nvclockmax" unsigned int - the GPU clocks max (in MHz) for the perf level + * "nvclockeditable" unsigned int - if the GPU clock domain is editable for the perf level + * "memclock" unsigned int - the memory clocks (in MHz) for the perf level + * "memclockmin" unsigned int - the memory clocks min (in MHz) for the perf level + * "memclockmax" unsigned int - the memory clocks max (in MHz) for the perf level + * "memclockeditable" unsigned int - if the memory clock domain is editable for the perf level + * "memtransferrate" unsigned int - the memory transfer rate (in MHz) for the perf level + * "memtransferratemin" unsigned int - the memory transfer rate min (in MHz) for the perf level + * "memtransferratemax" unsigned int - the memory transfer rate max (in MHz) for the perf level + * "memtransferrateeditable" unsigned int - if the memory transfer rate is editable for the perf level + * + * Example: + * + * perf=0, nvclock=324, nvclockmin=324, nvclockmax=324, nvclockeditable=0, + * memclock=324, memclockmin=324, memclockmax=324, memclockeditable=0, + * memtransferrate=648, memtransferratemin=648, memtransferratemax=648, + * memtransferrateeditable=0 ; + * perf=1, nvclock=324, nvclockmin=324, nvclockmax=640, nvclockeditable=0, + * memclock=810, memclockmin=810, memclockmax=810, memclockeditable=0, + * memtransferrate=1620, memtransferrate=1620, memtransferrate=1620, + * memtransferrateeditable=0 ; + * + * + * @param device The identifier of the target device + * @param perfModes Reference in which to return the performance level string + * + * @return + * - \ref NVML_SUCCESS if \a perfModes has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a name is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPerformanceModes(nvmlDevice_t device, nvmlDevicePerfModes_t *perfModes); + +/** + * Retrieves a string with the associated current GPU Clock and Memory Clock values. + * + * Not all tokens will be reported on all GPUs, and additional tokens + * may be added in the future. + * + * Note: These clock values take into account the offset + * set by clients through /ref nvmlDeviceSetClockOffsets. + * + * Clock values are returned as a comma-separated list of + * "token=value" pairs. + * Valid tokens: + * + * Token Value + * "perf" unsigned int - the Performance level + * "nvclock" unsigned int - the GPU clocks (in MHz) for the perf level + * "nvclockmin" unsigned int - the GPU clocks min (in MHz) for the perf level + * "nvclockmax" unsigned int - the GPU clocks max (in MHz) for the perf level + * "nvclockeditable" unsigned int - if the GPU clock domain is editable for the perf level + * "memclock" unsigned int - the memory clocks (in MHz) for the perf level + * "memclockmin" unsigned int - the memory clocks min (in MHz) for the perf level + * "memclockmax" unsigned int - the memory clocks max (in MHz) for the perf level + * "memclockeditable" unsigned int - if the memory clock domain is editable for the perf level + * "memtransferrate" unsigned int - the memory transfer rate (in MHz) for the perf level + * "memtransferratemin" unsigned int - the memory transfer rate min (in MHz) for the perf level + * "memtransferratemax" unsigned int - the memory transfer rate max (in MHz) for the perf level + * "memtransferrateeditable" unsigned int - if the memory transfer rate is editable for the perf level + * + * Example: + * + * nvclock=324, nvclockmin=324, nvclockmax=324, nvclockeditable=0, + * memclock=324, memclockmin=324, memclockmax=324, memclockeditable=0, + * memtransferrate=648, memtransferratemin=648, memtransferratemax=648, + * memtransferrateeditable=0 ; + * + * + * @param device The identifier of the target device + * @param currentClockFreqs Reference in which to return the performance level string + * + * @return + * - \ref NVML_SUCCESS if \a currentClockFreqs has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a name is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClockFreqs(nvmlDevice_t device, nvmlDeviceCurrentClockFreqs_t *currentClockFreqs); + +/** + * @deprecated This API has been deprecated. + * + * Retrieves the power management mode associated with this device. + * + * For products from the Fermi family. + * - Requires \a NVML_INFOROM_POWER version 3.0 or higher. + * + * For from the Kepler or newer families. + * - Does not require \a NVML_INFOROM_POWER object. + * + * This flag indicates whether any power management algorithm is currently active on the device. An + * enabled state does not necessarily mean the device is being actively throttled -- only that + * that the driver will do so if the appropriate conditions are met. + * + * See \ref nvmlEnableState_t for details on allowed modes. + * + * @param device The identifier of the target device + * @param mode Reference in which to return the current power management mode + * + * @return + * - \ref NVML_SUCCESS if \a mode has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementMode(nvmlDevice_t device, nvmlEnableState_t *mode); + +/** + * Retrieves the power management limit associated with this device. + * + * For Fermi &tm; or newer fully supported devices. + * + * The power limit defines the upper boundary for the card's power draw. If + * the card's total power draw reaches this limit the power management algorithm kicks in. + * + * This reading is only available if power management mode is supported. + * See \ref nvmlDeviceGetPowerManagementMode. + * + * @param device The identifier of the target device + * @param limit Reference in which to return the power management limit in milliwatts + * + * @return + * - \ref NVML_SUCCESS if \a limit has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimit(nvmlDevice_t device, unsigned int *limit); + +/** + * Retrieves information about possible values of power management limits on this device. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param minLimit Reference in which to return the minimum power management limit in milliwatts + * @param maxLimit Reference in which to return the maximum power management limit in milliwatts + * + * @return + * - \ref NVML_SUCCESS if \a minLimit and \a maxLimit have been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minLimit or \a maxLimit is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetPowerManagementLimit + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimitConstraints(nvmlDevice_t device, unsigned int *minLimit, unsigned int *maxLimit); + +/** + * Retrieves default power management limit on this device, in milliwatts. + * Default power management limit is a power management limit that the device boots with. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param defaultLimit Reference in which to return the default power management limit in milliwatts + * + * @return + * - \ref NVML_SUCCESS if \a defaultLimit has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementDefaultLimit(nvmlDevice_t device, unsigned int *defaultLimit); + +/** + * Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory) + * + * For Fermi &tm; or newer fully supported devices. + * + * On Fermi and Kepler GPUs the reading is accurate to within +/- 5% of current power draw. On Ampere + * (except GA100) or newer GPUs, the API returns power averaged over 1 sec interval. On GA100 and + * older architectures, instantaneous power is returned. + * + * See \ref NVML_FI_DEV_POWER_AVERAGE and \ref NVML_FI_DEV_POWER_INSTANT to query specific power + * values. + * + * It is only available if power management mode is supported. See \ref nvmlDeviceGetPowerManagementMode. + * + * @param device The identifier of the target device + * @param power Reference in which to return the power usage information + * + * @return + * - \ref NVML_SUCCESS if \a power has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a power is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support power readings + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPowerUsage(nvmlDevice_t device, unsigned int *power); + +/** + * Retrieves current power mizer mode on this device. + * + * PowerMizerMode provides a hint to the driver as to how to manage the performance of the GPU. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param powerMizerMode Reference in which to return the power mizer mode + * @param supportedPowerMizerModes Reference in which to return the bitmask of supported power mizer modes on this device. + * The supported modes can be combined using the bitwise OR operator '|'. + * For example, if a device supports all PowerMizer modes, the bitmask would be: + * supportedPowerMizerModes = ((1 << NVML_POWER_MIZER_MODE_ADAPTIVE) | + * (1 << NVML_POWER_MIZER_MODE_PREFER_MAXIMUM_PERFORMANCE) | + * (1 << NVML_POWER_MIZER_MODE_AUTO) | + * (1 << NVML_POWER_MIZER_MODE_PREFER_CONSISTENT_PERFORMANCE)); + * This bitmask can be used to check which power mizer modes are available on the device by performing + * a bitwise AND operation with the specific mode you want to check. + * + * @return + * - \ref NVML_SUCCESS if \a powerMizerMode has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a powerMizerMode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support powerMizerMode readings + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ + +nvmlReturn_t DECLDIR nvmlDeviceGetPowerMizerMode_v1(nvmlDevice_t device, nvmlDevicePowerMizerModes_v1_t *powerMizerMode); + +/** + * Sets the new power mizer mode. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param powerMizerMode Reference in which to set the power mizer mode. + * + * @return + * - \ref NVML_SUCCESS if \a powerMizerMode has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a powerMizerMode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support powerMizerMode readings + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ + +nvmlReturn_t DECLDIR nvmlDeviceSetPowerMizerMode_v1(nvmlDevice_t device, nvmlDevicePowerMizerModes_v1_t *powerMizerMode); + + +/** + * Retrieves total energy consumption for this GPU in millijoules (mJ) since the driver was last reloaded + * + * For Volta &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param energy Reference in which to return the energy consumption information + * + * @return + * - \ref NVML_SUCCESS if \a energy has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a energy is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support energy readings + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetTotalEnergyConsumption(nvmlDevice_t device, unsigned long long *energy); + +/** + * Get the effective power limit that the driver enforces after taking into account all limiters + * + * Note: This can be different from the \ref nvmlDeviceGetPowerManagementLimit if other limits are set elsewhere + * This includes the out of band power limit interface + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The device to communicate with + * @param limit Reference in which to return the power management limit in milliwatts + * + * @return + * - \ref NVML_SUCCESS if \a limit has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetEnforcedPowerLimit(nvmlDevice_t device, unsigned int *limit); + +/** + * Retrieves the current GOM and pending GOM (the one that GPU will switch to after reboot). + * + * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. + * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. + * Not supported on Quadro ® and Tesla &tm; C-class products. + * + * @param device The identifier of the target device + * @param current Reference in which to return the current GOM + * @param pending Reference in which to return the pending GOM + * + * @return + * - \ref NVML_SUCCESS if \a mode has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a current or \a pending is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlGpuOperationMode_t + * @see nvmlDeviceSetGpuOperationMode + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t *current, nvmlGpuOperationMode_t *pending); + +/** + * Retrieves the amount of used, free, reserved and total memory available on the device, in bytes. + * The reserved amount is supported on version 2 only. + * + * For all products. + * + * Enabling ECC reduces the amount of total available memory, due to the extra required parity bits. + * Under WDDM most device memory is allocated and managed on startup by Windows. + * + * Under Linux and Windows TCC, the reported amount of used memory is equal to the sum of memory allocated + * by all active channels on the device. + * + * See \ref nvmlMemory_v2_t for details on available memory info. + * + * @note In MIG mode, if device handle is provided, the API returns aggregate + * information, only if the caller has appropriate privileges. Per-instance + * information can be queried by using specific MIG device handles. + * + * @note nvmlDeviceGetMemoryInfo_v2 adds additional memory information. + * + * @note On systems where GPUs are NUMA nodes, the accuracy of FB memory utilization + * provided by this API depends on the memory accounting of the operating system. + * This is because FB memory is managed by the operating system instead of the NVIDIA GPU driver. + * Typically, pages allocated from FB memory are not released even after + * the process terminates to enhance performance. In scenarios where + * the operating system is under memory pressure, it may resort to utilizing FB memory. + * Such actions can result in discrepancies in the accuracy of memory reporting. + * + * @note On certain SOC platforms, the integrated GPU (iGPU) does not use a dedicated framebuffer + * but instead shares memory with the system. As a result, \ref NVML_ERROR_NOT_SUPPORTED + * will be returned in this case. + * + * @param device The identifier of the target device + * @param memory Reference in which to return the memory information + * + * @return + * - \ref NVML_SUCCESS if \a memory has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_SUPPORTED if video memory is unsupported on the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t *memory); + +/** + * nvmlDeviceGetMemoryInfo_v2 accounts separately for reserved memory and includes it in the used memory amount. + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t *memory); + +/** + * Retrieves the current compute mode for the device. + * + * For all products. + * + * See \ref nvmlComputeMode_t for details on allowed compute modes. + * + * @param device The identifier of the target device + * @param mode Reference in which to return the current compute mode + * + * @return + * - \ref NVML_SUCCESS if \a mode has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetComputeMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetComputeMode(nvmlDevice_t device, nvmlComputeMode_t *mode); + +/** + * Retrieves the CUDA compute capability of the device. + * + * For all products. + * + * Returns the major and minor compute capability version numbers of the + * device. The major and minor versions are equivalent to the + * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR and + * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR attributes that would be + * returned by CUDA's cuDeviceGetAttribute(). + * + * @param device The identifier of the target device + * @param major Reference in which to return the major CUDA compute capability + * @param minor Reference in which to return the minor CUDA compute capability + * + * @return + * - \ref NVML_SUCCESS if \a major and \a minor have been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a major or \a minor are NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCudaComputeCapability(nvmlDevice_t device, int *major, int *minor); + +/** + * Retrieves the current and pending DRAM Encryption modes for the device. + * + * For Blackwell &tm; or newer fully supported devices. + * Only applicable to devices that support DRAM Encryption + * Requires \a NVML_INFOROM_DEN version 1.0 or higher. + * + * Changing DRAM Encryption modes requires a reboot. The "pending" DRAM Encryption mode refers to the target mode following + * the next reboot. + * + * See \ref nvmlEnableState_t for details on allowed modes. + * + * @param device The identifier of the target device + * @param current Reference in which to return the current DRAM Encryption mode + * @param pending Reference in which to return the pending DRAM Encryption mode + * + * @return + * - \ref NVML_SUCCESS if \a current and \a pending have been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or either \a current or \a pending is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the argument version is not supported + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetDramEncryptionMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDramEncryptionMode(nvmlDevice_t device, nvmlDramEncryptionInfo_t *current, nvmlDramEncryptionInfo_t *pending); + +/** + * Set the DRAM Encryption mode for the device. + * + * For Kepler &tm; or newer fully supported devices. + * Only applicable to devices that support DRAM Encryption. + * Requires \a NVML_INFOROM_DEN version 1.0 or higher. + * Requires root/admin permissions. + * + * The DRAM Encryption mode determines whether the GPU enables its DRAM Encryption support. + * + * This operation takes effect after the next reboot. + * + * See \ref nvmlEnableState_t for details on available modes. + * + * @param device The identifier of the target device + * @param dramEncryption The target DRAM Encryption mode + * + * @return + * - \ref NVML_SUCCESS if the DRAM Encryption mode was set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a DRAM Encryption is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the argument version is not supported + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetDramEncryptionMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceSetDramEncryptionMode(nvmlDevice_t device, const nvmlDramEncryptionInfo_t *dramEncryption); + +/** + * Retrieves the current and pending ECC modes for the device. + * + * For Fermi &tm; or newer fully supported devices. + * Only applicable to devices with ECC. + * Requires \a NVML_INFOROM_ECC version 1.0 or higher. + * + * Changing ECC modes requires a reboot. The "pending" ECC mode refers to the target mode following + * the next reboot. + * + * See \ref nvmlEnableState_t for details on allowed modes. + * + * @param device The identifier of the target device + * @param current Reference in which to return the current ECC mode + * @param pending Reference in which to return the pending ECC mode + * + * @return + * - \ref NVML_SUCCESS if \a current and \a pending have been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or either \a current or \a pending is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetEccMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetEccMode(nvmlDevice_t device, nvmlEnableState_t *current, nvmlEnableState_t *pending); + +/** + * Retrieves the default ECC modes for the device. + * + * For Fermi &tm; or newer fully supported devices. + * Only applicable to devices with ECC. + * Requires \a NVML_INFOROM_ECC version 1.0 or higher. + * + * See \ref nvmlEnableState_t for details on allowed modes. + * + * @param device The identifier of the target device + * @param defaultMode Reference in which to return the default ECC mode + * + * @return + * - \ref NVML_SUCCESS if \a current and \a pending have been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a default is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetEccMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDefaultEccMode(nvmlDevice_t device, nvmlEnableState_t *defaultMode); + +/** + * Retrieves the device boardId from 0-N. + * Devices with the same boardId indicate GPUs connected to the same PLX. Use in conjunction with + * \ref nvmlDeviceGetMultiGpuBoard() to decide if they are on the same board as well. + * The boardId returned is a unique ID for the current configuration. Uniqueness and ordering across + * reboots and system configurations is not guaranteed (i.e. if a Tesla K40c returns 0x100 and + * the two GPUs on a Tesla K10 in the same system returns 0x200 it is not guaranteed they will + * always return those values but they will always be different from each other). + * + * + * For Fermi &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param boardId Reference in which to return the device's board ID + * + * @return + * - \ref NVML_SUCCESS if \a boardId has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a boardId is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetBoardId(nvmlDevice_t device, unsigned int *boardId); + +/** + * Retrieves whether the device is on a Multi-GPU Board + * Devices that are on multi-GPU boards will set \a multiGpuBool to a non-zero value. + * + * For Fermi &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param multiGpuBool Reference in which to return a zero or non-zero value + * to indicate whether the device is on a multi GPU board + * + * @return + * - \ref NVML_SUCCESS if \a multiGpuBool has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a multiGpuBool is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMultiGpuBoard(nvmlDevice_t device, unsigned int *multiGpuBool); + +/** + * Retrieves the total ECC error counts for the device. + * + * For Fermi &tm; or newer fully supported devices. + * Only applicable to devices with ECC. + * Requires \a NVML_INFOROM_ECC version 1.0 or higher. + * Requires ECC Mode to be enabled. + * + * The total error count is the sum of errors across each of the separate memory systems, i.e. the total set of + * errors across the entire device. + * + * See \ref nvmlMemoryErrorType_t for a description of available error types.\n + * See \ref nvmlEccCounterType_t for a description of available counter types. + * + * @param device The identifier of the target device + * @param errorType Flag that specifies the type of the errors. + * @param counterType Flag that specifies the counter-type of the errors. + * @param eccCounts Reference in which to return the specified ECC errors + * + * @return + * - \ref NVML_SUCCESS if \a eccCounts has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceClearEccErrorCounts() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetTotalEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, unsigned long long *eccCounts); + +/** + * Retrieves the detailed ECC error counts for the device. + * + * @deprecated This API supports only a fixed set of ECC error locations + * On different GPU architectures different locations are supported + * See \ref nvmlDeviceGetMemoryErrorCounter + * + * For Fermi &tm; or newer fully supported devices. + * Only applicable to devices with ECC. + * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based ECC counts. + * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other ECC counts. + * Requires ECC Mode to be enabled. + * + * Detailed errors provide separate ECC counts for specific parts of the memory system. + * + * Reports zero for unsupported ECC error counters when a subset of ECC error counters are supported. + * + * See \ref nvmlMemoryErrorType_t for a description of available bit types.\n + * See \ref nvmlEccCounterType_t for a description of available counter types.\n + * See \ref nvmlEccErrorCounts_t for a description of provided detailed ECC counts. + * + * @param device The identifier of the target device + * @param errorType Flag that specifies the type of the errors. + * @param counterType Flag that specifies the counter-type of the errors. + * @param eccCounts Reference in which to return the specified ECC errors + * + * @return + * - \ref NVML_SUCCESS if \a eccCounts has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceClearEccErrorCounts() + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetDetailedEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, nvmlEccErrorCounts_t *eccCounts); + +/** + * Retrieves the requested memory error counter for the device. + * + * For Fermi &tm; or newer fully supported devices. + * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based memory error counts. + * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other memory error counts. + * + * Only applicable to devices with ECC. + * + * Requires ECC Mode to be enabled. + * + * @note On MIG-enabled GPUs, per instance information can be queried using specific + * MIG device handles. Per instance information is currently only supported for + * non-DRAM uncorrectable volatile errors. Querying volatile errors using device + * handles is currently not supported. + * + * See \ref nvmlMemoryErrorType_t for a description of available memory error types.\n + * See \ref nvmlEccCounterType_t for a description of available counter types.\n + * See \ref nvmlMemoryLocation_t for a description of available counter locations.\n + * + * @param device The identifier of the target device + * @param errorType Flag that specifies the type of error. + * @param counterType Flag that specifies the counter-type of the errors. + * @param locationType Specifies the location of the counter. + * @param count Reference in which to return the ECC counter + * + * @return + * - \ref NVML_SUCCESS if \a count has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a bitTyp,e \a counterType or \a locationType is + * invalid, or \a count is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support ECC error reporting in the specified memory + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMemoryErrorCounter(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, + nvmlEccCounterType_t counterType, + nvmlMemoryLocation_t locationType, unsigned long long *count); + +/** + * Retrieves the current utilization rates for the device's major subsystems. + * + * For Fermi &tm; or newer fully supported devices. + * + * See \ref nvmlUtilization_t for details on available utilization rates. + * + * \note During driver initialization when ECC is enabled one can see high GPU and Memory Utilization readings. + * This is caused by ECC Memory Scrubbing mechanism that is performed during driver initialization. + * + * @note On MIG-enabled GPUs, querying device utilization rates is not currently supported. + * + * @param device The identifier of the target device + * @param utilization Reference in which to return the utilization information + * + * @return + * - \ref NVML_SUCCESS if \a utilization has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a utilization is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t *utilization); + +/** + * Retrieves the current utilization and sampling size in microseconds for the Encoder + * + * For Kepler &tm; or newer fully supported devices. + * + * @note On MIG-enabled GPUs, querying encoder utilization is not currently supported. + * + * @param device The identifier of the target device + * @param utilization Reference to an unsigned int for encoder utilization info + * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US + * + * @return + * - \ref NVML_SUCCESS if \a utilization has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetEncoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); + +/** + * Retrieves the current capacity of the device's encoder, as a percentage of maximum encoder capacity with valid values in the range 0-100. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param encoderQueryType Type of encoder to query + * @param encoderCapacity Reference to an unsigned int for the encoder capacity + * + * @return + * - \ref NVML_SUCCESS if \a encoderCapacity is fetched + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a encoderCapacity is NULL, or \a device or \a encoderQueryType + * are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if device does not support the encoder specified in \a encodeQueryType + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetEncoderCapacity (nvmlDevice_t device, nvmlEncoderType_t encoderQueryType, unsigned int *encoderCapacity); + +/** + * Retrieves the current encoder statistics for a given device. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param sessionCount Reference to an unsigned int for count of active encoder sessions + * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions + * @param averageLatency Reference to an unsigned int for encode latency in microseconds + * + * @return + * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount, or \a device or \a averageFps, + * or \a averageLatency is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetEncoderStats (nvmlDevice_t device, unsigned int *sessionCount, + unsigned int *averageFps, unsigned int *averageLatency); + +/** + * Retrieves information about active encoder sessions on a target device. + * + * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfos. The + * array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions + * written to the buffer. + * + * If the supplied buffer is not large enough to accommodate the active session array, the function returns + * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. + * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return + * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param sessionCount Reference to caller supplied array size, and returns the number of sessions. + * @param sessionInfos Reference in which to return the session information + * + * @return + * - \ref NVML_SUCCESS if \a sessionInfos is fetched + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL. + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetEncoderSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfos); + +/** + * Retrieves the current utilization and sampling size in microseconds for the Decoder + * + * For Kepler &tm; or newer fully supported devices. + * + * @note On MIG-enabled GPUs, querying decoder utilization is not currently supported. + * + * @param device The identifier of the target device + * @param utilization Reference to an unsigned int for decoder utilization info + * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US + * + * @return + * - \ref NVML_SUCCESS if \a utilization has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDecoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); + +/** + * Retrieves the current utilization and sampling size in microseconds for the JPG + * + * For Turing &tm; or newer fully supported devices. + * + * @note On MIG-enabled GPUs, querying decoder utilization is not currently supported. + * + * @param device The identifier of the target device + * @param utilization Reference to an unsigned int for jpg utilization info + * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US + * + * @return + * - \ref NVML_SUCCESS if \a utilization has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetJpgUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); + +/** + * Retrieves the current utilization and sampling size in microseconds for the OFA (Optical Flow Accelerator) + * + * For Turing &tm; or newer fully supported devices. + * + * @note On MIG-enabled GPUs, querying decoder utilization is not currently supported. + * + * @param device The identifier of the target device + * @param utilization Reference to an unsigned int for ofa utilization info + * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US + * + * @return + * - \ref NVML_SUCCESS if \a utilization has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetOfaUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); + +/** +* Retrieves the active frame buffer capture sessions statistics for a given device. +* +* For Maxwell &tm; or newer fully supported devices. +* +* @param device The identifier of the target device +* @param fbcStats Reference to nvmlFBCStats_t structure containing NvFBC stats +* +* @return +* - \ref NVML_SUCCESS if \a fbcStats is fetched +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a fbcStats is NULL +* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlDeviceGetFBCStats(nvmlDevice_t device, nvmlFBCStats_t *fbcStats); + +/** +* Retrieves information about active frame buffer capture sessions on a target device. +* +* An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The +* array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions +* written to the buffer. +* +* If the supplied buffer is not large enough to accommodate the active session array, the function returns +* NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \a sessionCount. +* To query the number of active FBC sessions, call this function with *sessionCount = 0. The code will return +* NVML_SUCCESS with number of active FBC sessions updated in *sessionCount. +* +* For Maxwell &tm; or newer fully supported devices. +* +* @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \a sessionInfo may +* be zero if there are no new frames captured since the session started. +* +* @param device The identifier of the target device +* @param sessionCount Reference to caller supplied array size, and returns the number of sessions. +* @param sessionInfo Reference in which to return the session information +* +* @return +* - \ref NVML_SUCCESS if \a sessionInfo is fetched +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL. +* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlDeviceGetFBCSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo); + +/** + * Retrieves the current and pending driver model for the device. + * + * For Kepler &tm; or newer fully supported devices. + * For windows only. + * + * On Windows platforms the device driver can run in either WDDM, MCDM or WDM (TCC) modes. If a display is attached + * to the device it must run in WDDM mode. MCDM mode is preferred if a display is not attached. TCC mode is deprecated. + * + * See \ref nvmlDriverModel_t for details on available driver models. + * + * @param device The identifier of the target device + * @param current Reference in which to return the current driver model + * @param pending Reference in which to return the pending driver model + * + * @return + * - \ref NVML_SUCCESS if either \a current and/or \a pending have been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or both \a current and \a pending are NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetDriverModel_v2() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDriverModel_v2(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending); + +/** + * Get VBIOS version of the device. + * + * For all products. + * + * The VBIOS version may change from time to time. It will not exceed 32 characters in length + * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE. + * + * @param device The identifier of the target device + * @param version Reference to which to return the VBIOS version + * @param length The maximum allowed length of the string returned in \a version + * + * @return + * - \ref NVML_SUCCESS if \a version has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a version is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVbiosVersion(nvmlDevice_t device, char *version, unsigned int length); + +/** + * Get Bridge Chip Information for all the bridge chips on the board. + * + * For all fully supported products. + * Only applicable to multi-GPU products. + * + * @param device The identifier of the target device + * @param bridgeHierarchy Reference to the returned bridge chip Hierarchy + * + * @return + * - \ref NVML_SUCCESS if bridge chip exists + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a bridgeInfo is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if bridge chip not supported on the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetBridgeChipInfo(nvmlDevice_t device, nvmlBridgeChipHierarchy_t *bridgeHierarchy); + +/** + * Get information about processes with a compute context on a device + * + * For Fermi &tm; or newer fully supported devices. + * + * This function returns information only about compute running processes (e.g. CUDA application which have + * active context). Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by this function. + * + * To query the current number of running compute processes, call this function with *infoCount = 0. The + * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call + * \a infos is allowed to be NULL. + * + * The usedGpuMemory field returned is all of the memory used by the application. + * + * Keep in mind that information returned by this call is dynamic and the number of elements might change in + * time. Allocate more space for \a infos table in case new compute processes are spawned. + * + * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if + * the caller has appropriate privileges. Per-instance information can be queried by using + * specific MIG device handles. + * Querying per-instance information using MIG device handles is not supported if the device is in vGPU Host virtualization mode. + * + * @param device The device handle or MIG device handle + * @param infoCount Reference in which to provide the \a infos array size, and + * to return the number of returned elements + * @param infos Reference in which to return the process information + * + * @return + * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small + * \a infoCount will contain minimal amount of space necessary for + * the call to complete + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see \ref nvmlSystemGetProcessName + */ +nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses_v3(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); + +/** + * Get information about processes with a graphics context on a device + * + * For Kepler &tm; or newer fully supported devices. + * + * This function returns information only about graphics based processes + * (eg. applications using OpenGL, DirectX) + * + * To query the current number of running graphics processes, call this function with *infoCount = 0. The + * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call + * \a infos is allowed to be NULL. + * + * The usedGpuMemory field returned is all of the memory used by the application. + * + * Keep in mind that information returned by this call is dynamic and the number of elements might change in + * time. Allocate more space for \a infos table in case new graphics processes are spawned. + * + * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if + * the caller has appropriate privileges. Per-instance information can be queried by using + * specific MIG device handles. + * Querying per-instance information using MIG device handles is not supported if the device is in vGPU Host virtualization mode. + * + * @param device The device handle or MIG device handle + * @param infoCount Reference in which to provide the \a infos array size, and + * to return the number of returned elements + * @param infos Reference in which to return the process information + * + * @return + * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small + * \a infoCount will contain minimal amount of space necessary for + * the call to complete + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see \ref nvmlSystemGetProcessName + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses_v3(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); + +/** + * Get information about processes with a Multi-Process Service (MPS) compute context on a device + * + * For Volta &tm; or newer fully supported devices. + * + * This function returns information only about compute running processes (e.g. CUDA application which have + * active context) utilizing MPS. Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by + * this function. + * + * To query the current number of running compute processes, call this function with *infoCount = 0. The + * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call + * \a infos is allowed to be NULL. + * + * The usedGpuMemory field returned is all of the memory used by the application. + * + * Keep in mind that information returned by this call is dynamic and the number of elements might change in + * time. Allocate more space for \a infos table in case new compute processes are spawned. + * + * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if + * the caller has appropriate privileges. Per-instance information can be queried by using + * specific MIG device handles. + * Querying per-instance information using MIG device handles is not supported if the device is in vGPU Host virtualization mode. + * + * @param device The device handle or MIG device handle + * @param infoCount Reference in which to provide the \a infos array size, and + * to return the number of returned elements + * @param infos Reference in which to return the process information + * + * @return + * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small + * \a infoCount will contain minimal amount of space necessary for + * the call to complete + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see \ref nvmlSystemGetProcessName + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMPSComputeRunningProcesses_v3(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); + +/** + * Get information about running processes on a device for input context + * + * For Hopper &tm; or newer fully supported devices. + * + * This function returns information only about running processes (e.g. CUDA application which have + * active context). + * + * To determine the size of the \a plist->procArray array to allocate, call the function with + * \a plist->numProcArrayEntries set to zero and \a plist->procArray set to NULL. The return + * code will be either NVML_ERROR_INSUFFICIENT_SIZE (if there are valid processes of type + * \a plist->mode to report on, in which case the \a plist->numProcArrayEntries field will + * indicate the required number of entries in the array) or NVML_SUCCESS (if no processes of type + * \a plist->mode exist). + * + * The usedGpuMemory field returned is all of the memory used by the application. + * The usedGpuCcProtectedMemory field returned is all of the protected memory used by the application. + * + * Keep in mind that information returned by this call is dynamic and the number of elements might change in + * time. Allocate more space for \a plist->procArray table in case new processes are spawned. + * + * @note In MIG mode, if device handle is provided, the API returns aggregate information, only if + * the caller has appropriate privileges. Per-instance information can be queried by using + * specific MIG device handles. + * Querying per-instance information using MIG device handles is not supported if the device is in + * vGPU Host virtualization mode. + * Protected memory usage is currently not available in MIG mode and in windows. + * + * @param device The device handle or MIG device handle + * @param plist Reference in which to process detail list + * \a plist->version The api version + * \a plist->mode The process mode + * \a plist->procArray Reference in which to return the process information + * \a plist->numProcArrayEntries Proc array size of returned entries + * + * @return + * - \ref NVML_SUCCESS if \a plist->numprocArrayEntries and \a plist->procArray have been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a plist->numprocArrayEntries indicates that the \a plist->procArray is too small + * \a plist->numprocArrayEntries will contain minimal amount of space necessary for + * the call to complete + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a plist is NULL, \a plist->version is invalid, + * \a plist->mode is invalid, + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by \a device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetRunningProcessDetailList(nvmlDevice_t device, nvmlProcessDetailList_t *plist); + +/** + * Check if the GPU devices are on the same physical board. + * + * For all fully supported products. + * + * @param device1 The first GPU device + * @param device2 The second GPU device + * @param onSameBoard Reference in which to return the status. + * Non-zero indicates that the GPUs are on the same board. + * + * @return + * - \ref NVML_SUCCESS if \a onSameBoard has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a dev1 or \a dev2 are invalid or \a onSameBoard is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this check is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the either GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceOnSameBoard(nvmlDevice_t device1, nvmlDevice_t device2, int *onSameBoard); + +/** + * Retrieves the root/admin permissions on the target API. See \a nvmlRestrictedAPI_t for the list of supported APIs. + * If an API is restricted only root users can call that API. See \a nvmlDeviceSetAPIRestriction to change current permissions. + * + * For all fully supported products. + * + * @param device The identifier of the target device + * @param apiType Target API type for this operation + * @param isRestricted Reference in which to return the current restriction + * NVML_FEATURE_ENABLED indicates that the API is root-only + * NVML_FEATURE_DISABLED indicates that the API is accessible to all users + * + * @return + * - \ref NVML_SUCCESS if \a isRestricted has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a apiType incorrect or \a isRestricted is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device or the device does not support + * the feature that is being queried (E.G. Enabling/disabling Auto Boosted clocks is + * not supported by the device) + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlRestrictedAPI_t + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t *isRestricted); + +/** + * Gets recent samples for the GPU. + * + * For Kepler &tm; or newer fully supported devices. + * + * Based on type, this method can be used to fetch the power, utilization or clock samples maintained in the buffer by + * the driver. + * + * Power, Utilization and Clock samples are returned as type "unsigned int" for the union nvmlValue_t. + * + * To get the size of samples that user needs to allocate, the method is invoked with samples set to NULL. + * The returned samplesCount will provide the number of samples that can be queried. The user needs to + * allocate the buffer with size as samplesCount * sizeof(nvmlSample_t). + * + * lastSeenTimeStamp represents CPU timestamp in microseconds. Set it to 0 to fetch all the samples maintained by the + * underlying buffer. Set lastSeenTimeStamp to one of the timeStamps retrieved from the date of the previous query + * to get more recent samples. + * + * This method fetches the number of entries which can be accommodated in the provided samples array, and the + * reference samplesCount is updated to indicate how many samples were actually retrieved. The advantage of using this + * method for samples in contrast to polling via existing methods is to get get higher frequency data at lower polling cost. + * + * @note On MIG-enabled GPUs, querying the following sample types, NVML_GPU_UTILIZATION_SAMPLES, NVML_MEMORY_UTILIZATION_SAMPLES + * NVML_ENC_UTILIZATION_SAMPLES and NVML_DEC_UTILIZATION_SAMPLES, is not currently supported. + * + * @param device The identifier for the target device + * @param type Type of sampling event + * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. + * @param sampleValType Output parameter to represent the type of sample value as described in nvmlSampleVal_t + * @param sampleCount Reference to provide the number of elements which can be queried in samples array + * @param samples Reference in which samples are returned + + * @return + * - \ref NVML_SUCCESS if samples are successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a samplesCount is NULL or + * reference to \a sampleCount is 0 for non null \a samples + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSamples(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp, + nvmlValueType_t *sampleValType, unsigned int *sampleCount, nvmlSample_t *samples); + +/** + * Gets Total, Available and Used size of BAR1 memory. + * + * BAR1 is used to map the FB (device memory) so that it can be directly accessed by the CPU or by 3rd party + * devices (peer-to-peer on the PCIE bus). + * + * @note In MIG mode, if device handle is provided, the API returns aggregate + * information, only if the caller has appropriate privileges. Per-instance + * information can be queried by using specific MIG device handles. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param bar1Memory Reference in which BAR1 memory + * information is returned. + * + * @return + * - \ref NVML_SUCCESS if BAR1 memory is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a bar1Memory is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetBAR1MemoryInfo(nvmlDevice_t device, nvmlBAR1Memory_t *bar1Memory); + +/** + * @deprecated Use \ref nvmlDeviceGetFieldValues to query this data. + * This API will be removed in CUDA 14.0. + * + * Translations are as follows: + + * + * NVML_PERF_POLICY_POWER -> NVML_FI_DEV_CLOCKS_EVENT_REASON_SW_POWER_CAP + * NVML_PERF_POLICY_THERMAL -> NVML_FI_DEV_CLOCKS_EVENT_REASON_SW_THERM_SLOWDOWN + * NVML_PERF_POLICY_SYNC_BOOST -> NVML_FI_DEV_CLOCKS_EVENT_REASON_SYNC_BOOST + * NVML_PERF_POLICY_BOARD_LIMIT -> NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT + * NVML_PERF_POLICY_LOW_UTILIZATION -> NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION + * NVML_PERF_POLICY_RELIABILITY -> NVML_FI_DEV_PERF_POLICY_RELIABILITY + * NVML_PERF_POLICY_TOTAL_APP_CLOCKS -> DEPRECATED, Do not use + * NVML_PERF_POLICY_TOTAL_BASE_CLOCKS -> NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetViolationStatus(nvmlDevice_t device, nvmlPerfPolicyType_t perfPolicyType, nvmlViolationTime_t *violTime); + +/** + * Gets the device's interrupt number + * + * @param device The identifier of the target device + * @param irqNum The interrupt number associated with the specified device + * + * @return + * - \ref NVML_SUCCESS if irq number is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a irqNum is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetIrqNum(nvmlDevice_t device, unsigned int *irqNum); + +/** + * Gets the device's core count + * + * @note On MIG-enabled GPUs, querying the device's core count is currently not supported using this API. + * Please use \ref nvmlDeviceGetGpuInstanceProfileInfo to fetch the MIG device's core count. + * + * @param device The identifier of the target device + * @param numCores The number of cores for the specified device + * + * @return + * - \ref NVML_SUCCESS if GPU core count is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a numCores is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device or a mig device. + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNumGpuCores(nvmlDevice_t device, unsigned int *numCores); + +/** + * Gets the devices power source + * + * @param device The identifier of the target device + * @param powerSource The power source of the device + * + * @return + * - \ref NVML_SUCCESS if the current power source was successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a powerSource is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPowerSource(nvmlDevice_t device, nvmlPowerSource_t *powerSource); + +/** + * Gets the device's memory bus width + * + * @param device The identifier of the target device + * @param busWidth The devices's memory bus width + * + * @return + * - \ref NVML_SUCCESS if the memory bus width is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a busWidth is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMemoryBusWidth(nvmlDevice_t device, unsigned int *busWidth); + +/** + * Gets the device's PCIE Max Link speed in MBPS + * + * @param device The identifier of the target device + * @param maxSpeed The devices's PCIE Max Link speed in MBPS + * + * @return + * - \ref NVML_SUCCESS if PCIe Max Link Speed is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a maxSpeed is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPcieLinkMaxSpeed(nvmlDevice_t device, unsigned int *maxSpeed); + +/** + * Gets the device's PCIe Link speed in Mbps + * + * @param device The identifier of the target device + * @param pcieSpeed The devices's PCIe Max Link speed in Mbps + * + * @return + * - \ref NVML_SUCCESS if \a pcieSpeed has been retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pcieSpeed is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support PCIe speed getting + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPcieSpeed(nvmlDevice_t device, unsigned int *pcieSpeed); + +/** + * Gets the device's Adaptive Clock status + * + * @param device The identifier of the target device + * @param adaptiveClockStatus The current adaptive clocking status, either + * NVML_ADAPTIVE_CLOCKING_INFO_STATUS_DISABLED + * or NVML_ADAPTIVE_CLOCKING_INFO_STATUS_ENABLED + * + * @return + * - \ref NVML_SUCCESS if the current adaptive clocking status is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a adaptiveClockStatus is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAdaptiveClockInfoStatus(nvmlDevice_t device, unsigned int *adaptiveClockStatus); + +/** + * Get the type of the GPU Bus (PCIe, PCI, ...) + * + * @param device The identifier of the target device + * @param type The PCI Bus type + * + * return + * - \ref NVML_SUCCESS if the bus \a type is successfully retreived + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a type is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetBusType(nvmlDevice_t device, nvmlBusType_t *type); + + + /** + * @deprecated Will be deprecated in a future release. Use \ref nvmlDeviceGetGpuFabricInfoV instead + * + * Get fabric information associated with the device. + * + * For Hopper &tm; or newer fully supported devices. + * + * On Hopper + NVSwitch systems, GPU is registered with the NVIDIA Fabric Manager + * Upon successful registration, the GPU is added to the NVLink fabric to enable + * peer-to-peer communication. + * This API reports the current state of the GPU in the NVLink fabric + * along with other useful information. + * + * + * @param device The identifier of the target device + * @param gpuFabricInfo Information about GPU fabric state + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support gpu fabric + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetGpuFabricInfo(nvmlDevice_t device, nvmlGpuFabricInfo_t *gpuFabricInfo); + +/** +* Versioned wrapper around \ref nvmlDeviceGetGpuFabricInfo that accepts a versioned +* \ref nvmlGpuFabricInfo_v2_t or later output structure. +* +* @note The caller must set the \ref nvmlGpuFabricInfoV_t.version field to the +* appropriate version prior to calling this function. For example: +* \code +* nvmlGpuFabricInfoV_t fabricInfo = +* { .version = nvmlGpuFabricInfo_v2 }; +* nvmlReturn_t result = nvmlDeviceGetGpuFabricInfoV(device,&fabricInfo); +* \endcode +* +* For Hopper &tm; or newer fully supported devices. +* +* @param device The identifier of the target device +* @param gpuFabricInfo Information about GPU fabric state +* +* @return +* - \ref NVML_SUCCESS Upon success +* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support gpu fabric +*/ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuFabricInfoV(nvmlDevice_t device, + nvmlGpuFabricInfoV_t *gpuFabricInfo); + +/** + * Get Conf Computing System capabilities. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param capabilities System CC capabilities + * + * @return + * - \ref NVML_SUCCESS if \a capabilities were successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a capabilities is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlSystemGetConfComputeCapabilities(nvmlConfComputeSystemCaps_t *capabilities); + +/** + * Get Conf Computing System State. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param state System CC State + * + * @return + * - \ref NVML_SUCCESS if \a state were successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a state is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlSystemGetConfComputeState(nvmlConfComputeSystemState_t *state); + +/** + * Get Conf Computing Protected and Unprotected Memory Sizes. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param device Device handle + * @param memInfo Protected/Unprotected Memory sizes + * + * @return + * - \ref NVML_SUCCESS if \a memInfo were successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a memInfo or \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeMemSizeInfo(nvmlDevice_t device, nvmlConfComputeMemSizeInfo_t *memInfo); + +/** + * Get Conf Computing GPUs ready state. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param isAcceptingWork Returns GPU current work accepting state, + * NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE or + * NVML_CC_ACCEPTING_CLIENT_REQUESTS_FALSE + * + * return + * - \ref NVML_SUCCESS if \a current GPUs ready state were successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a isAcceptingWork is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlSystemGetConfComputeGpusReadyState(unsigned int *isAcceptingWork); + +/** + * Get Conf Computing protected memory usage. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param device The identifier of the target device + * @param memory Reference in which to return the memory information + * + * @return + * - \ref NVML_SUCCESS if \a memory has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeProtectedMemoryUsage(nvmlDevice_t device, nvmlMemory_t *memory); + +/** + * Get Conf Computing GPU certificate details. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param device The identifier of the target device + * @param gpuCert Reference in which to return the gpu certificate information + * + * @return + * - \ref NVML_SUCCESS if \a gpu certificate info has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeGpuCertificate(nvmlDevice_t device, + nvmlConfComputeGpuCertificate_t *gpuCert); + +/** + * Get Conf Computing GPU attestation report. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param device The identifier of the target device + * @param gpuAtstReport Reference in which to return the gpu attestation report + * + * @return + * - \ref NVML_SUCCESS if \a gpu attestation report has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeGpuAttestationReport(nvmlDevice_t device, + nvmlConfComputeGpuAttestationReport_t *gpuAtstReport); +/** + * Get Conf Computing key rotation threshold detail. + * + * For Hopper &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param pKeyRotationThrInfo Reference in which to return the key rotation threshold data + * + * @return + * - \ref NVML_SUCCESS if \a gpu key rotation threshold info has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlSystemGetConfComputeKeyRotationThresholdInfo( + nvmlConfComputeGetKeyRotationThresholdInfo_t *pKeyRotationThrInfo); + +/** + * Set Conf Computing Unprotected Memory Size. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param device Device Handle + * @param sizeKiB Unprotected Memory size to be set in KiB + * + * @return + * - \ref NVML_SUCCESS if \a sizeKiB successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlDeviceSetConfComputeUnprotectedMemSize(nvmlDevice_t device, unsigned long long sizeKiB); + +/** + * Set Conf Computing GPUs ready state. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param isAcceptingWork GPU accepting new work, NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE or + * NVML_CC_ACCEPTING_CLIENT_REQUESTS_FALSE + * + * return + * - \ref NVML_SUCCESS if \a current GPUs ready state is successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a isAcceptingWork is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlSystemSetConfComputeGpusReadyState(unsigned int isAcceptingWork); + +/** + * Set Conf Computing key rotation threshold. + * + * For Hopper &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * This function is to set the confidential compute key rotation threshold parameters. + * \a pKeyRotationThrInfo->maxAttackerAdvantage should be in the range from + * NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MIN to NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MAX. + * Default value is 60. + * + * @param pKeyRotationThrInfo Reference to the key rotation threshold data + * + * @return + * - \ref NVML_SUCCESS if \a key rotation threashold max attacker advantage has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL + * - \ref NVML_ERROR_INVALID_STATE if confidential compute GPU ready state is enabled + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlSystemSetConfComputeKeyRotationThresholdInfo( + nvmlConfComputeSetKeyRotationThresholdInfo_t *pKeyRotationThrInfo); + +/** + * Get Conf Computing System Settings. + * + * For Hopper &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param settings System CC settings + * + * @return + * - \ref NVML_SUCCESS If the query is success + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid or \a counters is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST If the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the provided version is invalid/unsupported + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlSystemGetConfComputeSettings(nvmlSystemConfComputeSettings_t *settings); + +/** + * Retrieve GSP firmware version. + * + * The caller passes in buffer via \a version and corresponding GSP firmware numbered version + * is returned with the same parameter in string format. + * + * @param device Device handle + * @param version The retrieved GSP firmware version + * + * @return + * - \ref NVML_SUCCESS if GSP firmware version is sucessfully retrieved + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or GSP \a version pointer is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if GSP firmware is not enabled for GPU + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGspFirmwareVersion(nvmlDevice_t device, char *version); + +/** + * Retrieve GSP firmware mode. + * + * The caller passes in integer pointers. GSP firmware enablement and default mode information is returned with + * corresponding parameters. The return value in \a isEnabled and \a defaultMode should be treated as boolean. + * + * @param device Device handle + * @param isEnabled Pointer to specify if GSP firmware is enabled + * @param defaultMode Pointer to specify if GSP firmware is supported by default on \a device + * + * @return + * - \ref NVML_SUCCESS if GSP firmware mode is sucessfully retrieved + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or any of \a isEnabled or \a defaultMode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if GSP firmware is not enabled for GPU + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGspFirmwareMode(nvmlDevice_t device, unsigned int *isEnabled, unsigned int *defaultMode); + +/** + * Get SRAM ECC error status of this device. + * + * For Ampere &tm; or newer fully supported devices. + * Requires root/admin permissions. + * + * See \ref nvmlEccSramErrorStatus_v1_t for more information on the struct. + * + * @param device The identifier of the target device + * @param status Returns SRAM ECC error status + * + * @return + * - \ref NVML_SUCCESS If \a limit has been set + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid or \a counters is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST If the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a nvmlEccSramErrorStatus_t is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSramEccErrorStatus(nvmlDevice_t device, + nvmlEccSramErrorStatus_t *status); + +/** + * Set new power limit of this device. + * + * For Kepler &tm; or newer fully supported devices. + * Requires root/admin permissions. + * + * See \ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values. + * + * See \ref nvmlPowerValue_v2_t for more information on the struct. + * + * \note Limit is not persistent across reboots or driver unloads. + * Enable persistent mode to prevent driver from unloading when no application is using the device. + * + * This API replaces nvmlDeviceSetPowerManagementLimit. It can be used as a drop-in replacement for the older version. + * + * @param device The identifier of the target device + * @param powerValue Power management limit in milliwatts to set + * + * @return + * - \ref NVML_SUCCESS if \a limit has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a powerValue is NULL or contains invalid values + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see NVML_FI_DEV_POWER_AVERAGE + * @see NVML_FI_DEV_POWER_INSTANT + * @see NVML_FI_DEV_POWER_MIN_LIMIT + * @see NVML_FI_DEV_POWER_MAX_LIMIT + * @see NVML_FI_DEV_POWER_CURRENT_LIMIT + */ +nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit_v2(nvmlDevice_t device, nvmlPowerValue_v2_t *powerValue); + +/** + * @} // @defgroup nvmlDeviceQueries Device Queries + */ + +/** @addtogroup nvmlAccountingStats + * @{ + */ + +/** + * Queries the state of per process accounting mode. + * + * For Kepler &tm; or newer fully supported devices. + * + * See \ref nvmlDeviceGetAccountingStats for more details. + * See \ref nvmlDeviceSetAccountingMode + * + * @param device The identifier of the target device + * @param mode Reference in which to return the current accounting mode + * + * @return + * - \ref NVML_SUCCESS if the mode has been successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode are NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAccountingMode(nvmlDevice_t device, nvmlEnableState_t *mode); + +/** + * Queries process's accounting stats. + * + * For Kepler &tm; or newer fully supported devices. + * + * Accounting stats capture GPU utilization and other statistics across the lifetime of a process. + * Accounting stats can be queried during life time of the process and after its termination. + * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and + * updated to actual running time after its termination. + * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old + * processes. + * + * See \ref nvmlAccountingStats_t for description of each returned metric. + * List of processes that can be queried can be retrieved from \ref nvmlDeviceGetAccountingPids. + * + * @note Accounting Mode needs to be on. See \ref nvmlDeviceGetAccountingMode. + * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be + * queried since they don't contribute to GPU utilization. + * @note In case of pid collision stats of only the latest process (that terminated last) will be reported + * + * @warning On Kepler devices per process statistics are accurate only if there's one process running on a GPU. + * + * @param device The identifier of the target device + * @param pid Process Id of the target process to query stats for + * @param stats Reference in which to return the process's accounting stats + * + * @return + * - \ref NVML_SUCCESS if stats have been successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a stats are NULL + * - \ref NVML_ERROR_NOT_FOUND if process stats were not found + * - \ref NVML_ERROR_NOT_SUPPORTED if \a device doesn't support this feature or accounting mode is disabled + * or on vGPU host. + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetAccountingBufferSize + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAccountingStats(nvmlDevice_t device, unsigned int pid, nvmlAccountingStats_t *stats); + +/** + * Queries list of processes that can be queried for accounting stats. The list of processes returned + * can be in running or terminated state. + * + * For Kepler &tm; or newer fully supported devices. + * + * To query the number of processes under Accounting Mode, call this function with *count = 0 and pids=NULL. + * The return code will be NVML_ERROR_INSUFFICIENT_SIZE with an updated count value indicating the number of processes. + * + * For more details see \ref nvmlDeviceGetAccountingStats. + * + * @note In case of PID collision some processes might not be accessible before the circular buffer is full. + * + * @param device The identifier of the target device + * @param count Reference in which to provide the \a pids array size, and + * to return the number of elements ready to be queried + * @param pids Reference in which to return list of process ids + * + * @return + * - \ref NVML_SUCCESS if pids were successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if \a device doesn't support this feature or accounting mode is disabled + * or on vGPU host. + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to + * expected value) + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetAccountingBufferSize + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAccountingPids(nvmlDevice_t device, unsigned int *count, unsigned int *pids); + +/** + * Returns the number of processes that the circular buffer with accounting pids can hold. + * + * For Kepler &tm; or newer fully supported devices. + * + * This is the maximum number of processes that accounting information will be stored for before information + * about oldest processes will get overwritten by information about new processes. + * + * @param device The identifier of the target device + * @param bufferSize Reference in which to provide the size (in number of elements) + * of the circular buffer for accounting stats. + * + * @return + * - \ref NVML_SUCCESS if buffer size was successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a bufferSize is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetAccountingStats + * @see nvmlDeviceGetAccountingPids + */ +nvmlReturn_t DECLDIR nvmlDeviceGetAccountingBufferSize(nvmlDevice_t device, unsigned int *bufferSize); + +/** @} */ + +/** @addtogroup nvmlDeviceQueries + * @{ + */ + +/** + * Returns the list of retired pages by source, including pages that are pending retirement + * The address information provided from this API is the hardware address of the page that was retired. Note + * that this does not match the virtual address used in CUDA, but will match the address information in Xid 63 + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param cause Filter page addresses by cause of retirement + * @param pageCount Reference in which to provide the \a addresses buffer size, and + * to return the number of retired pages that match \a cause + * Set to 0 to query the size without allocating an \a addresses buffer + * @param addresses Buffer to write the page addresses into + * + * @return + * - \ref NVML_SUCCESS if \a pageCount was populated and \a addresses was filled + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the + * matching page addresses. \a pageCount is set to the needed size. + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or + * \a addresses is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages(nvmlDevice_t device, nvmlPageRetirementCause_t cause, + unsigned int *pageCount, unsigned long long *addresses); + +/** + * Returns the list of retired pages by source, including pages that are pending retirement + * The address information provided from this API is the hardware address of the page that was retired. Note + * that this does not match the virtual address used in CUDA, but will match the address information in Xid 63 + * + * \note nvmlDeviceGetRetiredPages_v2 adds an additional timestamps parameter to return the time of each page's + * retirement. This is supported for Pascal and newer architecture. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param cause Filter page addresses by cause of retirement + * @param pageCount Reference in which to provide the \a addresses buffer size, and + * to return the number of retired pages that match \a cause + * Set to 0 to query the size without allocating an \a addresses buffer + * @param addresses Buffer to write the page addresses into + * @param timestamps Buffer to write the timestamps of page retirement, additional for _v2 + * + * @return + * - \ref NVML_SUCCESS if \a pageCount was populated and \a addresses was filled + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the + * matching page addresses. \a pageCount is set to the needed size. + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or + * \a addresses is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages_v2(nvmlDevice_t device, nvmlPageRetirementCause_t cause, + unsigned int *pageCount, unsigned long long *addresses, unsigned long long *timestamps); + +/** + * Check if any pages are pending retirement and need a reboot to fully retire. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param isPending Reference in which to return the pending status + * + * @return + * - \ref NVML_SUCCESS if \a isPending was populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isPending is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPagesPendingStatus(nvmlDevice_t device, nvmlEnableState_t *isPending); + +/** + * Get number of remapped rows. The number of rows reported will be based on + * the cause of the remapping. isPending indicates whether or not there are + * pending remappings. A reset will be required to actually remap the row. + * failureOccurred will be set if a row remapping ever failed in the past. A + * pending remapping won't affect future work on the GPU since + * error-containment and dynamic page blacklisting will take care of that. + * + * @note On MIG-enabled GPUs with active instances, querying the number of + * remapped rows is not supported + * + * For Ampere &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param corrRows Reference for number of rows remapped due to correctable errors + * @param uncRows Reference for number of rows remapped due to uncorrectable errors + * @param isPending Reference for whether or not remappings are pending + * @param failureOccurred Reference that is set when a remapping has failed in the past + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a corrRows, \a uncRows, \a isPending or \a failureOccurred is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN Unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetRemappedRows(nvmlDevice_t device, unsigned int *corrRows, unsigned int *uncRows, + unsigned int *isPending, unsigned int *failureOccurred); + +/** + * Get the row remapper histogram. Returns the remap availability for each bank + * on the GPU. + * + * @param device Device handle + * @param values Histogram values + * + * @return + * - \ref NVML_SUCCESS On success + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetRowRemapperHistogram(nvmlDevice_t device, nvmlRowRemapperHistogramValues_t *values); + +/** + * Get architecture for device + * + * @param device The identifier of the target device + * @param arch Reference where architecture is returned, if call successful. + * Set to NVML_DEVICE_ARCH_* upon success + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a arch (output refererence) are invalid + */ +nvmlReturn_t DECLDIR nvmlDeviceGetArchitecture(nvmlDevice_t device, nvmlDeviceArchitecture_t *arch); + +/** + * Retrieves the frequency monitor fault status for the device. + * + * For Ampere &tm; or newer fully supported devices. + * Requires root user. + * + * See \ref nvmlClkMonStatus_t for details on decoding the status output. + * + * @param device The identifier of the target device + * @param status Reference in which to return the clkmon fault status + * + * @return + * - \ref NVML_SUCCESS if \a status has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a status is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetClkMonStatus() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetClkMonStatus(nvmlDevice_t device, nvmlClkMonStatus_t *status); + +/** + * Retrieves the current utilization and process ID + * + * For Maxwell &tm; or newer fully supported devices. + * + * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running. + * Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at + * by \a utilization. One utilization sample structure is returned per process running, that had some non-zero utilization + * during the last sample period. It includes the CPU timestamp at which the samples were recorded. Individual utilization values + * are returned as "unsigned int" values. If no valid sample entries are found since the lastSeenTimeStamp, NVML_ERROR_NOT_FOUND + * is returned. + * + * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with + * \a utilization set to NULL. The caller should allocate a buffer of size + * processSamplesCount * sizeof(nvmlProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed + * in \a utilization, and \a processSamplesCount set to the number of entries the buffer is sized for. + * + * On successful return, the function updates \a processSamplesCount with the number of process utilization sample + * structures that were actually written. This may differ from a previously read value as instances are created or + * destroyed. + * + * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 + * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp + * to a timeStamp retrieved from a previous query to read utilization since the previous query. + * + * @note On MIG-enabled GPUs, querying process utilization is not currently supported. + * + * @param device The identifier of the target device + * @param utilization Pointer to caller-supplied buffer in which guest process utilization samples are returned + * @param processSamplesCount Pointer to caller-supplied array size, and returns number of processes running + * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. + + * @return + * - \ref NVML_SUCCESS if \a utilization has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlProcessUtilizationSample_t *utilization, + unsigned int *processSamplesCount, unsigned long long lastSeenTimeStamp); + +/** + * Retrieves the recent utilization and process ID for all running processes + * + * For Maxwell &tm; or newer fully supported devices. + * + * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder, jpeg decoder, OFA (Optical Flow Accelerator) + * for all running processes. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at + * by \a procesesUtilInfo->procUtilArray. One utilization sample structure is returned per process running, that had some non-zero utilization + * during the last sample period. It includes the CPU timestamp at which the samples were recorded. Individual utilization values + * are returned as "unsigned int" values. + * + * The caller should allocate a buffer of size processSamplesCount * sizeof(nvmlProcessUtilizationInfo_t). If the buffer is too small, the API will + * return \a NVML_ERROR_INSUFFICIENT_SIZE, with the recommended minimal buffer size at \a procesesUtilInfo->processSamplesCount. The caller should + * invoke the function again with the allocated buffer passed in \a procesesUtilInfo->procUtilArray, and \a procesesUtilInfo->processSamplesCount + * set to the number no less than the recommended value by the previous API return. + * + * On successful return, the function updates \a procesesUtilInfo->processSamplesCount with the number of process utilization info structures + * that were actually written. This may differ from a previously read value as instances are created or destroyed. + * + * \a procesesUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 + * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set \a procesesUtilInfo->lastSeenTimeStamp + * to a timeStamp retrieved from a previous query to read utilization since the previous query. + * + * \a procesesUtilInfo->version is the version number of the structure nvmlProcessesUtilizationInfo_t, the caller should set the correct version + * number to retrieve the specific version of processes utilization information. + * + * @note On MIG-enabled GPUs, querying process utilization is not currently supported. + * + * @param device The identifier of the target device + * @param procesesUtilInfo Pointer to the caller-provided structure of nvmlProcessesUtilizationInfo_t. + + * @return + * - \ref NVML_SUCCESS If \a procesesUtilInfo->procUtilArray has been populated + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, or \a procesesUtilInfo is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If the device does not support this feature + * - \ref NVML_ERROR_NOT_FOUND If sample entries are not found + * - \ref NVML_ERROR_GPU_IS_LOST If the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a procesesUtilInfo is invalid + * - \ref NVML_ERROR_INSUFFICIENT_SIZE If \a procesesUtilInfo->procUtilArray is NULL, or the buffer size of procesesUtilInfo->procUtilArray is too small. + * The caller should check the minimul array size from the returned procesesUtilInfo->processSamplesCount, and call + * the function again with a buffer no smaller than procesesUtilInfo->processSamplesCount * sizeof(nvmlProcessUtilizationInfo_t) + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetProcessesUtilizationInfo(nvmlDevice_t device, nvmlProcessesUtilizationInfo_t *procesesUtilInfo); + +/** + * Get platform information of this device. + * + * For Blackwell &tm; or newer fully supported devices. + * + * See \ref nvmlPlatformInfo_v2_t for more information on the struct. + * + * @param device The identifier of the target device + * @param platformInfo Pointer to the caller-provided structure of nvmlPlatformInfo_t. + * + * @return + * - \ref NVML_SUCCESS If \a platformInfo has been retrieved + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid or \a platformInfo is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If the device does not support this feature + * - \ref NVML_ERROR_MEMORY if system memory is insufficient + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a nvmlPlatformInfo_t is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPlatformInfo(nvmlDevice_t device, nvmlPlatformInfo_t *platformInfo); + +/** + * Retrieves the Per Device Identifier (PDI) associated with this device. + * + * For Pascal &tm; or newer fully supported devices. + * + * See \ref nvmlPdi_v1_t for more information on the struct. + * + * @param[in] device The identifier of the target device + * @param[out] pdi Reference to the caller-provided structure to return the GPU PDI + * + * @return + * - \ref NVML_SUCCESS if \a pdi has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a pdi is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version is invalid/unsupported + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPdi(nvmlDevice_t device, nvmlPdi_t *pdi); + +/** + * Set the hostname for the device. + * + * For Blackwell &tm; or newer fully supported devices. + * Requires root/admin permissions. + * Supported on Linux only. + * + * Sets a hostname string for the GPU device. This operation takes effect immediately. + * + * The hostname is not stored persistently across GPU resets or driver reloads. + * + * @param device The identifier of the target device + * @param hostname Reference to the caller-provided \ref nvmlHostname_v1_t struct containing the hostname + * + * @return + * - \ref NVML_SUCCESS if the hostname was set successfully + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a hostname is NULL or contains invalid characters + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetHostname_v1() + */ +nvmlReturn_t DECLDIR nvmlDeviceSetHostname_v1(nvmlDevice_t device, nvmlHostname_v1_t *hostname); + +/** + * Get the hostname for the device. + * + * For Blackwell &tm; or newer fully supported devices. + * Supported on Linux only. + * + * Retrieves the hostname string for the GPU device that was set using \ref nvmlDeviceSetHostname_v1(). + * + * @param device The identifier of the target device + * @param hostname Reference to the caller-provided \ref nvmlHostname_v1_t struct to return the hostname + * + * @return + * - \ref NVML_SUCCESS if the hostname was retrieved successfully + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a hostname is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceSetHostname_v1() + */ +nvmlReturn_t DECLDIR nvmlDeviceGetHostname_v1(nvmlDevice_t device, nvmlHostname_v1_t *hostname); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlUnitCommands Unit Commands + * This chapter describes NVML operations that change the state of the unit. For S-class products. + * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION + * error code when invoking any of these methods. + * @{ + */ +/***************************************************************************************************/ + +/** + * Set the LED state for the unit. The LED can be either green (0) or amber (1). + * + * For S-class products. + * Requires root/admin permissions. + * + * This operation takes effect immediately. + * + * + * Current S-Class products don't provide unique LEDs for each unit. As such, both front + * and back LEDs will be toggled in unison regardless of which unit is specified with this command. + * + * See \ref nvmlLedColor_t for available colors. + * + * @param unit The identifier of the target unit + * @param color The target LED color + * + * @return + * - \ref NVML_SUCCESS if the LED color has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a color is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlUnitGetLedState() + */ +nvmlReturn_t DECLDIR nvmlUnitSetLedState(nvmlUnit_t unit, nvmlLedColor_t color); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlDeviceCommands Device Commands + * This chapter describes NVML operations that change the state of the device. + * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION + * error code when invoking any of these methods. + * @{ + */ +/***************************************************************************************************/ + +/** + * Set the persistence mode for the device. + * + * For all products. + * For Linux only. + * Requires root/admin permissions. + * + * The persistence mode determines whether the GPU driver software is torn down after the last client + * exits. + * + * This operation takes effect immediately. It is not persistent across reboots. After each reboot the + * persistence mode is reset to "Disabled". + * + * See \ref nvmlEnableState_t for available modes. + * + * After calling this API with mode set to NVML_FEATURE_DISABLED on a device that has its own NUMA + * memory, the given device handle will no longer be valid, and to continue to interact with this + * device, a new handle should be obtained from one of the nvmlDeviceGetHandleBy*() APIs. This + * limitation is currently only applicable to devices that have a coherent NVLink connection to + * system memory. + * + * @param device The identifier of the target device + * @param mode The target persistence mode + * + * @return + * - \ref NVML_SUCCESS if the persistence mode was set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetPersistenceMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceSetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t mode); + +/** + * Set the compute mode for the device. + * + * For all products. + * Requires root/admin permissions. + * + * The compute mode determines whether a GPU can be used for compute operations and whether it can + * be shared across contexts. + * + * This operation takes effect immediately. Under Linux it is not persistent across reboots and + * always resets to "Default". Under windows it is persistent. + * + * Under windows compute mode may only be set to DEFAULT when running in WDDM + * + * @note On MIG-enabled GPUs, compute mode would be set to DEFAULT and changing it is not supported. + * + * See \ref nvmlComputeMode_t for details on available compute modes. + * + * @param device The identifier of the target device + * @param mode The target compute mode + * + * @return + * - \ref NVML_SUCCESS if the compute mode was set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetComputeMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceSetComputeMode(nvmlDevice_t device, nvmlComputeMode_t mode); + +/** + * Set the ECC mode for the device. + * + * For Kepler &tm; or newer fully supported devices. + * Only applicable to devices with ECC. + * Requires \a NVML_INFOROM_ECC version 1.0 or higher. + * Requires root/admin permissions. + * + * The ECC mode determines whether the GPU enables its ECC support. + * + * This operation takes effect after the next reboot. + * + * See \ref nvmlEnableState_t for details on available modes. + * + * @param device The identifier of the target device + * @param ecc The target ECC mode + * + * @return + * - \ref NVML_SUCCESS if the ECC mode was set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a ecc is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetEccMode() + */ +nvmlReturn_t DECLDIR nvmlDeviceSetEccMode(nvmlDevice_t device, nvmlEnableState_t ecc); + +/** + * Clear the ECC error and other memory error counts for the device. + * + * For Kepler &tm; or newer fully supported devices. + * Only applicable to devices with ECC. + * Requires \a NVML_INFOROM_ECC version 2.0 or higher to clear aggregate location-based ECC counts. + * Requires \a NVML_INFOROM_ECC version 1.0 or higher to clear all other ECC counts. + * Requires root/admin permissions. + * Requires ECC Mode to be enabled. + * + * Sets all of the specified ECC counters to 0, including both detailed and total counts. + * + * This operation takes effect immediately. + * + * See \ref nvmlMemoryErrorType_t for details on available counter types. + * + * @param device The identifier of the target device + * @param counterType Flag that indicates which type of errors should be cleared. + * + * @return + * - \ref NVML_SUCCESS if the error counts were cleared + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counterType is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see + * - nvmlDeviceGetDetailedEccErrors() + * - nvmlDeviceGetTotalEccErrors() + */ +nvmlReturn_t DECLDIR nvmlDeviceClearEccErrorCounts(nvmlDevice_t device, nvmlEccCounterType_t counterType); + +/** + * Set the driver model for the device. + * + * For Fermi &tm; or newer fully supported devices. + * For windows only. + * Requires root/admin permissions. + * + * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached + * to the device it must run in WDDM mode. + * + * It is possible to force the change to WDM (TCC) while the display is still attached with a force flag (nvmlFlagForce). + * This should only be done if the host is subsequently powered down and the display is detached from the device + * before the next reboot. + * + * This operation takes effect after the next reboot. + * + * Windows driver model may only be set to WDDM when running in DEFAULT compute mode. + * + * Change driver model to WDDM is not supported when GPU doesn't support graphics acceleration or + * will not support it after reboot. See \ref nvmlDeviceSetGpuOperationMode. + * + * See \ref nvmlDriverModel_t for details on available driver models. + * See \ref nvmlFlagDefault and \ref nvmlFlagForce + * + * @param device The identifier of the target device + * @param driverModel The target driver model + * @param flags Flags that change the default behavior + * + * @return + * - \ref NVML_SUCCESS if the driver model has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a driverModel is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows or the device does not support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetDriverModel() + */ +nvmlReturn_t DECLDIR nvmlDeviceSetDriverModel(nvmlDevice_t device, nvmlDriverModel_t driverModel, unsigned int flags); + +typedef enum nvmlClockLimitId_enum { + NVML_CLOCK_LIMIT_ID_RANGE_START = 0xffffff00, + NVML_CLOCK_LIMIT_ID_TDP, + NVML_CLOCK_LIMIT_ID_UNLIMITED +} nvmlClockLimitId_t; + +/** + * Set clocks that device will lock to. + * + * Sets the clocks that the device will be running at to the value in the range of minGpuClockMHz to maxGpuClockMHz. + * + * Can be used as a setting to request constant performance. + * + * This can be called with a pair of integer clock frequencies in MHz, or a pair of /ref nvmlClockLimitId_t values. + * See the table below for valid combinations of these values. + * + * minGpuClock | maxGpuClock | Effect + * ------------+-------------+-------------------------------------------------- + * tdp | tdp | Lock clock to TDP + * unlimited | tdp | Upper bound is TDP but clock may drift below this + * tdp | unlimited | Lower bound is TDP but clock may boost above this + * unlimited | unlimited | Unlocked (== nvmlDeviceResetGpuLockedClocks) + * + * If one arg takes one of these values, the other must be one of these values as + * well. Mixed numeric and symbolic calls return NVML_ERROR_INVALID_ARGUMENT. + * + * Requires root/admin permissions. + * + * After system reboot or driver reload GPU clocks go back to their default value. + * See \ref nvmlDeviceResetGpuLockedClocks. + * + * For Volta &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param minGpuClockMHz Requested minimum gpu clock in MHz + * @param maxGpuClockMHz Requested maximum gpu clock in MHz + * + * @return + * - \ref NVML_SUCCESS if new settings were successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minGpuClockMHz and \a maxGpuClockMHz + * is not a valid clock combination + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetGpuLockedClocks(nvmlDevice_t device, unsigned int minGpuClockMHz, unsigned int maxGpuClockMHz); + +/** + * Resets the gpu clock to the default value + * + * This is the gpu clock that will be used after system reboot or driver reload. + * Default values are idle clocks. + * + * @see nvmlDeviceSetGpuLockedClocks + * + * For Volta &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * + * @return + * - \ref NVML_SUCCESS if new settings were successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceResetGpuLockedClocks(nvmlDevice_t device); + +/** + * Set memory clocks that device will lock to. + * + * Sets the device's memory clocks to the value in the range of minMemClockMHz to maxMemClockMHz. + * + * Can be used as a setting to request constant performance. + * + * Requires root/admin permissions. + * + * After system reboot or driver reload memory clocks go back to their default value. + * See \ref nvmlDeviceResetMemoryLockedClocks. + * + * For Ampere &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param minMemClockMHz Requested minimum memory clock in MHz + * @param maxMemClockMHz Requested maximum memory clock in MHz + * + * @return + * - \ref NVML_SUCCESS if new settings were successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minGpuClockMHz and \a maxGpuClockMHz + * is not a valid clock combination + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetMemoryLockedClocks(nvmlDevice_t device, unsigned int minMemClockMHz, unsigned int maxMemClockMHz); + +/** + * Resets the memory clock to the default value + * + * This is the memory clock that will be used after system reboot or driver reload. + * Default values are idle clocks. + * + * @see nvmlDeviceSetMemoryLockedClocks + * + * For Ampere &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * + * @return + * - \ref NVML_SUCCESS if new settings were successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceResetMemoryLockedClocks(nvmlDevice_t device); + +/** + * @deprecated Applications clocks are deprecated and will be removed in CUDA 14.0. + * + * Please use \ref nvmlDeviceSetMemoryLockedClocks for Memory Clocks and + * \ref nvmlDeviceSetGpuLockedClocks for Graphics Clocks. + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceSetApplicationsClocks(nvmlDevice_t device, unsigned int memClockMHz, unsigned int graphicsClockMHz); + +/** + * @deprecated Applications clocks are deprecated and will be removed in CUDA 14.0. + * + * Please use \ref nvmlDeviceResetMemoryLockedClocks for Memory Clocks and + * \ref nvmlDeviceResetGpuLockedClocks for Graphics Clocks. + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceResetApplicationsClocks(nvmlDevice_t device); + +/** + * Try to set the current state of Auto Boosted clocks on a device. + * + * For Kepler &tm; or newer fully supported devices. + * + * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates + * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock + * rates are desired. + * + * Non-root users may use this API by default but can be restricted by root from using this API by calling + * \ref nvmlDeviceSetAPIRestriction with apiType=NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS. + * Note: Persistence Mode is required to modify current Auto Boost settings, therefore, it must be enabled. + * + * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. + * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost + * behavior. + * + * @param device The identifier of the target device + * @param enabled What state to try to set Auto Boosted clocks of the target device to + * + * @return + * - \ref NVML_SUCCESS If the Auto Boosted clocks were successfully set to the state specified by \a enabled + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + */ +nvmlReturn_t DECLDIR nvmlDeviceSetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled); + +/** + * Try to set the default state of Auto Boosted clocks on a device. This is the default state that Auto Boosted clocks will + * return to when no compute running processes (e.g. CUDA application which have an active context) are running + * + * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. + * Requires root/admin permissions. + * + * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates + * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock + * rates are desired. + * + * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. + * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost + * behavior. + * + * @param device The identifier of the target device + * @param enabled What state to try to set default Auto Boosted clocks of the target device to + * @param flags Flags that change the default behavior. Currently Unused. + * + * @return + * - \ref NVML_SUCCESS If the Auto Boosted clock's default state was successfully set to the state specified by \a enabled + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_NO_PERMISSION If the calling user does not have permission to change Auto Boosted clock's default state. + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + */ +nvmlReturn_t DECLDIR nvmlDeviceSetDefaultAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled, unsigned int flags); + +/** + * Sets the speed of the fan control policy to default. + * + * For all cuda-capable discrete products with fans + * + * @param device The identifier of the target device + * @param fan The index of the fan, starting at zero + * + * return + * NVML_SUCCESS if speed has been adjusted + * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * NVML_ERROR_INVALID_ARGUMENT if device is invalid + * NVML_ERROR_NOT_SUPPORTED if the device does not support this + * (doesn't have fans) + * NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetDefaultFanSpeed_v2(nvmlDevice_t device, unsigned int fan); + +/** + * Sets current fan control policy. + * + * For Maxwell &tm; or newer fully supported devices. + * + * Requires privileged user. + * + * For all cuda-capable discrete products with fans + * + * device The identifier of the target \a device + * policy The fan control \a policy to set + * + * return + * NVML_SUCCESS if \a policy has been set + * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a policy is null or the \a fan given doesn't reference + * a fan that exists. + * NVML_ERROR_NOT_SUPPORTED if the \a device is older than Maxwell + * NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetFanControlPolicy(nvmlDevice_t device, unsigned int fan, + nvmlFanControlPolicy_t policy); + +/** + * Sets the temperature threshold for the GPU with the specified threshold type in degrees C. + * + * For Maxwell &tm; or newer fully supported devices. + * + * See \ref nvmlTemperatureThresholds_t for details on available temperature thresholds. + * + * @param device The identifier of the target device + * @param thresholdType The type of threshold value to be set + * @param temp Reference which hold the value to be set + * @return + * - \ref NVML_SUCCESS if \a temp has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a thresholdType is invalid or \a temp is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a temperature sensor or is unsupported + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, int *temp); + +/** + * Set new power limit of this device. + * + * For Kepler &tm; or newer fully supported devices. + * Requires root/admin permissions. + * + * See \ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values. + * + * \note Limit is not persistent across reboots or driver unloads. + * Enable persistent mode to prevent driver from unloading when no application is using the device. + * + * @param device The identifier of the target device + * @param limit Power management limit in milliwatts to set + * + * @return + * - \ref NVML_SUCCESS if \a limit has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is out of range + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceGetPowerManagementLimitConstraints + * @see nvmlDeviceGetPowerManagementDefaultLimit + */ +nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit(nvmlDevice_t device, unsigned int limit); + +/** + * Sets new GOM. See \a nvmlGpuOperationMode_t for details. + * + * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. + * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. + * Not supported on Quadro ® and Tesla &tm; C-class products. + * Requires root/admin permissions. + * + * Changing GOMs requires a reboot. + * The reboot requirement might be removed in the future. + * + * Compute only GOMs don't support graphics acceleration. Under windows switching to these GOMs when + * pending driver model is WDDM is not supported. See \ref nvmlDeviceSetDriverModel. + * + * @param device The identifier of the target device + * @param mode Target GOM + * + * @return + * - \ref NVML_SUCCESS if \a mode has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode incorrect + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support GOM or specific mode + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlGpuOperationMode_t + * @see nvmlDeviceGetGpuOperationMode + */ +nvmlReturn_t DECLDIR nvmlDeviceSetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t mode); + +/** + * Changes the root/admin restructions on certain APIs. See \a nvmlRestrictedAPI_t for the list of supported APIs. + * This method can be used by a root/admin user to give non-root/admin access to certain otherwise-restricted APIs. + * The new setting lasts for the lifetime of the NVIDIA driver; it is not persistent. See \a nvmlDeviceGetAPIRestriction + * to query the current restriction settings. + * + * For Kepler &tm; or newer fully supported devices. + * Requires root/admin permissions. + * + * @param device The identifier of the target device + * @param apiType Target API type for this operation + * @param isRestricted The target restriction + * + * @return + * - \ref NVML_SUCCESS if \a isRestricted has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a apiType incorrect + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support changing API restrictions or the device does not support + * the feature that api restrictions are being set for (E.G. Enabling/disabling auto + * boosted clocks is not supported by the device) + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlRestrictedAPI_t + */ +nvmlReturn_t DECLDIR nvmlDeviceSetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t isRestricted); + +/** + * Sets the speed of a specified fan. + * + * WARNING: This function changes the fan control policy to manual. It means that YOU have to monitor + * the temperature and adjust the fan speed accordingly. + * If you set the fan speed too low you can burn your GPU! + * Use nvmlDeviceSetDefaultFanSpeed_v2 to restore default control policy. + * + * For all cuda-capable discrete products with fans that are Maxwell or Newer. + * + * device The identifier of the target device + * fan The index of the fan, starting at zero + * speed The target speed of the fan [0-100] in % of max speed + * + * return + * NVML_SUCCESS if the fan speed has been set + * NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * NVML_ERROR_INVALID_ARGUMENT if the device is not valid, or the speed is outside acceptable ranges, + * or if the fan index doesn't reference an actual fan. + * NVML_ERROR_NOT_SUPPORTED if the device is older than Maxwell. + * NVML_ERROR_UNKNOWN if there was an unexpected error. + */ +nvmlReturn_t DECLDIR nvmlDeviceSetFanSpeed_v2(nvmlDevice_t device, unsigned int fan, unsigned int speed); + +/** + * @deprecated Will be deprecated in a future release. Use \ref nvmlDeviceSetClockOffsets instead. It works + * on Maxwell onwards GPU architectures. + * + * Set the GPCCLK VF offset value + * @param[in] device The identifier of the target device + * @param[in] offset The GPCCLK VF offset value to set + * + * @return + * - \ref NVML_SUCCESS if \a offset has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceSetGpcClkVfOffset(nvmlDevice_t device, int offset); + +/** + * @deprecated Will be deprecated in a future release. Use \ref nvmlDeviceSetClockOffsets instead. It works + * on Maxwell onwards GPU architectures. + * + * Set the MemClk (Memory Clock) VF offset value. It requires elevated privileges. + * @param[in] device The identifier of the target device + * @param[in] offset The MemClk VF offset value to set + * + * @return + * - \ref NVML_SUCCESS if \a offset has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a offset is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceSetMemClkVfOffset(nvmlDevice_t device, int offset); + +/** + * @} + */ + +/** @addtogroup nvmlAccountingStats + * @{ + */ + +/** + * Enables or disables per process accounting. + * + * For Kepler &tm; or newer fully supported devices. + * Requires root/admin permissions. + * + * @note This setting is not persistent and will default to disabled after driver unloads. + * Enable persistence mode to be sure the setting doesn't switch off to disabled. + * + * @note Enabling accounting mode has no negative impact on the GPU performance. + * + * @note Disabling accounting clears all accounting pids information. + * + * @note On MIG-enabled GPUs, accounting mode would be set to DISABLED and changing it is not supported. + * + * See \ref nvmlDeviceGetAccountingMode + * See \ref nvmlDeviceGetAccountingStats + * See \ref nvmlDeviceClearAccountingPids + * + * @param device The identifier of the target device + * @param mode The target accounting mode + * + * @return + * - \ref NVML_SUCCESS if the new mode has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a mode are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetAccountingMode(nvmlDevice_t device, nvmlEnableState_t mode); + +/** + * Clears accounting information about all processes that have already terminated. + * + * For Kepler &tm; or newer fully supported devices. + * Requires root/admin permissions. + * + * See \ref nvmlDeviceGetAccountingMode + * See \ref nvmlDeviceGetAccountingStats + * See \ref nvmlDeviceSetAccountingMode + * + * @param device The identifier of the target device + * + * @return + * - \ref NVML_SUCCESS if accounting information has been cleared + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceClearAccountingPids(nvmlDevice_t device); + +/** @} */ // @addtogroup nvmlAccountingStats + +/***************************************************************************************************/ +/** @defgroup NvLink NvLink Methods + * This chapter describes methods that NVML can perform on NVLINK enabled devices. + * @{ + */ +/***************************************************************************************************/ + +#define NVML_NVLINK_BER_MANTISSA_SHIFT 8 +#define NVML_NVLINK_BER_MANTISSA_WIDTH 0xf + +#define NVML_NVLINK_BER_EXP_SHIFT 0 +#define NVML_NVLINK_BER_EXP_WIDTH 0xff + +/** + * Nvlink Error counter BER can be obtained using the below macros + * Ex - NVML_NVLINK_ERROR_COUNTER_BER_GET(var, BER_MANTISSA) + */ +#define NVML_NVLINK_ERROR_COUNTER_BER_GET(var, type) \ + (((var) >> NVML_NVLINK_##type##_SHIFT) & \ + (NVML_NVLINK_##type##_WIDTH)) \ + +/* + * NVML_FI_DEV_NVLINK_GET_STATE state enums + */ +#define NVML_NVLINK_STATE_INACTIVE 0x0 +#define NVML_NVLINK_STATE_ACTIVE 0x1 +#define NVML_NVLINK_STATE_SLEEP 0x2 + +#define NVML_NVLINK_TOTAL_SUPPORTED_BW_MODES 23 + +typedef struct +{ + unsigned int version; + unsigned char bwModes[NVML_NVLINK_TOTAL_SUPPORTED_BW_MODES]; + unsigned char totalBwModes; +} nvmlNvlinkSupportedBwModes_v1_t; +typedef nvmlNvlinkSupportedBwModes_v1_t nvmlNvlinkSupportedBwModes_t; +#define nvmlNvlinkSupportedBwModes_v1 NVML_STRUCT_VERSION(NvlinkSupportedBwModes, 1) + +typedef struct +{ + unsigned int version; + unsigned int bIsBest; + unsigned char bwMode; +} nvmlNvlinkGetBwMode_v1_t; +typedef nvmlNvlinkGetBwMode_v1_t nvmlNvlinkGetBwMode_t; +#define nvmlNvlinkGetBwMode_v1 NVML_STRUCT_VERSION(NvlinkGetBwMode, 1) + +typedef struct +{ + unsigned int version; + unsigned int bSetBest; + unsigned char bwMode; +} nvmlNvlinkSetBwMode_v1_t; +typedef nvmlNvlinkSetBwMode_v1_t nvmlNvlinkSetBwMode_t; +#define nvmlNvlinkSetBwMode_v1 NVML_STRUCT_VERSION(NvlinkSetBwMode, 1) + +/** + * Struct to represent per device NVLINK information v1 + */ +typedef struct +{ + unsigned int version; //!< IN - the API version number + unsigned int isNvleEnabled; //!< OUT - NVLINK encryption enablement +} nvmlNvLinkInfo_v1_t; +#define nvmlNvLinkInfo_v1 NVML_STRUCT_VERSION(NvLinkInfo, 1) + +#define NVML_NVLINK_FIRMWARE_UCODE_TYPE_MSE 0x1 +#define NVML_NVLINK_FIRMWARE_UCODE_TYPE_NETIR 0x2 +#define NVML_NVLINK_FIRMWARE_UCODE_TYPE_NETIR_UPHY 0x3 +#define NVML_NVLINK_FIRMWARE_UCODE_TYPE_NETIR_CLN 0x4 +#define NVML_NVLINK_FIRMWARE_UCODE_TYPE_NETIR_DLN 0x5 +#define NVML_NVLINK_FIRMWARE_VERSION_LENGTH 100 + +/** + * Struct to represent NVLINK firmware Semantic versioning and ucode type + */ +typedef struct +{ + unsigned char ucodeType; + unsigned int major; + unsigned int minor; + unsigned int subMinor; +} nvmlNvlinkFirmwareVersion_t; + +/** + * Struct to represent NVLINK firmware information + */ +typedef struct +{ + nvmlNvlinkFirmwareVersion_t firmwareVersion[NVML_NVLINK_FIRMWARE_VERSION_LENGTH]; //!< OUT - NVLINK firmware version + unsigned int numValidEntries; //!< OUT - Number of valid firmware entries +} nvmlNvlinkFirmwareInfo_t; + +/** + * Struct to represent per device NVLINK information v2 + */ +typedef struct +{ + unsigned int version; //!< IN - the API version number + unsigned int isNvleEnabled; //!< OUT - NVLINK encryption enablement + nvmlNvlinkFirmwareInfo_t firmwareInfo; //!< OUT - NVLINK Firmware info +} nvmlNvLinkInfo_v2_t; +typedef nvmlNvLinkInfo_v2_t nvmlNvLinkInfo_t; +#define nvmlNvLinkInfo_v2 NVML_STRUCT_VERSION(NvLinkInfo, 2) + +/** + * Retrieves the state of the device's NvLink for the link specified + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * @param isActive \a nvmlEnableState_t where NVML_FEATURE_ENABLED indicates that + * the link is active and NVML_FEATURE_DISABLED indicates it + * is inactive + * + * @return + * - \ref NVML_SUCCESS if \a isActive has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a isActive is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkState(nvmlDevice_t device, unsigned int link, nvmlEnableState_t *isActive); + +/** + * Retrieves the version of the device's NvLink for the link specified + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * @param version Requested NvLink version from nvmlNvlinkVersion_t + * + * @return + * - \ref NVML_SUCCESS if \a version has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a version is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkVersion(nvmlDevice_t device, unsigned int link, unsigned int *version); + +/** + * Retrieves the requested capability from the device's NvLink for the link specified + * Please refer to the \a nvmlNvLinkCapability_t structure for the specific caps that can be queried + * The return value should be treated as a boolean. + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * @param capability Specifies the \a nvmlNvLinkCapability_t to be queried + * @param capResult A boolean for the queried capability indicating that feature is available + * + * @return + * - \ref NVML_SUCCESS if \a capResult has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a capability is invalid or \a capResult is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkCapability(nvmlDevice_t device, unsigned int link, + nvmlNvLinkCapability_t capability, unsigned int *capResult); + +/** + * Retrieves the PCI information for the remote node on a NvLink link + * Note: pciSubSystemId is not filled in this function and is indeterminate + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * @param pci \a nvmlPciInfo_t of the remote node for the specified link + * + * @return + * - \ref NVML_SUCCESS if \a pci has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a pci is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo_v2(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci); + +/** + * Retrieves the specified error counter value + * Please refer to \a nvmlNvLinkErrorCounter_t for error counters that are available + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * @param counter Specifies the NvLink counter to be queried + * @param counterValue Returned counter value + * + * @return + * - \ref NVML_SUCCESS if \a counter has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid or \a counterValue is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkErrorCounter(nvmlDevice_t device, unsigned int link, + nvmlNvLinkErrorCounter_t counter, unsigned long long *counterValue); + +/** + * Resets all error counters to zero + * Please refer to \a nvmlNvLinkErrorCounter_t for the list of error counters that are reset + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * + * @return + * - \ref NVML_SUCCESS if the reset is successful + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkErrorCounters(nvmlDevice_t device, unsigned int link); + +/** + * @deprecated Setting utilization counter control is no longer supported. + * + * Set the NVLINK utilization counter control information for the specified counter, 0 or 1. + * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition. Performs a reset + * of the counters if the reset parameter is non-zero. + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param counter Specifies the counter that should be set (0 or 1). + * @param link Specifies the NvLink link to be queried + * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to set + * @param reset Resets the counters on set if non-zero + * + * @return + * - \ref NVML_SUCCESS if the control has been set successfully + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceSetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, + nvmlNvLinkUtilizationControl_t *control, unsigned int reset); + +/** + * @deprecated Getting utilization counter control is no longer supported. + * + * Get the NVLINK utilization counter control information for the specified counter, 0 or 1. + * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param counter Specifies the counter that should be set (0 or 1). + * @param link Specifies the NvLink link to be queried + * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to place information + * + * @return + * - \ref NVML_SUCCESS if the control has been set successfully + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, + nvmlNvLinkUtilizationControl_t *control); + + +/** + * @deprecated Use \ref nvmlDeviceGetFieldValues with NVML_FI_DEV_NVLINK_THROUGHPUT_* as field values instead. + * + * Retrieve the NVLINK utilization counter based on the current control for a specified counter. + * In general it is good practice to use \a nvmlDeviceSetNvLinkUtilizationControl + * before reading the utilization counters as they have no default state + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * @param counter Specifies the counter that should be read (0 or 1). + * @param rxcounter Receive counter return value + * @param txcounter Transmit counter return value + * + * @return + * - \ref NVML_SUCCESS if \a rxcounter and \a txcounter have been successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, or \a link is invalid or \a rxcounter or \a txcounter are NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationCounter(nvmlDevice_t device, unsigned int link, unsigned int counter, + unsigned long long *rxcounter, unsigned long long *txcounter); + +/** + * @deprecated Freezing NVLINK utilization counters is no longer supported. + * + * Freeze the NVLINK utilization counters + * Both the receive and transmit counters are operated on by this function + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be queried + * @param counter Specifies the counter that should be frozen (0 or 1). + * @param freeze NVML_FEATURE_ENABLED = freeze the receive and transmit counters + * NVML_FEATURE_DISABLED = unfreeze the receive and transmit counters + * + * @return + * - \ref NVML_SUCCESS if counters were successfully frozen or unfrozen + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, \a counter, or \a freeze is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceFreezeNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, + unsigned int counter, nvmlEnableState_t freeze); + +/** + * @deprecated Resetting NVLINK utilization counters is no longer supported. + * + * Reset the NVLINK utilization counters + * Both the receive and transmit counters are operated on by this function + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param link Specifies the NvLink link to be reset + * @param counter Specifies the counter that should be reset (0 or 1) + * + * @return + * - \ref NVML_SUCCESS if counters were successfully reset + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, unsigned int counter); + +/** +* Get the NVLink device type of the remote device connected over the given link. +* +* @param device The device handle of the target GPU +* @param link The NVLink link index on the target GPU +* @param pNvLinkDeviceType Pointer in which the output remote device type is returned +* +* @return +* - \ref NVML_SUCCESS if \a pNvLinkDeviceType has been set +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_NOT_SUPPORTED if NVLink is not supported +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid, or +* \a pNvLinkDeviceType is NULL +* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is +* otherwise inaccessible +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemoteDeviceType(nvmlDevice_t device, unsigned int link, nvmlIntNvLinkDeviceType_t *pNvLinkDeviceType); + +/** + * Set NvLink Low Power Threshold for device. + * + * For Hopper &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param info Reference to \a nvmlNvLinkPowerThres_t struct + * input parameters + * + * @return + * - \ref NVML_SUCCESS if the \a Threshold is successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a Threshold is not within range + * - \ref NVML_ERROR_NOT_READY if an internal driver setting prevents the threshold from being used + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * + **/ +nvmlReturn_t DECLDIR nvmlDeviceSetNvLinkDeviceLowPowerThreshold(nvmlDevice_t device, nvmlNvLinkPowerThres_t *info); + +/** + * Set the global nvlink bandwith mode + * + * @param nvlinkBwMode nvlink bandwidth mode + * @return + * - \ref NVML_SUCCESS on success + * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid argument is provided + * - \ref NVML_ERROR_IN_USE if P2P object exists + * - \ref NVML_ERROR_NOT_SUPPORTED if GPU is not Hopper or newer architecture. + * - \ref NVML_ERROR_NO_PERMISSION if not root user + */ +nvmlReturn_t DECLDIR nvmlSystemSetNvlinkBwMode(unsigned int nvlinkBwMode); + +/** + * Get the global nvlink bandwith mode + * + * @param nvlinkBwMode reference of nvlink bandwidth mode + * @return + * - \ref NVML_SUCCESS on success + * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid pointer is provided + * - \ref NVML_ERROR_NOT_SUPPORTED if GPU is not Hopper or newer architecture. + * - \ref NVML_ERROR_NO_PERMISSION if not root user + */ +nvmlReturn_t DECLDIR nvmlSystemGetNvlinkBwMode(unsigned int *nvlinkBwMode); + +/** + * Get the supported NvLink Reduced Bandwidth Modes of the device + * + * For Blackwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param supportedBwMode Reference to \a nvmlNvlinkSupportedBwModes_t + * + * @return + * - \ref NVML_SUCCESS if the query was successful + * - \ref NVML_ERROR_INVALID_ARGUMENT if device is invalid or supportedBwMode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this feature is not supported by the device + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version specified is not supported + **/ +nvmlReturn_t DECLDIR nvmlDeviceGetNvlinkSupportedBwModes(nvmlDevice_t device, + nvmlNvlinkSupportedBwModes_t *supportedBwMode); + +/** + * Get the NvLink Reduced Bandwidth Mode for the device + * + * For Blackwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param getBwMode Reference to \a nvmlNvlinkGetBwMode_t + * + * @return + * - \ref NVML_SUCCESS if the query was successful + * - \ref NVML_ERROR_INVALID_ARGUMENT if device is invalid or getBwMode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this feature is not supported by the device + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version specified is not supported + **/ +nvmlReturn_t DECLDIR nvmlDeviceGetNvlinkBwMode(nvmlDevice_t device, + nvmlNvlinkGetBwMode_t *getBwMode); + +/** + * Set the NvLink Reduced Bandwidth Mode for the device + * + * For Blackwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param setBwMode Reference to \a nvmlNvlinkSetBwMode_t + * + * @return + * - \ref NVML_SUCCESS if the Bandwidth mode was successfully set + * - \ref NVML_ERROR_INVALID_ARGUMENT if device is invalid or setBwMode is NULL + * - \ref NVML_ERROR_NO_PERMISSION if user does not have permission to change Bandwidth mode + * - \ref NVML_ERROR_NOT_SUPPORTED if this feature is not supported by the device + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version specified is not supported + **/ +nvmlReturn_t DECLDIR nvmlDeviceSetNvlinkBwMode(nvmlDevice_t device, + nvmlNvlinkSetBwMode_t *setBwMode); + +/** + * Query NVLINK information associated with this device. + * + * @param[in] device The identifier of the target device + * @param[out] info Reference to \a nvmlNvLinkInfo_t + * + * @return + * - \ref NVML_SUCCESS if query is success + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a info is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version is invalid/unsupported + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkInfo(nvmlDevice_t device, nvmlNvLinkInfo_t *info); + +/** @} */ // @defgroup NvLink NvLink Methods + +/***************************************************************************************************/ +/** @defgroup nvmlEvents Event Handling Methods + * This chapter describes methods that NVML can perform against each device to register and wait for + * some event to occur. + * @{ + */ +/***************************************************************************************************/ + +/** + * Create an empty set of events. + * Event set should be freed by \ref nvmlEventSetFree + * + * For Fermi &tm; or newer fully supported devices. + * @param set Reference in which to return the event handle + * + * @return + * - \ref NVML_SUCCESS if the event has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a set is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlEventSetFree + */ +nvmlReturn_t DECLDIR nvmlEventSetCreate(nvmlEventSet_t *set); + +/** + * Starts recording of events on a specified devices and add the events to specified \ref nvmlEventSet_t + * + * For Fermi &tm; or newer fully supported devices. + * ECC events are available only on ECC-enabled devices (see \ref nvmlDeviceGetTotalEccErrors) + * Power capping events are available only on Power Management enabled devices (see \ref nvmlDeviceGetPowerManagementMode) + * + * For Linux only. + * + * This call starts recording of events on specific device. + * All events that occurred before this call are not recorded. + * Checking if some event occurred can be done with \ref nvmlEventSetWait_v2 + * + * If function reports NVML_ERROR_UNKNOWN, event set is in undefined state and should be freed. + * If function reports NVML_ERROR_NOT_SUPPORTED, event set can still be used. None of the requested eventTypes + * are registered in that case. + * + * @param device The identifier of the target device + * @param eventTypes Bitmask of \ref nvmlEventType to record + * @param set Set to which add new event types + * + * @return + * - \ref NVML_SUCCESS if the event has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventTypes is invalid or \a set is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the platform does not support this feature or some of requested event types + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlEventType + * @see nvmlDeviceGetSupportedEventTypes + * @see nvmlEventSetWait + * @see nvmlEventSetFree + */ +nvmlReturn_t DECLDIR nvmlDeviceRegisterEvents(nvmlDevice_t device, unsigned long long eventTypes, nvmlEventSet_t set); + +/** + * Returns information about events supported on device + * + * For Fermi &tm; or newer fully supported devices. + * + * Events are not supported on Windows. So this function returns an empty mask in \a eventTypes on Windows. + * + * @param device The identifier of the target device + * @param eventTypes Reference in which to return bitmask of supported events + * + * @return + * - \ref NVML_SUCCESS if the eventTypes has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventType is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlEventType + * @see nvmlDeviceRegisterEvents + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSupportedEventTypes(nvmlDevice_t device, unsigned long long *eventTypes); + +/** + * Waits on events and delivers events + * + * For Fermi &tm; or newer fully supported devices. + * + * If some events are ready to be delivered at the time of the call, function returns immediately. + * If there are no events ready to be delivered, function sleeps till event arrives + * but not longer than specified timeout. This function in certain conditions can return before + * specified timeout passes (e.g. when interrupt arrives) + * + * On Windows, in case of Xid error, the function returns the most recent Xid error type seen by the system. + * If there are multiple Xid errors generated before nvmlEventSetWait is invoked then the last seen Xid error + * type is returned for all Xid error events. + * + * On Linux, every Xid error event would return the associated event data and other information if applicable. + * + * In MIG mode, if device handle is provided, the API reports all the events for the available instances, + * only if the caller has appropriate privileges. In absence of required privileges, only the events which + * affect all the instances (i.e. whole device) are reported. + * + * This API does not currently support per-instance event reporting using MIG device handles. + * + * @param set Reference to set of events to wait on + * @param data Reference in which to return event data + * @param timeoutms Maximum amount of wait time in milliseconds for registered event + * + * @return + * - \ref NVML_SUCCESS if the data has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a data is NULL + * - \ref NVML_ERROR_TIMEOUT if no event arrived in specified timeout or interrupt arrived + * - \ref NVML_ERROR_GPU_IS_LOST if a GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlEventType + * @see nvmlDeviceRegisterEvents + */ +nvmlReturn_t DECLDIR nvmlEventSetWait_v2(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms); + +/** + * Releases events in the set + * + * For Fermi &tm; or newer fully supported devices. + * + * @param set Reference to events to be released + * + * @return + * - \ref NVML_SUCCESS if the event has been successfully released + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceRegisterEvents + */ +nvmlReturn_t DECLDIR nvmlEventSetFree(nvmlEventSet_t set); + +/** + * Create an empty set of system events. + * Event set should be freed by \ref nvmlSystemEventSetFree + * + * For Fermi &tm; or newer fully supported devices. + * @param request Reference to nvmlSystemEventSetCreateRequest_t + * + * @return + * - \ref NVML_SUCCESS if the event has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if request is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH for unsupported version + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlSystemEventSetFree + */ +nvmlReturn_t DECLDIR nvmlSystemEventSetCreate(nvmlSystemEventSetCreateRequest_t *request); + +/** + * Releases system event set + * + * For Fermi &tm; or newer fully supported devices. + * + * @param request Reference to nvmlSystemEventSetFreeRequest_t + * + * @return + * - \ref NVML_SUCCESS if the event has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if request is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH for unsupported version + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlDeviceRegisterEvents + */ +nvmlReturn_t DECLDIR nvmlSystemEventSetFree(nvmlSystemEventSetFreeRequest_t *request); + +/** + * Starts recording of events on system and add the events to specified \ref nvmlSystemEventSet_t + * + * For Linux only. + * + * This call starts recording of events on specific device. + * All events that occurred before this call are not recorded. + * Checking if some event occurred can be done with \ref nvmlSystemEventSetWait + * + * If function reports NVML_ERROR_UNKNOWN, event set is in undefined state and should be freed. + * If function reports NVML_ERROR_NOT_SUPPORTED, event set can still be used. None of the requested eventTypes + * are registered in that case. + * + * @param request Reference to the struct nvmlSystemRegisterEventRequest_t + * + * @return + * - \ref NVML_SUCCESS if the event has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if request is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH for unsupported version + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlSystemEventType + * @see nvmlSystemEventSetWait + * @see nvmlEventSetFree + */ +nvmlReturn_t DECLDIR nvmlSystemRegisterEvents(nvmlSystemRegisterEventRequest_t *request); + +/** + * Waits on system events and delivers events + * + * For Fermi &tm; or newer fully supported devices. + * + * If some events are ready to be delivered at the time of the call, function returns immediately. + * If there are no events ready to be delivered, function sleeps till event arrives + * but not longer than specified timeout. This function in certain conditions can return before + * specified timeout passes (e.g. when interrupt arrives) + * + * if the return request->numEvent equals to request->dataSize, there might be outstanding + * event, it is recommended to call nvmlSystemEventSetWait again to query all the events. + * + * @param request Reference in which to nvmlSystemEventSetWaitRequest_t + * + * @return + * - \ref NVML_SUCCESS if the event has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if request is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH for unsupported version + * - \ref NVML_ERROR_TIMEOUT if no event notification after timeoutms + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlSystemEventType + * @see nvmlSystemRegisterEvents + */ +nvmlReturn_t DECLDIR nvmlSystemEventSetWait(nvmlSystemEventSetWaitRequest_t *request); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlZPI Drain states + * This chapter describes methods that NVML can perform against each device to control their drain state + * and recognition by NVML and NVIDIA kernel driver. These methods can be used with out-of-band tools to + * power on/off GPUs, enable robust reset scenarios, etc. + * @{ + */ +/***************************************************************************************************/ + +/** + * Modify the drain state of a GPU. This method forces a GPU to no longer accept new incoming requests. + * Any new NVML process will no longer see this GPU. Persistence mode for this GPU must be turned off before + * this call is made. + * Must be called as administrator. + * For Linux only. + * + * For Pascal &tm; or newer fully supported devices. + * Some Kepler devices supported. + * + * @param pciInfo The PCI address of the GPU drain state to be modified + * @param newState The drain state that should be entered, see \ref nvmlEnableState_t + * + * @return + * - \ref NVML_SUCCESS if counters were successfully reset + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a newState is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation + * - \ref NVML_ERROR_IN_USE if the device has persistence mode turned on + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceModifyDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t newState); + +/** + * Query the drain state of a GPU. This method is used to check if a GPU is in a currently draining + * state. + * For Linux only. + * + * For Pascal &tm; or newer fully supported devices. + * Some Kepler devices supported. + * + * @param pciInfo The PCI address of the GPU drain state to be queried + * @param currentState The current drain state for this GPU, see \ref nvmlEnableState_t + * + * @return + * - \ref NVML_SUCCESS if counters were successfully reset + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a currentState is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceQueryDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t *currentState); + +/** + * This method will remove the specified GPU from the view of both NVML and the NVIDIA kernel driver + * as long as no other processes are attached. If other processes are attached, this call will return + * NVML_ERROR_IN_USE and the GPU will be returned to its original "draining" state. Note: the + * only situation where a process can still be attached after nvmlDeviceModifyDrainState() is called + * to initiate the draining state is if that process was using, and is still using, a GPU before the + * call was made. Also note, persistence mode counts as an attachment to the GPU thus it must be disabled + * prior to this call. + * + * For long-running NVML processes please note that this will change the enumeration of current GPUs. + * For example, if there are four GPUs present and GPU1 is removed, the new enumeration will be 0-2. + * Also, device handles after the removed GPU will not be valid and must be re-established. + * Must be run as administrator. + * For Linux only. + * + * For Pascal &tm; or newer fully supported devices. + * Some Kepler devices supported. + * + * @param pciInfo The PCI address of the GPU to be removed + * @param gpuState Whether the GPU is to be removed, from the OS + * see \ref nvmlDetachGpuState_t + * @param linkState Requested upstream PCIe link state, see \ref nvmlPcieLinkState_t + * + * @return + * - \ref NVML_SUCCESS if counters were successfully reset + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature + * - \ref NVML_ERROR_IN_USE if the device is still in use and cannot be removed + */ +nvmlReturn_t DECLDIR nvmlDeviceRemoveGpu_v2(nvmlPciInfo_t *pciInfo, nvmlDetachGpuState_t gpuState, nvmlPcieLinkState_t linkState); + +/** + * Request the OS and the NVIDIA kernel driver to rediscover a portion of the PCI subsystem looking for GPUs that + * were previously removed. The portion of the PCI tree can be narrowed by specifying a domain, bus, and device. + * If all are zeroes then the entire PCI tree will be searched. Please note that for long-running NVML processes + * the enumeration will change based on how many GPUs are discovered and where they are inserted in bus order. + * + * In addition, all newly discovered GPUs will be initialized and their ECC scrubbed which may take several seconds + * per GPU. Also, all device handles are no longer guaranteed to be valid post discovery. + * + * Must be run as administrator. + * For Linux only. + * + * For Pascal &tm; or newer fully supported devices. + * Some Kepler devices supported. + * + * @param pciInfo The PCI tree to be searched. Only the domain, bus, and device + * fields are used in this call. + * + * @return + * - \ref NVML_SUCCESS if counters were successfully reset + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciInfo is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if the operating system does not support this feature + * - \ref NVML_ERROR_OPERATING_SYSTEM if the operating system is denying this feature + * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceDiscoverGpus (nvmlPciInfo_t *pciInfo); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlFieldValueQueries Field Value Queries + * This chapter describes NVML operations that are associated with retrieving Field Values from NVML + * @{ + */ +/***************************************************************************************************/ + +/** + * Request values for a list of fields for a device. This API allows multiple fields to be queried at once. + * If any of the underlying fieldIds are populated by the same driver call, the results for those field IDs + * will be populated from a single call rather than making a driver call for each fieldId. + * + * @param device The device handle of the GPU to request field values for + * @param valuesCount Number of entries in values that should be retrieved + * @param values Array of \a valuesCount structures to hold field values. + * Each value's fieldId must be populated prior to this call + * + * @return + * - \ref NVML_SUCCESS if any values in \a values were populated. Note that you must + * check the nvmlReturn field of each value for each individual + * status + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a values is NULL + */ +nvmlReturn_t DECLDIR nvmlDeviceGetFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values); + +/** + * Clear values for a list of fields for a device. This API allows multiple fields to be cleared at once. + * + * @param device The device handle of the GPU to request field values for + * @param valuesCount Number of entries in values that should be cleared + * @param values Array of \a valuesCount structures to hold field values. + * Each value's fieldId must be populated prior to this call + * + * @return + * - \ref NVML_SUCCESS if any values in \a values were cleared. Note that you must + * check the nvmlReturn field of each value for each individual + * status + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a values is NULL + */ +nvmlReturn_t DECLDIR nvmlDeviceClearFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlVirtualGpuQueries vGPU APIs + * This chapter describes operations that are associated with NVIDIA vGPU Software products. + * @{ + */ +/***************************************************************************************************/ + +/** + * This method is used to get the virtualization mode corresponding to the GPU. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device Identifier of the target device + * @param pVirtualMode Reference to virtualization mode. One of NVML_GPU_VIRTUALIZATION_? + * + * @return + * - \ref NVML_SUCCESS if \a pVirtualMode is fetched + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pVirtualMode is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t *pVirtualMode); + +/** + * Queries if SR-IOV host operation is supported on a vGPU supported device. + * + * Checks whether SR-IOV host capability is supported by the device and the + * driver, and indicates device is in SR-IOV mode if both of these conditions + * are true. + * + * @param device The identifier of the target device + * @param pHostVgpuMode Reference in which to return the current vGPU mode + * + * @return + * - \ref NVML_SUCCESS if device's vGPU mode has been successfully retrieved + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device handle is 0 or \a pVgpuMode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if \a device doesn't support this feature. + * - \ref NVML_ERROR_UNKNOWN if any unexpected error occurred + */ +nvmlReturn_t DECLDIR nvmlDeviceGetHostVgpuMode(nvmlDevice_t device, nvmlHostVgpuMode_t *pHostVgpuMode); + +/** + * This method is used to set the virtualization mode corresponding to the GPU. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device Identifier of the target device + * @param virtualMode virtualization mode. One of NVML_GPU_VIRTUALIZATION_? + * + * @return + * - \ref NVML_SUCCESS if \a virtualMode is set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a virtualMode is NULL + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_SUPPORTED if setting of virtualization mode is not supported. + * - \ref NVML_ERROR_NO_PERMISSION if setting of virtualization mode is not allowed for this client. + */ +nvmlReturn_t DECLDIR nvmlDeviceSetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t virtualMode); + +/** + * Get the vGPU heterogeneous mode for the device. + * + * When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes. + * + * On successful return, the function returns \a pHeterogeneousMode->mode with the current vGPU heterogeneous mode. + * \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should + * set the correct version number to retrieve the vGPU heterogeneous mode. + * \a pHeterogeneousMode->mode can either be \ref NVML_FEATURE_ENABLED or \ref NVML_FEATURE_DISABLED. + * + * @param device The identifier of the target device + * @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid or \a pHeterogeneousMode is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device doesn't support this feature + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuHeterogeneousMode(nvmlDevice_t device, nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode); + +/** + * Enable or disable vGPU heterogeneous mode for the device. + * + * When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes. + * + * API would return an appropriate error code upon unsuccessful activation. For example, the heterogeneous mode + * set will fail with error \ref NVML_ERROR_IN_USE if any vGPU instance is active on the device. The caller of this API + * is expected to shutdown the vGPU VMs and retry setting the \a mode. + * On KVM platform, setting heterogeneous mode is allowed, if no MDEV device is created on the device, else will fail + * with same error \ref NVML_ERROR_IN_USE. + * On successful return, the function updates the vGPU heterogeneous mode with the user provided \a pHeterogeneousMode->mode. + * \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should + * set the correct version number to set the vGPU heterogeneous mode. + * + * @param device Identifier of the target device + * @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a pHeterogeneousMode is NULL or \a pHeterogeneousMode->mode is invalid + * - \ref NVML_ERROR_IN_USE If the \a device is in use + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device doesn't support this feature + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetVgpuHeterogeneousMode(nvmlDevice_t device, const nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode); + +/** + * Query the placement ID of active vGPU instance. + * + * When in vGPU heterogeneous mode, this function returns a valid placement ID as \a pPlacement->placementId + * else NVML_INVALID_VGPU_PLACEMENT_ID is returned. + * \a pPlacement->version is the version number of the structure nvmlVgpuPlacementId_t, the caller should + * set the correct version number to get placement id of the vGPU instance \a vgpuInstance. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param pPlacement Pointer to vGPU placement ID structure \a nvmlVgpuPlacementId_t + * + * @return + * - \ref NVML_SUCCESS If information is successfully retrieved + * - \ref NVML_ERROR_NOT_FOUND If \a vgpuInstance does not match a valid active vGPU instance + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuInstance is invalid or \a pPlacement is NULL + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pPlacement is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetPlacementId(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuPlacementId_t *pPlacement); + +/** + * Query the supported vGPU placement ID of the vGPU type. + * + * The function returns an array of supported vGPU placement IDs for the specified vGPU type ID in the buffer provided + * by the caller at \a pPlacementList->placementIds. The required memory for the placementIds array must be allocated + * based on the maximum number of vGPU type instances, which is retrievable through \ref nvmlVgpuTypeGetMaxInstances(). + * If the provided count by the caller is insufficient, the function will return NVML_ERROR_INSUFFICIENT_SIZE along with + * the number of required entries in \a pPlacementList->count. The caller should then reallocate a buffer with the size + * of pPlacementList->count * sizeof(pPlacementList->placementIds) and invoke the function again. + * + * To obtain a list of homogeneous placement IDs, the caller needs to set \a pPlacementList->mode to NVML_VGPU_PGPU_HOMOGENEOUS_MODE. + * For heterogeneous placement IDs, \a pPlacementList->mode should be set to NVML_VGPU_PGPU_HETEROGENEOUS_MODE. + * By default, a list of heterogeneous placement IDs is returned. + * + * @param device Identifier of the target device + * @param vgpuTypeId Handle to vGPU type. The vGPU type ID + * @param pPlacementList Pointer to the vGPU placement structure \a nvmlVgpuPlacementList_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a vgpuTypeId is invalid or \a pPlacementList is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device or \a vgpuTypeId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pPlacementList is invalid + * - \ref NVML_ERROR_INSUFFICIENT_SIZE If the buffer is small, element count is returned in \a pPlacementList->count + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuTypeSupportedPlacements(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuPlacementList_t *pPlacementList); + +/** + * Query the creatable vGPU placement ID of the vGPU type. + * + * An array of creatable vGPU placement IDs for the vGPU type ID indicated by \a vgpuTypeId is returned in the + * caller-supplied buffer of \a pPlacementList->placementIds. Memory needed for the placementIds array should be + * allocated based on maximum instances of a vGPU type which can be queried via \ref nvmlVgpuTypeGetMaxInstances(). + * If the provided count by the caller is insufficient, the function will return NVML_ERROR_INSUFFICIENT_SIZE along with + * the number of required entries in \a pPlacementList->count. The caller should then reallocate a buffer with the size + * of pPlacementList->count * sizeof(pPlacementList->placementIds) and invoke the function again. + * + * The creatable vGPU placement IDs may differ over time, as there may be restrictions on what type of vGPU the + * vGPU instance is running. + * + * @param device The identifier of the target device + * @param vgpuTypeId Handle to vGPU type. The vGPU type ID + * @param pPlacementList Pointer to the list of vGPU placement structure \a nvmlVgpuPlacementList_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a vgpuTypeId is invalid or \a pPlacementList is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device or \a vgpuTypeId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pPlacementList is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuTypeCreatablePlacements(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuPlacementList_t *pPlacementList); + +/** + * Retrieve the static GSP heap size of the vGPU type in bytes + * + * @param vgpuTypeId Handle to vGPU type + * @param gspHeapSize Reference to return the GSP heap size value + * @return + * - \ref NVML_SUCCESS Successful completion + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuTypeId is invalid, or \a gspHeapSize is NULL + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetGspHeapSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *gspHeapSize); + +/** + * Retrieve the static framebuffer reservation of the vGPU type in bytes + * + * @param vgpuTypeId Handle to vGPU type + * @param fbReservation Reference to return the framebuffer reservation + * @return + * - \ref NVML_SUCCESS Successful completion + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuTypeId is invalid, or \a fbReservation is NULL + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetFbReservation(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbReservation); + +/** + * Retrieve the currently used runtime state size of the vGPU instance + * + * This size represents the maximum in-memory data size utilized by a vGPU instance during standard operation. + * This measurement is exclusive of frame buffer (FB) data size assigned to the vGPU instance. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param pState Pointer to the vGPU runtime state's structure \a nvmlVgpuRuntimeState_t + * + * @return + * - \ref NVML_SUCCESS If information is successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuInstance is invalid, or \a pState is NULL + * - \ref NVML_ERROR_NOT_FOUND If \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pState is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetRuntimeStateSize(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuRuntimeState_t *pState); + +/** + * Set the desirable vGPU capability of a device + * + * Refer to the \a nvmlDeviceVgpuCapability_t structure for the specific capabilities that can be set. + * See \ref nvmlEnableState_t for available state. + * + * @param device The identifier of the target device + * @param capability Specifies the \a nvmlDeviceVgpuCapability_t to be set + * @param state The target capability mode + * + * @return + * - \ref NVML_SUCCESS Successful completion + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, or \a capability is invalid, or \a state is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state, or \a device not in vGPU mode + * - \ref NVML_ERROR_UNKNOWN On any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlDeviceSetVgpuCapabilities(nvmlDevice_t device, nvmlDeviceVgpuCapability_t capability, nvmlEnableState_t state); + +/** + * Retrieve the vGPU Software licensable features. + * + * Identifies whether the system supports vGPU Software Licensing. If it does, return the list of licensable feature(s) + * and their current license status. + * + * @param device Identifier of the target device + * @param pGridLicensableFeatures Pointer to structure in which vGPU software licensable features are returned + * + * @return + * - \ref NVML_SUCCESS if licensable features are successfully retrieved + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pGridLicensableFeatures is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures_v4(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlVgpu vGPU Management + * @{ + * + * This chapter describes APIs supporting NVIDIA vGPU. + */ +/***************************************************************************************************/ + +/** + * Retrieve the requested vGPU driver capability. + * + * Refer to the \a nvmlVgpuDriverCapability_t structure for the specific capabilities that can be queried. + * The return value in \a capResult should be treated as a boolean, with a non-zero value indicating that the capability + * is supported. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param capability Specifies the \a nvmlVgpuDriverCapability_t to be queried + * @param capResult A boolean for the queried capability indicating that feature is supported + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a capability is invalid, or \a capResult is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED the API is not supported in current state or \a devices not in vGPU mode + * - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlGetVgpuDriverCapabilities(nvmlVgpuDriverCapability_t capability, unsigned int *capResult); + +/** + * Retrieve the requested vGPU capability for GPU. + * + * Refer to the \a nvmlDeviceVgpuCapability_t structure for the specific capabilities that can be queried. + * The return value in \a capResult reports a non-zero value indicating that the capability + * is supported, and also reports the capability's data based on the queried capability. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param capability Specifies the \a nvmlDeviceVgpuCapability_t to be queried + * @param capResult Specifies that the queried capability is supported, and also returns capability's data + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a capability is invalid, or \a capResult is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED the API is not supported in current state or \a device not in vGPU mode + * - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuCapabilities(nvmlDevice_t device, nvmlDeviceVgpuCapability_t capability, unsigned int *capResult); + +/** + * Retrieve the supported vGPU types on a physical GPU (device). + * + * An array of supported vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer + * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount + * is used to return the number of vGPU types written to the buffer. + * + * If the supplied buffer is not large enough to accommodate the vGPU type array, the function returns + * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. + * To query the number of vGPU types supported for the GPU, call this function with *vgpuCount = 0. + * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are supported. + * + * @param device The identifier of the target device + * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types + * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL or \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSupportedVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); + +/** + * Retrieve the currently creatable vGPU types on a physical GPU (device). + * + * An array of creatable vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer + * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount + * is used to return the number of vGPU types written to the buffer. + * + * The creatable vGPU types for a device may differ over time, as there may be restrictions on what type of vGPU types + * can concurrently run on a device. For example, if only one vGPU type is allowed at a time on a device, then the creatable + * list will be restricted to whatever vGPU type is already running on the device. + * + * If the supplied buffer is not large enough to accommodate the vGPU type array, the function returns + * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. + * To query the number of vGPU types that can be created for the GPU, call this function with *vgpuCount = 0. + * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are creatable. + * + * @param device The identifier of the target device + * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types + * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCreatableVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); + +/** + * Retrieve the class of a vGPU type. It will not exceed 64 characters in length (including the NUL terminator). + * See \ref nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param vgpuTypeClass Pointer to string array to return class in + * @param size Size of string + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeClass is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetClass(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeClass, unsigned int *size); + +/** + * Retrieve the vGPU type name. + * + * The name is an alphanumeric string that denotes a particular vGPU, e.g. GRID M60-2Q. It will not + * exceed 64 characters in length (including the NUL terminator). See \ref + * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param vgpuTypeName Pointer to buffer to return name + * @param size Size of buffer + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a name is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetName(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeName, unsigned int *size); + +/** + * Retrieve the GPU Instance Profile ID for the given vGPU type ID. + * The API will return a valid GPU Instance Profile ID for the MIG capable vGPU types, else INVALID_GPU_INSTANCE_PROFILE_ID is + * returned. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param gpuInstanceProfileId GPU Instance Profile ID + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_NOT_SUPPORTED if \a device is not in vGPU Host virtualization mode + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a gpuInstanceProfileId is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetGpuInstanceProfileId(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *gpuInstanceProfileId); + +/** + * Retrieve the device ID of a vGPU type. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param deviceID Device ID and vendor ID of the device contained in single 32 bit value + * @param subsystemID Subsystem ID and subsystem vendor ID of the device contained in single 32 bit value + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a deviceId or \a subsystemID are NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetDeviceID(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *deviceID, unsigned long long *subsystemID); + +/** + * Retrieve the vGPU framebuffer size in bytes. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param fbSize Pointer to framebuffer size in bytes + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a fbSize is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetFramebufferSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbSize); + +/** + * Retrieve count of vGPU's supported display heads. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param numDisplayHeads Pointer to number of display heads + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a numDisplayHeads is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetNumDisplayHeads(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *numDisplayHeads); + +/** + * Retrieve vGPU display head's maximum supported resolution. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param displayIndex Zero-based index of display head + * @param xdim Pointer to maximum number of pixels in X dimension + * @param ydim Pointer to maximum number of pixels in Y dimension + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a xdim or \a ydim are NULL, or \a displayIndex + * is out of range. + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetResolution(nvmlVgpuTypeId_t vgpuTypeId, unsigned int displayIndex, unsigned int *xdim, unsigned int *ydim); + +/** + * Retrieve license requirements for a vGPU type + * + * The license type and version required to run the specified vGPU type is returned as an alphanumeric string, in the form + * ",", for example "GRID-Virtual-PC,2.0". If a vGPU is runnable with* more than one type of license, + * the licenses are delimited by a semicolon, for example "GRID-Virtual-PC,2.0;GRID-Virtual-WS,2.0;GRID-Virtual-WS-Ext,2.0". + * + * The total length of the returned string will not exceed 128 characters, including the NUL terminator. + * See \ref nvmlVgpuConstants::NVML_GRID_LICENSE_BUFFER_SIZE. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param vgpuTypeLicenseString Pointer to buffer to return license info + * @param size Size of \a vgpuTypeLicenseString buffer + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeLicenseString is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetLicense(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeLicenseString, unsigned int size); + +/** + * Retrieve the static frame rate limit value of the vGPU type + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param frameRateLimit Reference to return the frame rate limit value + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a frameRateLimit is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetFrameRateLimit(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *frameRateLimit); + +/** + * Retrieve the maximum number of vGPU instances creatable on a device for given vGPU type + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param vgpuTypeId Handle to vGPU type + * @param vgpuInstanceCount Pointer to get the max number of vGPU instances + * that can be created on a deicve for given vgpuTypeId + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid or is not supported on target device, + * or \a vgpuInstanceCount is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstances(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCount); + +/** + * Retrieve the maximum number of vGPU instances supported per VM for given vGPU type + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param vgpuInstanceCountPerVm Pointer to get the max number of vGPU instances supported per VM for given \a vgpuTypeId + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuInstanceCountPerVm is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstancesPerVm(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCountPerVm); + +/** + * Retrieve the BAR1 info for given vGPU type. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuTypeId Handle to vGPU type + * @param bar1Info Pointer to the vGPU type BAR1 information structure \a nvmlVgpuTypeBar1Info_t + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a bar1Info is NULL + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetBAR1Info(nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuTypeBar1Info_t *bar1Info); + +/** + * Retrieve the active vGPU instances on a device. + * + * An array of active vGPU instances is returned in the caller-supplied buffer pointed at by \a vgpuInstances. The + * array element count is passed in \a vgpuCount, and \a vgpuCount is used to return the number of vGPU instances + * written to the buffer. + * + * If the supplied buffer is not large enough to accommodate the vGPU instance array, the function returns + * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuInstance_t array required in \a vgpuCount. + * To query the number of active vGPU instances, call this function with *vgpuCount = 0. The code will return + * NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU Types are supported. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param device The identifier of the target device + * @param vgpuCount Pointer which passes in the array size as well as get + * back the number of types + * @param vgpuInstances Pointer to array in which to return list of vGPU instances + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a vgpuCount is NULL + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small + * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetActiveVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuInstance_t *vgpuInstances); + +/** + * Retrieve the VM ID associated with a vGPU instance. + * + * The VM ID is returned as a string, not exceeding 80 characters in length (including the NUL terminator). + * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. + * + * The format of the VM ID varies by platform, and is indicated by the type identifier returned in \a vmIdType. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param vmId Pointer to caller-supplied buffer to hold VM ID + * @param size Size of buffer in bytes + * @param vmIdType Pointer to hold VM ID type + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vmId or \a vmIdType is NULL, or \a vgpuInstance is 0 + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmID(nvmlVgpuInstance_t vgpuInstance, char *vmId, unsigned int size, nvmlVgpuVmIdType_t *vmIdType); + +/** + * Retrieve the UUID of a vGPU instance. + * + * The UUID is a globally unique identifier associated with the vGPU, and is returned as a 5-part hexadecimal string, + * not exceeding 80 characters in length (including the NULL terminator). + * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param uuid Pointer to caller-supplied buffer to hold vGPU UUID + * @param size Size of buffer in bytes + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a uuid is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetUUID(nvmlVgpuInstance_t vgpuInstance, char *uuid, unsigned int size); + +/** + * Retrieve the NVIDIA driver version installed in the VM associated with a vGPU. + * + * The version is returned as an alphanumeric string in the caller-supplied buffer \a version. The length of the version + * string will not exceed 80 characters in length (including the NUL terminator). + * See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. + * + * nvmlVgpuInstanceGetVmDriverVersion() may be called at any time for a vGPU instance. The guest VM driver version is + * returned as "Not Available" if no NVIDIA driver is installed in the VM, or the VM has not yet booted to the point where the + * NVIDIA driver is loaded and initialized. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param version Caller-supplied buffer to return driver version string + * @param length Size of \a version buffer + * + * @return + * - \ref NVML_SUCCESS if \a version has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0 + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmDriverVersion(nvmlVgpuInstance_t vgpuInstance, char* version, unsigned int length); + +/** + * Retrieve the framebuffer usage in bytes. + * + * Framebuffer usage is the amont of vGPU framebuffer memory that is currently in use by the VM. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuInstance The identifier of the target instance + * @param fbUsage Pointer to framebuffer usage in bytes + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a fbUsage is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFbUsage(nvmlVgpuInstance_t vgpuInstance, unsigned long long *fbUsage); + +/** + * @deprecated Use \ref nvmlVgpuInstanceGetLicenseInfo_v2. + * + * Retrieve the current licensing state of the vGPU instance. + * + * If the vGPU is currently licensed, \a licensed is set to 1, otherwise it is set to 0. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param licensed Reference to return the licensing status + * + * @return + * - \ref NVML_SUCCESS if \a licensed has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a licensed is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +DEPRECATED(13.0) nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseStatus(nvmlVgpuInstance_t vgpuInstance, unsigned int *licensed); + +/** + * Retrieve the vGPU type of a vGPU instance. + * + * Returns the vGPU type ID of vgpu assigned to the vGPU instance. + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param vgpuTypeId Reference to return the vgpuTypeId + * + * @return + * - \ref NVML_SUCCESS if \a vgpuTypeId has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a vgpuTypeId is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetType(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuTypeId_t *vgpuTypeId); + +/** + * Retrieve the frame rate limit set for the vGPU instance. + * + * Returns the value of the frame rate limit set for the vGPU instance + * + * For Kepler &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param frameRateLimit Reference to return the frame rate limit + * + * @return + * - \ref NVML_SUCCESS if \a frameRateLimit has been set + * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a frameRateLimit is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFrameRateLimit(nvmlVgpuInstance_t vgpuInstance, unsigned int *frameRateLimit); + +/** + * Retrieve the current ECC mode of vGPU instance. + * + * @param vgpuInstance The identifier of the target vGPU instance + * @param eccMode Reference in which to return the current ECC mode + * + * @return + * - \ref NVML_SUCCESS if the vgpuInstance's ECC mode has been successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEccMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *eccMode); + +/** + * Retrieve the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param encoderCapacity Reference to an unsigned int for the encoder capacity + * + * @return + * - \ref NVML_SUCCESS if \a encoderCapacity has been retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a encoderQueryType is invalid + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int *encoderCapacity); + +/** + * Set the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param encoderCapacity Unsigned int for the encoder capacity value + * + * @return + * - \ref NVML_SUCCESS if \a encoderCapacity has been set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a encoderCapacity is out of range of 0-100. + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceSetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int encoderCapacity); + +/** + * Retrieves the current encoder statistics of a vGPU Instance + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param sessionCount Reference to an unsigned int for count of active encoder sessions + * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions + * @param averageLatency Reference to an unsigned int for encode latency in microseconds + * + * @return + * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount , or \a averageFps or \a averageLatency is NULL + * or \a vgpuInstance is 0. + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderStats(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, + unsigned int *averageFps, unsigned int *averageLatency); + +/** + * Retrieves information about all active encoder sessions on a vGPU Instance. + * + * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The + * array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions + * written to the buffer. + * + * If the supplied buffer is not large enough to accommodate the active session array, the function returns + * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. + * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return + * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param sessionCount Reference to caller supplied array size, and returns + * the number of sessions. + * @param sessionInfo Reference to caller supplied array in which the list + * of session information us returned. + * + * @return + * - \ref NVML_SUCCESS if \a sessionInfo is fetched + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is + returned in \a sessionCount + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL, or \a vgpuInstance is 0. + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfo); + +/** +* Retrieves the active frame buffer capture sessions statistics of a vGPU Instance +* +* For Maxwell &tm; or newer fully supported devices. +* +* @param vgpuInstance Identifier of the target vGPU instance +* @param fbcStats Reference to nvmlFBCStats_t structure containing NvFBC stats +* +* @return +* - \ref NVML_SUCCESS if \a fbcStats is fetched +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a fbcStats is NULL +* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCStats(nvmlVgpuInstance_t vgpuInstance, nvmlFBCStats_t *fbcStats); + +/** +* Retrieves information about active frame buffer capture sessions on a vGPU Instance. +* +* An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The +* array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions +* written to the buffer. +* +* If the supplied buffer is not large enough to accommodate the active session array, the function returns +* NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \a sessionCount. +* To query the number of active FBC sessions, call this function with *sessionCount = 0. The code will return +* NVML_SUCCESS with number of active FBC sessions updated in *sessionCount. +* +* For Maxwell &tm; or newer fully supported devices. +* +* @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \a sessionInfo may +* be zero if there are no new frames captured since the session started. +* +* @param vgpuInstance Identifier of the target vGPU instance +* @param sessionCount Reference to caller supplied array size, and returns the number of sessions. +* @param sessionInfo Reference in which to return the session information +* +* @return +* - \ref NVML_SUCCESS if \a sessionInfo is fetched +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a sessionCount is NULL. +* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system +* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo); + +/** +* Retrieve the GPU Instance ID for the given vGPU Instance. +* The API will return a valid GPU Instance ID for MIG backed vGPU Instance, else INVALID_GPU_INSTANCE_ID is returned. +* +* For Kepler &tm; or newer fully supported devices. +* +* @param vgpuInstance Identifier of the target vGPU instance +* @param gpuInstanceId GPU Instance ID +* +* @return +* - \ref NVML_SUCCESS successful completion +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a gpuInstanceId is NULL. +* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetGpuInstanceId(nvmlVgpuInstance_t vgpuInstance, unsigned int *gpuInstanceId); + +/** +* Retrieves the PCI Id of the given vGPU Instance i.e. the PCI Id of the GPU as seen inside the VM. +* +* The vGPU PCI id is returned as "00000000:00:00.0" if NVIDIA driver is not installed on the vGPU instance. +* +* @param vgpuInstance Identifier of the target vGPU instance +* @param vgpuPciId Caller-supplied buffer to return vGPU PCI Id string +* @param length Size of the vgpuPciId buffer +* +* @return +* - \ref NVML_SUCCESS if vGPU PCI Id is sucessfully retrieved +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a vgpuPciId is NULL +* - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system +* - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running on the vGPU instance +* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small, \a length is set to required length +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetGpuPciId(nvmlVgpuInstance_t vgpuInstance, char *vgpuPciId, unsigned int *length); + +/** +* Retrieve the requested capability for a given vGPU type. Refer to the \a nvmlVgpuCapability_t structure +* for the specific capabilities that can be queried. The return value in \a capResult should be treated as +* a boolean, with a non-zero value indicating that the capability is supported. +* +* For Maxwell &tm; or newer fully supported devices. +* +* @param vgpuTypeId Handle to vGPU type +* @param capability Specifies the \a nvmlVgpuCapability_t to be queried +* @param capResult A boolean for the queried capability indicating that feature is supported +* +* @return +* - \ref NVML_SUCCESS successful completion +* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized +* - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a capability is invalid, or \a capResult is NULL +* - \ref NVML_ERROR_UNKNOWN on any unexpected error +*/ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetCapabilities(nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuCapability_t capability, unsigned int *capResult); + +/** + * Retrieve the MDEV UUID of a vGPU instance. + * + * The MDEV UUID is a globally unique identifier of the mdev device assigned to the VM, and is returned as a 5-part hexadecimal string, + * not exceeding 80 characters in length (including the NULL terminator). + * MDEV UUID is displayed only on KVM platform. + * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param mdevUuid Pointer to caller-supplied buffer to hold MDEV UUID + * @param size Size of buffer in bytes + * + * @return + * - \ref NVML_SUCCESS successful completion + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_NOT_SUPPORTED on any hypervisor other than KVM + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mdevUuid is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetMdevUUID(nvmlVgpuInstance_t vgpuInstance, char *mdevUuid, unsigned int size); + +/** + * Query the currently creatable vGPU types on a specific GPU Instance. + * + * The function returns an array of vGPU types that can be created for a specified GPU instance. This array is stored + * in a caller-supplied buffer, with the buffer's element count passed through \a pVgpus->vgpuCount. The number of + * vGPU types written to the buffer is indicated by \a pVgpus->vgpuCount. If the buffer is too small to hold the vGPU + * type array, the function returns NVML_ERROR_INSUFFICIENT_SIZE and updates \a pVgpus->vgpuCount with the required + * element count. + * + * To determine the creatable vGPUs for a GPU Instance, invoke this function with \a pVgpus->vgpuCount set to 0 and + * \a pVgpus->vgpuTypeIds as NULL. This will result in NVML_ERROR_INSUFFICIENT_SIZE being returned, along with the + * count value in \a pVgpus->vgpuCount. + * + * The creatable vGPU types may differ over time, as there may be restrictions on what type of vGPUs can concurrently + * run on the device. + * + * @param gpuInstance The GPU instance handle + * @param pVgpus Pointer to the caller-provided structure of nvmlVgpuTypeIdInfo_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, or \a pVgpus is NULL + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU + * - \ref NVML_ERROR_INSUFFICIENT_SIZE If \a pVgpus->vgpuTypeIds buffer is small + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pVgpus is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetCreatableVgpus(nvmlGpuInstance_t gpuInstance, nvmlVgpuTypeIdInfo_t *pVgpus); + +/** + * Retrieve the maximum number of vGPU instances per GPU instance for given vGPU type + * + * @param pMaxInstance Pointer to the caller-provided structure of nvmlVgpuTypeMaxInstance_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a pMaxInstance is NULL or \a pMaxInstance->vgpuTypeId is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU or non-MIG vGPU type + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pMaxInstance is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstancesPerGpuInstance(nvmlVgpuTypeMaxInstance_t *pMaxInstance); + +/** + * Retrieve the active vGPU instances within a GPU instance. + * + * An array of active vGPU instances is returned in the caller-supplied buffer pointed + * at by \a pVgpuInstanceInfo->vgpuInstances. The array element count is passed in + * \a pVgpuInstanceInfo->vgpuCount, and \a pVgpuInstanceInfo->vgpuCount is used to return + * the number of vGPU instances written to the buffer. + * + * If the supplied buffer is not large enough to accommodate the vGPU instance array, + * the function returns NVML_ERROR_INSUFFICIENT_SIZE, with the element count of + * nvmlVgpuInstance_t array required in \a pVgpuInstanceInfo->vgpuCount. To query the + * number of active vGPU instances, call this function with pVgpuInstanceInfo->vgpuCount = 0 + * and pVgpuInstanceInfo->vgpuTypeIds = NULL. The code will return NVML_ERROR_INSUFFICIENT_SIZE, + * or NVML_SUCCESS if no vGPU Types are active. + * + * @param gpuInstance The GPU instance handle + * @param pVgpuInstanceInfo Pointer to the vGPU instance information structure \a nvmlActiveVgpuInstanceInfo_t + * + * @return + * - \ref NVML_SUCCESS Successful completion + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, or \a pVgpuInstanceInfo is NULL + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a pVgpuInstanceInfo->vgpuTypeIds buffer is too small, + * array element count is returned in \a pVgpuInstanceInfo->vgpuCount + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pVgpuInstanceInfo is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetActiveVgpus(nvmlGpuInstance_t gpuInstance, nvmlActiveVgpuInstanceInfo_t *pVgpuInstanceInfo); + +/** + * Set vGPU scheduler state for the given GPU instance + * + * For Blackwell &tm GB20x; or newer fully supported devices. + * + * Scheduler state and params will be allowed to set only when no VM is running within the GPU instance. + * In \a nvmlVgpuSchedulerState_t, IFF enableARRMode is enabled then provide the avgFactor and frequency + * as input. If enableARRMode is disabled then provide timeslice as input. + * + * The scheduler state change won't persist across module load/unload and GPU Instance creation/deletion. + * + * @param gpuInstance The GPU instance handle + * @param pScheduler Pointer to the caller-provided structure of nvmlVgpuSchedulerState_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, or \a pScheduler is NULL + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_RESET_REQUIRED If setting the state failed with fatal error, reboot is required + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU or if any vGPU instance exists + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pScheduler is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceSetVgpuSchedulerState(nvmlGpuInstance_t gpuInstance, nvmlVgpuSchedulerState_t *pScheduler); + +/** + * Returns the vGPU scheduler state for the given GPU instance. + * The information returned in \a nvmlVgpuSchedulerStateInfo_t is not relevant if the BEST EFFORT policy is set. + * + * For Blackwell &tm GB20x; or newer fully supported devices. + * + * @param gpuInstance The GPU instance handle + * @param pSchedulerStateInfo Reference in which \a pSchedulerStateInfo is returned + * + * @return + * - \ref NVML_SUCCESS vGPU scheduler state is successfully obtained + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, or \a pSchedulerStateInfo is NULL + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pSchedulerStateInfo is invalid + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetVgpuSchedulerState(nvmlGpuInstance_t gpuInstance, nvmlVgpuSchedulerStateInfo_t *pSchedulerStateInfo); + +/** + * Returns the vGPU scheduler logs for the given GPU instance. + * \a pSchedulerLogInfo points to a caller-allocated structure to contain the logs. The number of elements returned will + * never exceed \a NVML_SCHEDULER_SW_MAX_LOG_ENTRIES. + * + * To get the entire logs, call the function atleast 5 times a second. + * + * For Blackwell &tm GB20x; or newer fully supported devices. + * + * @param gpuInstance The GPU instance handle + * @param pSchedulerLogInfo Reference in which \a pSchedulerLogInfo is written + * + * @return + * - \ref NVML_SUCCESS vGPU scheduler logs are successfully obtained + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, or \a pSchedulerLogInfo is NULL + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pSchedulerLogInfo is invalid + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetVgpuSchedulerLog(nvmlGpuInstance_t gpuInstance, nvmlVgpuSchedulerLogInfo_t *pSchedulerLogInfo); + +/** + * Query the creatable vGPU placement ID of the vGPU type within a GPU instance. + * + * For Blackwell &tm GB20x; or newer fully supported devices. + * + * An array of creatable vGPU placement IDs for the vGPU type ID indicated by \a pCreatablePlacementInfo->vgpuTypeId + * is returned in the caller-supplied buffer of \a pCreatablePlacementInfo->placementIds. Memory needed for the + * placementIds array should be allocated based on maximum instances of a vGPU type per GPU instance which can be + * queried via \ref nvmlVgpuTypeGetMaxInstancesPerGpuInstance(). + * If the provided count by the caller is insufficient, the function will return NVML_ERROR_INSUFFICIENT_SIZE along with + * the number of required entries in \a pCreatablePlacementInfo->count. The caller should then reallocate a buffer with the size + * of pCreatablePlacementInfo->count * sizeof(pCreatablePlacementInfo->placementIds) and invoke the function again. + * The creatable vGPU placement IDs may differ over time, as there may be restrictions on what type of vGPU the + * vGPU instance is running. + * + * @param gpuInstance The GPU instance handle + * @param pCreatablePlacementInfo Pointer to the list of vGPU creatable placement structure \a nvmlVgpuCreatablePlacementInfo_t + * + * @return + * - \ref NVML_SUCCESS Successful completion + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, or \a pCreatablePlacementInfo is NULL + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_INSUFFICIENT_SIZE If the buffer is small, element count is returned in \a pCreatablePlacementInfo->count + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pCreatablePlacementInfo is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU or vGPU heterogeneous mode is not enabled + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetVgpuTypeCreatablePlacements(nvmlGpuInstance_t gpuInstance, nvmlVgpuCreatablePlacementInfo_t *pCreatablePlacementInfo); + +/** + * Get the vGPU heterogeneous mode for the GPU instance. + * + * When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes. + * + * On successful return, the function returns \a pHeterogeneousMode->mode with the current vGPU heterogeneous mode. + * \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should + * set the correct version number to retrieve the vGPU heterogeneous mode. + * \a pHeterogeneousMode->mode can either be \ref NVML_FEATURE_ENABLED or \ref NVML_FEATURE_DISABLED. + * + * For Blackwell &tm GB20x; or newer fully supported devices. + * + * @param gpuInstance The GPU instance handle + * @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, or \a pHeterogeneousMode is NULL + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU or not in MIG mode + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetVgpuHeterogeneousMode(nvmlGpuInstance_t gpuInstance, nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode); + +/** + * Enable or disable vGPU heterogeneous mode for the GPU instance. + * + * When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes. + * + * API would return an appropriate error code upon unsuccessful activation. For example, the heterogeneous mode + * set will fail with error \ref NVML_ERROR_IN_USE if any vGPU instance is active within the GPU instance. + * The caller of this API is expected to shutdown the vGPU VMs and retry setting the \a mode. + * On successful return, the function updates the vGPU heterogeneous mode with the user provided \a pHeterogeneousMode->mode. + * \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should + * set the correct version number to set the vGPU heterogeneous mode. + * + * @param gpuInstance The GPU instance handle + * @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is NULL or invalid, + * or \a pHeterogeneousMode is NULL or \a pHeterogeneousMode->mode is invalid + * or GPU Instance Id is invalid + * - \ref NVML_ERROR_IN_USE If the \a gpuInstance is in use + * - \ref NVML_ERROR_NOT_SUPPORTED If not on a vGPU host or an unsupported GPU + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceSetVgpuHeterogeneousMode(nvmlGpuInstance_t gpuInstance, const nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlVgpuMigration vGPU Migration + * This chapter describes operations that are associated with vGPU Migration. + * @{ + */ +/***************************************************************************************************/ + +/** + * Structure representing range of vGPU versions. + */ +typedef struct nvmlVgpuVersion_st +{ + unsigned int minVersion; //!< Minimum vGPU version. + unsigned int maxVersion; //!< Maximum vGPU version. +} nvmlVgpuVersion_t; + +/** + * vGPU metadata structure. + */ +typedef struct nvmlVgpuMetadata_st +{ + unsigned int version; //!< Current version of the structure + unsigned int revision; //!< Current revision of the structure + nvmlVgpuGuestInfoState_t guestInfoState; //!< Current state of Guest-dependent fields + char guestDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Version of driver installed in guest + char hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Version of driver installed in host + unsigned int reserved[6]; //!< Reserved for internal use + unsigned int vgpuVirtualizationCaps; //!< vGPU virtualization capabilities bitfield + unsigned int guestVgpuVersion; //!< vGPU version of guest driver + unsigned int opaqueDataSize; //!< Size of opaque data field in bytes + char opaqueData[4]; //!< Opaque data +} nvmlVgpuMetadata_t; + +/** + * Physical GPU metadata structure + */ +typedef struct nvmlVgpuPgpuMetadata_st +{ + unsigned int version; //!< Current version of the structure + unsigned int revision; //!< Current revision of the structure + char hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Host driver version + unsigned int pgpuVirtualizationCaps; //!< Pgpu virtualization capabilities bitfield + unsigned int reserved[5]; //!< Reserved for internal use + nvmlVgpuVersion_t hostSupportedVgpuRange; //!< vGPU version range supported by host driver + unsigned int opaqueDataSize; //!< Size of opaque data field in bytes + char opaqueData[4]; //!< Opaque data +} nvmlVgpuPgpuMetadata_t; + +/** + * vGPU VM compatibility codes + */ +typedef enum nvmlVgpuVmCompatibility_enum +{ + NVML_VGPU_VM_COMPATIBILITY_NONE = 0x0, //!< vGPU is not runnable + NVML_VGPU_VM_COMPATIBILITY_COLD = 0x1, //!< vGPU is runnable from a cold / powered-off state (ACPI S5) + NVML_VGPU_VM_COMPATIBILITY_HIBERNATE = 0x2, //!< vGPU is runnable from a hibernated state (ACPI S4) + NVML_VGPU_VM_COMPATIBILITY_SLEEP = 0x4, //!< vGPU is runnable from a sleeped state (ACPI S3) + NVML_VGPU_VM_COMPATIBILITY_LIVE = 0x8 //!< vGPU is runnable from a live/paused (ACPI S0) +} nvmlVgpuVmCompatibility_t; + +/** + * vGPU-pGPU compatibility limit codes + */ +typedef enum nvmlVgpuPgpuCompatibilityLimitCode_enum +{ + NVML_VGPU_COMPATIBILITY_LIMIT_NONE = 0x0, //!< Compatibility is not limited. + NVML_VGPU_COMPATIBILITY_LIMIT_HOST_DRIVER = 0x1, //!< ompatibility is limited by host driver version. + NVML_VGPU_COMPATIBILITY_LIMIT_GUEST_DRIVER = 0x2, //!< Compatibility is limited by guest driver version. + NVML_VGPU_COMPATIBILITY_LIMIT_GPU = 0x4, //!< Compatibility is limited by GPU hardware. + NVML_VGPU_COMPATIBILITY_LIMIT_OTHER = 0x80000000 //!< Compatibility is limited by an undefined factor. +} nvmlVgpuPgpuCompatibilityLimitCode_t; + +/** + * vGPU-pGPU compatibility structure + */ +typedef struct nvmlVgpuPgpuCompatibility_st +{ + nvmlVgpuVmCompatibility_t vgpuVmCompatibility; //!< Compatibility of vGPU VM. See \ref nvmlVgpuVmCompatibility_t + nvmlVgpuPgpuCompatibilityLimitCode_t compatibilityLimitCode; //!< Limiting factor for vGPU-pGPU compatibility. See \ref nvmlVgpuPgpuCompatibilityLimitCode_t +} nvmlVgpuPgpuCompatibility_t; + +/** + * Returns vGPU metadata structure for a running vGPU. The structure contains information about the vGPU and its associated VM + * such as the currently installed NVIDIA guest driver version, together with host driver version and an opaque data section + * containing internal state. + * + * nvmlVgpuInstanceGetMetadata() may be called at any time for a vGPU instance. Some fields in the returned structure are + * dependent on information obtained from the guest VM, which may not yet have reached a state where that information + * is available. The current state of these dependent fields is reflected in the info structure's \ref nvmlVgpuGuestInfoState_t field. + * + * The VMM may choose to read and save the vGPU's VM info as persistent metadata associated with the VM, and provide + * it to Virtual GPU Manager when creating a vGPU for subsequent instances of the VM. + * + * The caller passes in a buffer via \a vgpuMetadata, with the size of the buffer in \a bufferSize. If the vGPU Metadata structure + * is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed + * in \a bufferSize. + * + * @param vgpuInstance vGPU instance handle + * @param vgpuMetadata Pointer to caller-supplied buffer into which vGPU metadata is written + * @param bufferSize Size of vgpuMetadata buffer + * + * @return + * - \ref NVML_SUCCESS vGPU metadata structure was successfully returned + * - \ref NVML_ERROR_INSUFFICIENT_SIZE vgpuMetadata buffer is too small, required size is returned in \a bufferSize + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a vgpuInstance is 0; if \a vgpuMetadata is NULL and the value of \a bufferSize is not 0. + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetMetadata(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuMetadata_t *vgpuMetadata, unsigned int *bufferSize); + +/** + * Returns a vGPU metadata structure for the physical GPU indicated by \a device. The structure contains information about + * the GPU and the currently installed NVIDIA host driver version that's controlling it, together with an opaque data section + * containing internal state. + * + * The caller passes in a buffer via \a pgpuMetadata, with the size of the buffer in \a bufferSize. If the \a pgpuMetadata + * structure is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed + * in \a bufferSize. + * + * @param device The identifier of the target device + * @param pgpuMetadata Pointer to caller-supplied buffer into which \a pgpuMetadata is written + * @param bufferSize Pointer to size of \a pgpuMetadata buffer + * + * @return + * - \ref NVML_SUCCESS GPU metadata structure was successfully returned + * - \ref NVML_ERROR_INSUFFICIENT_SIZE pgpuMetadata buffer is too small, required size is returned in \a bufferSize + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a device is invalid; if \a pgpuMetadata is NULL and the value of \a bufferSize is not 0. + * - \ref NVML_ERROR_NOT_SUPPORTED vGPU is not supported by the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuMetadata(nvmlDevice_t device, nvmlVgpuPgpuMetadata_t *pgpuMetadata, unsigned int *bufferSize); + +/** + * Takes a vGPU instance metadata structure read from \ref nvmlVgpuInstanceGetMetadata(), and a vGPU metadata structure for a + * physical GPU read from \ref nvmlDeviceGetVgpuMetadata(), and returns compatibility information of the vGPU instance and the + * physical GPU. + * + * The caller passes in a buffer via \a compatibilityInfo, into which a compatibility information structure is written. The + * structure defines the states in which the vGPU / VM may be booted on the physical GPU. If the vGPU / VM compatibility + * with the physical GPU is limited, a limit code indicates the factor limiting compatability. + * (see \ref nvmlVgpuPgpuCompatibilityLimitCode_t for details). + * + * Note: vGPU compatibility does not take into account dynamic capacity conditions that may limit a system's ability to + * boot a given vGPU or associated VM. + * + * @param vgpuMetadata Pointer to caller-supplied vGPU metadata structure + * @param pgpuMetadata Pointer to caller-supplied GPU metadata structure + * @param compatibilityInfo Pointer to caller-supplied buffer to hold compatibility info + * + * @return + * - \ref NVML_SUCCESS vGPU metadata structure was successfully returned + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuMetadata or \a pgpuMetadata or \a bufferSize are NULL + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlGetVgpuCompatibility(nvmlVgpuMetadata_t *vgpuMetadata, nvmlVgpuPgpuMetadata_t *pgpuMetadata, nvmlVgpuPgpuCompatibility_t *compatibilityInfo); + +/** + * Returns the properties of the physical GPU indicated by the device in an ascii-encoded string format. + * + * The caller passes in a buffer via \a pgpuMetadata, with the size of the buffer in \a bufferSize. If the + * string is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed + * in \a bufferSize. + * + * @param device The identifier of the target device + * @param pgpuMetadata Pointer to caller-supplied buffer into which \a pgpuMetadata is written + * @param bufferSize Pointer to size of \a pgpuMetadata buffer + * + * @return + * - \ref NVML_SUCCESS GPU metadata structure was successfully returned + * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a pgpuMetadata buffer is too small, required size is returned in \a bufferSize + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a bufferSize is NULL or \a device is invalid; if \a pgpuMetadata is NULL and the value of \a bufferSize is not 0. + * - \ref NVML_ERROR_NOT_SUPPORTED If vGPU is not supported by the system + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPgpuMetadataString(nvmlDevice_t device, char *pgpuMetadata, unsigned int *bufferSize); + +/** + * Returns the vGPU Software scheduler logs. + * \a pSchedulerLog points to a caller-allocated structure to contain the logs. The number of elements returned will + * never exceed \a NVML_SCHEDULER_SW_MAX_LOG_ENTRIES. + * + * To get the entire logs, call the function atleast 5 times a second. + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target \a device + * @param pSchedulerLog Reference in which \a pSchedulerLog is written + * + * @return + * - \ref NVML_SUCCESS vGPU scheduler logs were successfully obtained + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a pSchedulerLog is NULL or \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device not in vGPU host mode + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuSchedulerLog(nvmlDevice_t device, nvmlVgpuSchedulerLog_t *pSchedulerLog); + +/** + * Returns the vGPU scheduler state. + * The information returned in \a nvmlVgpuSchedulerGetState_t is not relevant if the BEST EFFORT policy is set. + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target \a device + * @param pSchedulerState Reference in which \a pSchedulerState is returned + * + * @return + * - \ref NVML_SUCCESS vGPU scheduler state is successfully obtained + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a pSchedulerState is NULL or \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device not in vGPU host mode + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuSchedulerState(nvmlDevice_t device, nvmlVgpuSchedulerGetState_t *pSchedulerState); + +/** + * Returns the vGPU scheduler capabilities. + * The list of supported vGPU schedulers returned in \a nvmlVgpuSchedulerCapabilities_t is from + * the NVML_VGPU_SCHEDULER_POLICY_*. This list enumerates the supported scheduler policies + * if the engine is Graphics type. + * The other values in \a nvmlVgpuSchedulerCapabilities_t are also applicable if the engine is + * Graphics type. For other engine types, it is BEST EFFORT policy. + * If ARR is supported and enabled, scheduling frequency and averaging factor are applicable + * else timeSlice is applicable. + * + * For Pascal &tm; or newer fully supported devices. + * + * @param device The identifier of the target \a device + * @param pCapabilities Reference in which \a pCapabilities is written + * + * @return + * - \ref NVML_SUCCESS vGPU scheduler capabilities were successfully obtained + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a pCapabilities is NULL or \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state or \a device not in vGPU host mode + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuSchedulerCapabilities(nvmlDevice_t device, nvmlVgpuSchedulerCapabilities_t *pCapabilities); + +/** + * Sets the vGPU scheduler state. + * + * For Pascal &tm; or newer fully supported devices. + * + * The scheduler state change won't persist across module load/unload. + * Scheduler state and params will be allowed to set only when no VM is running. + * In \a nvmlVgpuSchedulerSetState_t, IFF enableARRMode is enabled then + * provide avgFactorForARR and frequency as input. If enableARRMode is disabled + * then provide timeslice as input. + * + * @param device The identifier of the target \a device + * @param pSchedulerState vGPU \a pSchedulerState to set + * + * @return + * - \ref NVML_SUCCESS vGPU scheduler state has been successfully set + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a pSchedulerState is NULL or \a device is invalid + * - \ref NVML_ERROR_RESET_REQUIRED If setting \a pSchedulerState failed with fatal error, + * reboot is required to overcome from this error. + * - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device not in vGPU host mode + * or if any vGPU instance currently exists on the \a device + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceSetVgpuSchedulerState(nvmlDevice_t device, nvmlVgpuSchedulerSetState_t *pSchedulerState); + +/* + * Virtual GPU (vGPU) version + * + * The NVIDIA vGPU Manager and the guest drivers are tagged with a range of supported vGPU versions. This determines the range of NVIDIA guest driver versions that + * are compatible for vGPU feature support with a given NVIDIA vGPU Manager. For vGPU feature support, the range of supported versions for the NVIDIA vGPU Manager + * and the guest driver must overlap. Otherwise, the guest driver fails to load in the VM. + * + * When the NVIDIA guest driver loads, either when the VM is booted or when the driver is installed or upgraded, a negotiation occurs between the guest driver + * and the NVIDIA vGPU Manager to select the highest mutually compatible vGPU version. The negotiated vGPU version stays the same across VM migration. + */ + +/** + * Query the ranges of supported vGPU versions. + * + * This function gets the linear range of supported vGPU versions that is preset for the NVIDIA vGPU Manager and the range set by an administrator. + * If the preset range has not been overridden by \ref nvmlSetVgpuVersion, both ranges are the same. + * + * The caller passes pointers to the following \ref nvmlVgpuVersion_t structures, into which the NVIDIA vGPU Manager writes the ranges: + * 1. \a supported structure that represents the preset range of vGPU versions supported by the NVIDIA vGPU Manager. + * 2. \a current structure that represents the range of supported vGPU versions set by an administrator. By default, this range is the same as the preset range. + * + * @param supported Pointer to the structure in which the preset range of vGPU versions supported by the NVIDIA vGPU Manager is written + * @param current Pointer to the structure in which the range of supported vGPU versions set by an administrator is written + * + * @return + * - \ref NVML_SUCCESS The vGPU version range structures were successfully obtained. + * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported. + * - \ref NVML_ERROR_INVALID_ARGUMENT The \a supported parameter or the \a current parameter is NULL. + * - \ref NVML_ERROR_UNKNOWN An error occurred while the data was being fetched. + */ +nvmlReturn_t DECLDIR nvmlGetVgpuVersion(nvmlVgpuVersion_t *supported, nvmlVgpuVersion_t *current); + +/** + * Override the preset range of vGPU versions supported by the NVIDIA vGPU Manager with a range set by an administrator. + * + * This function configures the NVIDIA vGPU Manager with a range of supported vGPU versions set by an administrator. This range must be a subset of the + * preset range that the NVIDIA vGPU Manager supports. The custom range set by an administrator takes precedence over the preset range and is advertised to + * the guest VM for negotiating the vGPU version. See \ref nvmlGetVgpuVersion for details of how to query the preset range of versions supported. + * + * This function takes a pointer to vGPU version range structure \ref nvmlVgpuVersion_t as input to override the preset vGPU version range that the NVIDIA vGPU Manager supports. + * + * After host system reboot or driver reload, the range of supported versions reverts to the range that is preset for the NVIDIA vGPU Manager. + * + * @note 1. The range set by the administrator must be a subset of the preset range that the NVIDIA vGPU Manager supports. Otherwise, an error is returned. + * 2. If the range of supported guest driver versions does not overlap the range set by the administrator, the guest driver fails to load. + * 3. If the range of supported guest driver versions overlaps the range set by the administrator, the guest driver will load with a negotiated + * vGPU version that is the maximum value in the overlapping range. + * 4. No VMs must be running on the host when this function is called. If a VM is running on the host, the call to this function fails. + * + * @param vgpuVersion Pointer to a caller-supplied range of supported vGPU versions. + * + * @return + * - \ref NVML_SUCCESS The preset range of supported vGPU versions was successfully overridden. + * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported. + * - \ref NVML_ERROR_IN_USE The range was not overridden because a VM is running on the host. + * - \ref NVML_ERROR_INVALID_ARGUMENT The \a vgpuVersion parameter specifies a range that is outside the range supported by the NVIDIA vGPU Manager or if \a vgpuVersion is NULL. + */ +nvmlReturn_t DECLDIR nvmlSetVgpuVersion(nvmlVgpuVersion_t *vgpuVersion); + +/** @} */ // @defgroup nvmlVgpuMigration vGPU Migration + +/***************************************************************************************************/ +/** @defgroup nvmlUtil vGPU Utilization and Accounting + * This chapter describes operations that are associated with vGPU Utilization and Accounting. + * @{ + */ +/***************************************************************************************************/ + +/** + * Retrieves current utilization for vGPUs on a physical GPU (device). + * + * For Kepler &tm; or newer fully supported devices. + * + * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for vGPU instances running + * on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer + * pointed at by \a utilizationSamples. One utilization sample structure is returned per vGPU instance, and includes the + * CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values + * in nvmlValue_t unions. The function sets the caller-supplied \a sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to + * indicate the returned value type. + * + * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with + * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance + * count in \a vgpuInstanceSamplesCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate + * a buffer of size vgpuInstanceSamplesCount * sizeof(nvmlVgpuInstanceUtilizationSample_t). Invoke the function again with + * the allocated buffer passed in \a utilizationSamples, and \a vgpuInstanceSamplesCount set to the number of entries the + * buffer is sized for. + * + * On successful return, the function updates \a vgpuInstanceSampleCount with the number of vGPU utilization sample + * structures that were actually written. This may differ from a previously read value as vGPU instances are created or + * destroyed. + * + * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 + * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp + * to a timeStamp retrieved from a previous query to read utilization since the previous query. + * + * @param device The identifier for the target device + * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. + * @param sampleValType Pointer to caller-supplied buffer to hold the type of returned sample values + * @param vgpuInstanceSamplesCount Pointer to caller-supplied array size, and returns number of vGPU instances + * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU utilization samples are returned + + * @return + * - \ref NVML_SUCCESS if utilization samples are successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuInstanceSamplesCount or \a sampleValType is + * NULL, or a sample count of 0 is passed with a non-NULL \a utilizationSamples + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuInstanceSamplesCount is too small to return samples for all + * vGPU instances currently executing on the device + * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, + nvmlValueType_t *sampleValType, unsigned int *vgpuInstanceSamplesCount, + nvmlVgpuInstanceUtilizationSample_t *utilizationSamples); + +/** + * Retrieves recent utilization for vGPU instances running on a physical GPU (device). + * + * For Kepler &tm; or newer fully supported devices. + * + * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, video decoder, jpeg decoder, and OFA for vGPU + * instances running on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied + * buffer pointed at by \a vgpuUtilInfo->vgpuUtilArray. One utilization sample structure is returned per vGPU instance, and includes the + * CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values + * in nvmlValue_t unions. The function sets the caller-supplied \a vgpuUtilInfo->sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to + * indicate the returned value type. + * + * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with + * \a vgpuUtilInfo->vgpuUtilArray set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance + * count in \a vgpuUtilInfo->vgpuInstanceCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate + * a buffer of size vgpuUtilInfo->vgpuInstanceCount * sizeof(nvmlVgpuInstanceUtilizationInfo_t). Invoke the function again with + * the allocated buffer passed in \a vgpuUtilInfo->vgpuUtilArray, and \a vgpuUtilInfo->vgpuInstanceCount set to the number of entries the + * buffer is sized for. + * + * On successful return, the function updates \a vgpuUtilInfo->vgpuInstanceCount with the number of vGPU utilization sample + * structures that were actually written. This may differ from a previously read value as vGPU instances are created or + * destroyed. + * + * \a vgpuUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 + * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set \a vgpuUtilInfo->lastSeenTimeStamp + * to a timeStamp retrieved from a previous query to read utilization since the previous query. + * + * @param device The identifier for the target device + * @param vgpuUtilInfo Pointer to the caller-provided structure of nvmlVgpuInstancesUtilizationInfo_t + + * @return + * - \ref NVML_SUCCESS If utilization samples are successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, \a vgpuUtilInfo is NULL, or \a vgpuUtilInfo->vgpuInstanceCount is 0 + * - \ref NVML_ERROR_NOT_SUPPORTED If vGPU is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST If the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a vgpuUtilInfo is invalid + * - \ref NVML_ERROR_INSUFFICIENT_SIZE If \a vgpuUtilInfo->vgpuUtilArray is NULL, or the buffer size of vgpuUtilInfo->vgpuInstanceCount is too small. + * The caller should check the current vGPU instance count from the returned vgpuUtilInfo->vgpuInstanceCount, and call + * the function again with a buffer of size vgpuUtilInfo->vgpuInstanceCount * sizeof(nvmlVgpuInstanceUtilizationInfo_t) + * - \ref NVML_ERROR_NOT_FOUND If sample entries are not found + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuInstancesUtilizationInfo(nvmlDevice_t device, + nvmlVgpuInstancesUtilizationInfo_t *vgpuUtilInfo); + +/** + * Retrieves current utilization for processes running on vGPUs on a physical GPU (device). + * + * For Maxwell &tm; or newer fully supported devices. + * + * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running on + * vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the + * caller-supplied buffer pointed at by \a utilizationSamples. One utilization sample structure is returned per process running + * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which + * the samples were recorded. Individual utilization values are returned as "unsigned int" values. + * + * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with + * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance + * count in \a vgpuProcessSamplesCount. The caller should allocate a buffer of size + * vgpuProcessSamplesCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with + * the allocated buffer passed in \a utilizationSamples, and \a vgpuProcessSamplesCount set to the number of entries the + * buffer is sized for. + * + * On successful return, the function updates \a vgpuSubProcessSampleCount with the number of vGPU sub process utilization sample + * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active + * in any given sample period. + * + * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 + * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp + * to a timeStamp retrieved from a previous query to read utilization since the previous query. + * + * @param device The identifier for the target device + * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. + * @param vgpuProcessSamplesCount Pointer to caller-supplied array size, and returns number of processes running on vGPU instances + * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU sub process utilization samples are returned + + * @return + * - \ref NVML_SUCCESS if utilization samples are successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuProcessSamplesCount or a sample count of 0 is + * passed with a non-NULL \a utilizationSamples + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuProcessSamplesCount is too small to return samples for all + * vGPU instances currently executing on the device + * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, + unsigned int *vgpuProcessSamplesCount, + nvmlVgpuProcessUtilizationSample_t *utilizationSamples); + +/** + * Retrieves recent utilization for processes running on vGPU instances on a physical GPU (device). + * + * For Maxwell &tm; or newer fully supported devices. + * + * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, video decoder, jpeg decoder, and OFA for processes running + * on vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied + * buffer pointed at by \a vgpuProcUtilInfo->vgpuProcUtilArray. One utilization sample structure is returned per process running + * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which + * the samples were recorded. Individual utilization values are returned as "unsigned int" values. + * + * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with + * \a vgpuProcUtilInfo->vgpuProcUtilArray set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current processes' count + * running on vGPU instances in \a vgpuProcUtilInfo->vgpuProcessCount. The caller should allocate a buffer of size + * vgpuProcUtilInfo->vgpuProcessCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed + * in \a vgpuProcUtilInfo->vgpuProcUtilArray, and \a vgpuProcUtilInfo->vgpuProcessCount set to the number of entries the buffer is sized for. + * + * On successful return, the function updates \a vgpuProcUtilInfo->vgpuProcessCount with the number of vGPU sub process utilization sample + * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active + * in any given sample period. + * + * vgpuProcUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 + * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set vgpuProcUtilInfo->lastSeenTimeStamp + * to a timeStamp retrieved from a previous query to read utilization since the previous query. + * + * @param device The identifier for the target device + * @param vgpuProcUtilInfo Pointer to the caller-provided structure of nvmlVgpuProcessesUtilizationInfo_t + + * @return + * - \ref NVML_SUCCESS If utilization samples are successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, or \a vgpuProcUtilInfo is null + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the version of \a vgpuProcUtilInfo is invalid + * - \ref NVML_ERROR_INSUFFICIENT_SIZE If \a vgpuProcUtilInfo->vgpuProcUtilArray is null, or supplied \a vgpuProcUtilInfo->vgpuProcessCount + * is too small to return samples for all processes on vGPU instances currently executing on the device. + * The caller should check the current processes count from the returned \a vgpuProcUtilInfo->vgpuProcessCount, + * and call the function again with a buffer of size + * vgpuProcUtilInfo->vgpuProcessCount * sizeof(nvmlVgpuProcessUtilizationSample_t) + * - \ref NVML_ERROR_NOT_SUPPORTED If vGPU is not supported by the device + * - \ref NVML_ERROR_GPU_IS_LOST If the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_NOT_FOUND If sample entries are not found + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessesUtilizationInfo(nvmlDevice_t device, nvmlVgpuProcessesUtilizationInfo_t *vgpuProcUtilInfo); + +/** + * Queries the state of per process accounting mode on vGPU. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance The identifier of the target vGPU instance + * @param mode Reference in which to return the current accounting mode + * + * @return + * - \ref NVML_SUCCESS if the mode has been successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature + * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running on the vGPU instance + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *mode); + +/** + * Queries list of processes running on vGPU that can be queried for accounting stats. The list of processes + * returned can be in running or terminated state. + * + * For Maxwell &tm; or newer fully supported devices. + * + * To just query the maximum number of processes that can be queried, call this function with *count = 0 and + * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty. + * + * For more details see \ref nvmlVgpuInstanceGetAccountingStats. + * + * @note In case of PID collision some processes might not be accessible before the circular buffer is full. + * + * @param vgpuInstance The identifier of the target vGPU instance + * @param count Reference in which to provide the \a pids array size, and + * to return the number of elements ready to be queried + * @param pids Reference in which to return list of process ids + * + * @return + * - \ref NVML_SUCCESS if pids were successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a count is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to expected value) + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + * + * @see nvmlVgpuInstanceGetAccountingPids + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingPids(nvmlVgpuInstance_t vgpuInstance, unsigned int *count, unsigned int *pids); + +/** + * Queries process's accounting stats. + * + * For Maxwell &tm; or newer fully supported devices. + * + * Accounting stats capture GPU utilization and other statistics across the lifetime of a process, and + * can be queried during life time of the process or after its termination. + * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and + * updated to actual running time after its termination. + * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old + * processes. + * + * See \ref nvmlAccountingStats_t for description of each returned metric. + * List of processes that can be queried can be retrieved from \ref nvmlVgpuInstanceGetAccountingPids. + * + * @note Accounting Mode needs to be on. See \ref nvmlVgpuInstanceGetAccountingMode. + * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be + * queried since they don't contribute to GPU utilization. + * @note In case of pid collision stats of only the latest process (that terminated last) will be reported + * + * @param vgpuInstance The identifier of the target vGPU instance + * @param pid Process Id of the target process to query stats for + * @param stats Reference in which to return the process's accounting stats + * + * @return + * - \ref NVML_SUCCESS if stats have been successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a stats is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * or \a stats is not found + * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingStats(nvmlVgpuInstance_t vgpuInstance, unsigned int pid, nvmlAccountingStats_t *stats); + +/** + * Clears accounting information of the vGPU instance that have already terminated. + * + * For Maxwell &tm; or newer fully supported devices. + * Requires root/admin permissions. + * + * @note Accounting Mode needs to be on. See \ref nvmlVgpuInstanceGetAccountingMode. + * @note Only compute and graphics applications stats are reported and can be cleared since monitoring applications + * stats don't contribute to GPU utilization. + * + * @param vgpuInstance The identifier of the target vGPU instance + * + * @return + * - \ref NVML_SUCCESS if accounting information has been cleared + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is invalid + * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation + * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceClearAccountingPids(nvmlVgpuInstance_t vgpuInstance); + +/** + * Query the license information of the vGPU instance. + * + * For Maxwell &tm; or newer fully supported devices. + * + * @param vgpuInstance Identifier of the target vGPU instance + * @param licenseInfo Pointer to vGPU license information structure + * + * @return + * - \ref NVML_SUCCESS if information is successfully retrieved + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a licenseInfo is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running on the vGPU instance + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseInfo_v2(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuLicenseInfo_t *licenseInfo); +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlExcludedGpuQueries Excluded GPU Queries + * This chapter describes NVML operations that are associated with excluded GPUs. + * @{ + */ +/***************************************************************************************************/ + +/** + * Excluded GPU device information + **/ +typedef struct nvmlExcludedDeviceInfo_st +{ + nvmlPciInfo_t pciInfo; //!< The PCI information for the excluded GPU + char uuid[NVML_DEVICE_UUID_BUFFER_SIZE]; //!< The ASCII string UUID for the excluded GPU +} nvmlExcludedDeviceInfo_t; + + /** + * Retrieves the number of excluded GPU devices in the system. + * + * For all products. + * + * @param deviceCount Reference in which to return the number of excluded devices + * + * @return + * - \ref NVML_SUCCESS if \a deviceCount has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a deviceCount is NULL + */ +nvmlReturn_t DECLDIR nvmlGetExcludedDeviceCount(unsigned int *deviceCount); + +/** + * Acquire the device information for an excluded GPU device, based on its index. + * + * For all products. + * + * Valid indices are derived from the \a deviceCount returned by + * \ref nvmlGetExcludedDeviceCount(). For example, if \a deviceCount is 2 the valid indices + * are 0 and 1, corresponding to GPU 0 and GPU 1. + * + * @param index The index of the target GPU, >= 0 and < \a deviceCount + * @param info Reference in which to return the device information + * + * @return + * - \ref NVML_SUCCESS if \a device has been set + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a info is NULL + * + * @see nvmlGetExcludedDeviceCount + */ +nvmlReturn_t DECLDIR nvmlGetExcludedDeviceInfoByIndex(unsigned int index, nvmlExcludedDeviceInfo_t *info); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlGPUPRMAccess PRM Access + * This chapter describes NVML operations that are associated with PRM register reads + * @{ + */ +/***************************************************************************************************/ + +#define NVML_PRM_DATA_MAX_SIZE 496 +/** + * Main PRM input structure + */ +typedef struct +{ + /* I/O parameters */ + unsigned dataSize; //!< Size of the input TLV data. + unsigned status; //!< OUT: status of the PRM command + union { + /* Input data in TLV format */ + unsigned char inData[NVML_PRM_DATA_MAX_SIZE]; //!< IN: Input data in TLV format + /* Output data in TLV format */ + unsigned char outData[NVML_PRM_DATA_MAX_SIZE]; //!< OUT: Output PRM data in TLV format + }; +} nvmlPRMTLV_v1_t; + +/** + * Read or write a GPU PRM register. The input is assumed to be in TLV format in + * network byte order. + * + * For Blackwell &tm; or newer fully supported devices. + * + * Supported on Linux only. + * + * @param device Identifer of target GPU device + * @param buffer Structure holding the input data in TLV format as well as + * the PRM register contents in TLV format (in the case of a successful + * read operation). + * Note: the input data and any returned data shall be in network byte order. + * + * @return + * - \ref NVML_SUCCESS on success + * - \ref NVML_ERROR_INVALID_ARGUMENT if \p device or \p buffer are invalid + * - \ref NVML_ERROR_NO_PERMISSION if user does not have permission to perform this operation + * - \ref NVML_ERROR_NOT_SUPPORTED if this feature is not supported by the device + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the version specified in \p buffer is not supported + */ +nvmlReturn_t DECLDIR nvmlDeviceReadWritePRM_v1(nvmlDevice_t device, nvmlPRMTLV_v1_t *buffer); + +/** @} */ + +/***************************************************************************************************/ +/** @defgroup nvmlMultiInstanceGPU Multi Instance GPU Management + * This chapter describes NVML operations that are associated with Multi Instance GPU management. + * @{ + */ +/***************************************************************************************************/ + +/** + * Disable Multi Instance GPU mode. + */ +#define NVML_DEVICE_MIG_DISABLE 0x0 + +/** + * Enable Multi Instance GPU mode. + */ +#define NVML_DEVICE_MIG_ENABLE 0x1 + +/** + * GPU instance profiles. + * + * These macros should be passed to \ref nvmlDeviceGetGpuInstanceProfileInfo to retrieve the + * detailed information about a GPU instance such as profile ID, engine counts. + */ +#define NVML_GPU_INSTANCE_PROFILE_1_SLICE 0x0 +#define NVML_GPU_INSTANCE_PROFILE_2_SLICE 0x1 +#define NVML_GPU_INSTANCE_PROFILE_3_SLICE 0x2 +#define NVML_GPU_INSTANCE_PROFILE_4_SLICE 0x3 +#define NVML_GPU_INSTANCE_PROFILE_7_SLICE 0x4 +#define NVML_GPU_INSTANCE_PROFILE_8_SLICE 0x5 +#define NVML_GPU_INSTANCE_PROFILE_6_SLICE 0x6 +// 1_SLICE profile with at least one (if supported at all) of Decoder, Encoder, JPEG, OFA engines. +#define NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV1 0x7 +// 2_SLICE profile with at least one (if supported at all) of Decoder, Encoder, JPEG, OFA engines. +#define NVML_GPU_INSTANCE_PROFILE_2_SLICE_REV1 0x8 +// 1_SLICE profile with twice the amount of memory resources. +#define NVML_GPU_INSTANCE_PROFILE_1_SLICE_REV2 0x9 +// 1_SLICE gfx capable profile +#define NVML_GPU_INSTANCE_PROFILE_1_SLICE_GFX 0x0A +// 2_SLICE gfx capable profile +#define NVML_GPU_INSTANCE_PROFILE_2_SLICE_GFX 0x0B +// 4_SLICE gfx capable profile +#define NVML_GPU_INSTANCE_PROFILE_4_SLICE_GFX 0x0C +// 1_SLICE profile with none of Decode, Encoder, JPEG, OFA engines. +#define NVML_GPU_INSTANCE_PROFILE_1_SLICE_NO_ME 0x0D +// 2_SLICE profile with none of Decode, Encoder, JPEG, OFA engines. +#define NVML_GPU_INSTANCE_PROFILE_2_SLICE_NO_ME 0x0E +// 1_SLICE profile with all of GPU Decode, Encoder, JPEG, OFA engines. +// Allocation of instance of this profile prevents allocation of +// all but _NO_ME profiles. +#define NVML_GPU_INSTANCE_PROFILE_1_SLICE_ALL_ME 0x0F +// 2_SLICE profile with all of GPU Decode, Encoder, JPEG, OFA engines. +// Allocation of instance of this profile prevents allocation of +// all but _NO_ME profiles. +#define NVML_GPU_INSTANCE_PROFILE_2_SLICE_ALL_ME 0x10 +#define NVML_GPU_INSTANCE_PROFILE_COUNT 0x11 + +/** + * MIG GPU instance profile capability. + * + * Bit field values representing MIG profile capabilities + * \ref nvmlGpuInstanceProfileInfo_v3_t.capabilities + */ +#define NVML_GPU_INSTANCE_PROFILE_CAPS_P2P 0x1 +#define NVML_GPU_INTSTANCE_PROFILE_CAPS_P2P 0x1 //!< Deprecated, do not use +#define NVML_GPU_INSTANCE_PROFILE_CAPS_GFX 0x2 + +/** + * MIG compute instance profile capability. + * + * Bit field values representing MIG profile capabilities + * \ref nvmlComputeInstanceProfileInfo_v3_t.capabilities + */ +#define NVML_COMPUTE_INSTANCE_PROFILE_CAPS_GFX 0x1 + +typedef struct nvmlGpuInstancePlacement_st +{ + unsigned int start; //!< Index of first occupied memory slice + unsigned int size; //!< Number of memory slices occupied +} nvmlGpuInstancePlacement_t; + +/** + * GPU instance profile information. + */ +typedef struct nvmlGpuInstanceProfileInfo_st +{ + unsigned int id; //!< Unique profile ID within the device + unsigned int isP2pSupported; //!< Peer-to-Peer support + unsigned int sliceCount; //!< GPU Slice count + unsigned int instanceCount; //!< GPU instance count + unsigned int multiprocessorCount; //!< Streaming Multiprocessor count + unsigned int copyEngineCount; //!< Copy Engine count + unsigned int decoderCount; //!< Decoder Engine count + unsigned int encoderCount; //!< Encoder Engine count + unsigned int jpegCount; //!< JPEG Engine count + unsigned int ofaCount; //!< OFA Engine count + unsigned long long memorySizeMB; //!< Memory size in MBytes +} nvmlGpuInstanceProfileInfo_t; + +/** + * GPU instance profile information (v2). + * + * Version 2 adds the \ref nvmlGpuInstanceProfileInfo_v2_t.version field + * to the start of the structure, and the \ref nvmlGpuInstanceProfileInfo_v2_t.name + * field to the end. This structure is not backwards-compatible with + * \ref nvmlGpuInstanceProfileInfo_t. + */ +typedef struct nvmlGpuInstanceProfileInfo_v2_st +{ + unsigned int version; //!< Structure version identifier (set to \ref nvmlGpuInstanceProfileInfo_v2) + unsigned int id; //!< Unique profile ID within the device + unsigned int isP2pSupported; //!< Peer-to-Peer support + unsigned int sliceCount; //!< GPU Slice count + unsigned int instanceCount; //!< GPU instance count + unsigned int multiprocessorCount; //!< Streaming Multiprocessor count + unsigned int copyEngineCount; //!< Copy Engine count + unsigned int decoderCount; //!< Decoder Engine count + unsigned int encoderCount; //!< Encoder Engine count + unsigned int jpegCount; //!< JPEG Engine count + unsigned int ofaCount; //!< OFA Engine count + unsigned long long memorySizeMB; //!< Memory size in MBytes + char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name +} nvmlGpuInstanceProfileInfo_v2_t; + +/** + * Version identifier value for \ref nvmlGpuInstanceProfileInfo_v2_t.version. + */ +#define nvmlGpuInstanceProfileInfo_v2 NVML_STRUCT_VERSION(GpuInstanceProfileInfo, 2) + +/** + * GPU instance profile information (v3). + * + * Version 3 removes isP2pSupported field and adds the \ref nvmlGpuInstanceProfileInfo_v3_t.capabilities + * field \ref nvmlGpuInstanceProfileInfo_t. + */ +typedef struct nvmlGpuInstanceProfileInfo_v3_st +{ + unsigned int version; //!< Structure version identifier (set to \ref nvmlGpuInstanceProfileInfo_v3) + unsigned int id; //!< Unique profile ID within the device + unsigned int sliceCount; //!< GPU Slice count + unsigned int instanceCount; //!< GPU instance count + unsigned int multiprocessorCount; //!< Streaming Multiprocessor count + unsigned int copyEngineCount; //!< Copy Engine count + unsigned int decoderCount; //!< Decoder Engine count + unsigned int encoderCount; //!< Encoder Engine count + unsigned int jpegCount; //!< JPEG Engine count + unsigned int ofaCount; //!< OFA Engine count + unsigned long long memorySizeMB; //!< Memory size in MBytes + char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name + unsigned int capabilities; //!< Additional capabilities +} nvmlGpuInstanceProfileInfo_v3_t; + +/** + * Version identifier value for \ref nvmlGpuInstanceProfileInfo_v3_t.version. + */ +#define nvmlGpuInstanceProfileInfo_v3 NVML_STRUCT_VERSION(GpuInstanceProfileInfo, 3) + +typedef struct nvmlGpuInstanceInfo_st +{ + nvmlDevice_t device; //!< Parent device + unsigned int id; //!< Unique instance ID within the device + unsigned int profileId; //!< Unique profile ID within the device + nvmlGpuInstancePlacement_t placement; //!< Placement for this instance +} nvmlGpuInstanceInfo_t; + +/** + * Compute instance profiles. + * + * These macros should be passed to \ref nvmlGpuInstanceGetComputeInstanceProfileInfo to retrieve the + * detailed information about a compute instance such as profile ID, engine counts + */ +#define NVML_COMPUTE_INSTANCE_PROFILE_1_SLICE 0x0 +#define NVML_COMPUTE_INSTANCE_PROFILE_2_SLICE 0x1 +#define NVML_COMPUTE_INSTANCE_PROFILE_3_SLICE 0x2 +#define NVML_COMPUTE_INSTANCE_PROFILE_4_SLICE 0x3 +#define NVML_COMPUTE_INSTANCE_PROFILE_7_SLICE 0x4 +#define NVML_COMPUTE_INSTANCE_PROFILE_8_SLICE 0x5 +#define NVML_COMPUTE_INSTANCE_PROFILE_6_SLICE 0x6 +#define NVML_COMPUTE_INSTANCE_PROFILE_1_SLICE_REV1 0x7 +#define NVML_COMPUTE_INSTANCE_PROFILE_COUNT 0x8 + +#define NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_SHARED 0x0 //!< All the engines except multiprocessors would be shared +#define NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_COUNT 0x1 + +typedef struct nvmlComputeInstancePlacement_st +{ + unsigned int start; //!< Index of first occupied compute slice + unsigned int size; //!< Number of compute slices occupied +} nvmlComputeInstancePlacement_t; + +/** + * Compute instance profile information. + */ +typedef struct nvmlComputeInstanceProfileInfo_st +{ + unsigned int id; //!< Unique profile ID within the GPU instance + unsigned int sliceCount; //!< GPU Slice count + unsigned int instanceCount; //!< Compute instance count + unsigned int multiprocessorCount; //!< Streaming Multiprocessor count + unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count + unsigned int sharedDecoderCount; //!< Shared Decoder Engine count + unsigned int sharedEncoderCount; //!< Shared Encoder Engine count + unsigned int sharedJpegCount; //!< Shared JPEG Engine count + unsigned int sharedOfaCount; //!< Shared OFA Engine count +} nvmlComputeInstanceProfileInfo_t; + +/** + * Compute instance profile information (v2). + * + * Version 2 adds the \ref nvmlComputeInstanceProfileInfo_v2_t.version field + * to the start of the structure, and the \ref nvmlComputeInstanceProfileInfo_v2_t.name + * field to the end. This structure is not backwards-compatible with + * \ref nvmlComputeInstanceProfileInfo_t. + */ +typedef struct nvmlComputeInstanceProfileInfo_v2_st +{ + unsigned int version; //!< Structure version identifier (set to \ref nvmlComputeInstanceProfileInfo_v2) + unsigned int id; //!< Unique profile ID within the GPU instance + unsigned int sliceCount; //!< GPU Slice count + unsigned int instanceCount; //!< Compute instance count + unsigned int multiprocessorCount; //!< Streaming Multiprocessor count + unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count + unsigned int sharedDecoderCount; //!< Shared Decoder Engine count + unsigned int sharedEncoderCount; //!< Shared Encoder Engine count + unsigned int sharedJpegCount; //!< Shared JPEG Engine count + unsigned int sharedOfaCount; //!< Shared OFA Engine count + char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name +} nvmlComputeInstanceProfileInfo_v2_t; + +/** + * Version identifier value for \ref nvmlComputeInstanceProfileInfo_v2_t.version. + */ +#define nvmlComputeInstanceProfileInfo_v2 NVML_STRUCT_VERSION(ComputeInstanceProfileInfo, 2) + +/** + * Compute instance profile information (v3). + * + * Version 3 adds the \ref nvmlComputeInstanceProfileInfo_v3_t.capabilities field + * \ref nvmlComputeInstanceProfileInfo_t. + */ +typedef struct nvmlComputeInstanceProfileInfo_v3_st +{ + unsigned int version; //!< Structure version identifier (set to \ref nvmlComputeInstanceProfileInfo_v3) + unsigned int id; //!< Unique profile ID within the GPU instance + unsigned int sliceCount; //!< GPU Slice count + unsigned int instanceCount; //!< Compute instance count + unsigned int multiprocessorCount; //!< Streaming Multiprocessor count + unsigned int sharedCopyEngineCount; //!< Shared Copy Engine count + unsigned int sharedDecoderCount; //!< Shared Decoder Engine count + unsigned int sharedEncoderCount; //!< Shared Encoder Engine count + unsigned int sharedJpegCount; //!< Shared JPEG Engine count + unsigned int sharedOfaCount; //!< Shared OFA Engine count + char name[NVML_DEVICE_NAME_V2_BUFFER_SIZE]; //!< Profile name + unsigned int capabilities; //!< Additional capabilities +} nvmlComputeInstanceProfileInfo_v3_t; + +/** + * Version identifier value for \ref nvmlComputeInstanceProfileInfo_v3_t.version. + */ +#define nvmlComputeInstanceProfileInfo_v3 NVML_STRUCT_VERSION(ComputeInstanceProfileInfo, 3) + +typedef struct nvmlComputeInstanceInfo_st +{ + nvmlDevice_t device; //!< Parent device + nvmlGpuInstance_t gpuInstance; //!< Parent GPU instance + unsigned int id; //!< Unique instance ID within the GPU instance + unsigned int profileId; //!< Unique profile ID within the GPU instance + nvmlComputeInstancePlacement_t placement; //!< Placement for this instance within the GPU instance's compute slice range {0, sliceCount} +} nvmlComputeInstanceInfo_t; + +typedef struct nvmlComputeInstance_st* nvmlComputeInstance_t; + +/** + * Set MIG mode for the device. + * + * For Ampere &tm; or newer fully supported devices. + * Requires root user. + * + * This mode determines whether a GPU instance can be created. + * + * This API may unbind or reset the device to activate the requested mode. Thus, the attributes associated with the + * device, such as minor number, might change. The caller of this API is expected to query such attributes again. + * + * On certain platforms like pass-through virtualization, where reset functionality may not be exposed directly, VM + * reboot is required. \a activationStatus would return \ref NVML_ERROR_RESET_REQUIRED for such cases. + * + * \a activationStatus would return the appropriate error code upon unsuccessful activation. For example, if device + * unbind fails because the device isn't idle, \ref NVML_ERROR_IN_USE would be returned. The caller of this API + * is expected to idle the device and retry setting the \a mode. + * + * @note On Windows, only disabling MIG mode is supported. \a activationStatus would return \ref + * NVML_ERROR_NOT_SUPPORTED as GPU reset is not supported on Windows through this API. + * + * @param device The identifier of the target device + * @param mode The mode to be set, \ref NVML_DEVICE_MIG_DISABLE or + * \ref NVML_DEVICE_MIG_ENABLE + * @param activationStatus The activationStatus status + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device,\a mode or \a activationStatus are invalid + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG mode + */ +nvmlReturn_t DECLDIR nvmlDeviceSetMigMode(nvmlDevice_t device, unsigned int mode, nvmlReturn_t *activationStatus); + +/** + * Get MIG mode for the device. + * + * For Ampere &tm; or newer fully supported devices. + * + * Changing MIG modes may require device unbind or reset. The "pending" MIG mode refers to the target mode following the + * next activation trigger. + * + * @param device The identifier of the target device + * @param currentMode Returns the current mode, \ref NVML_DEVICE_MIG_DISABLE or + * \ref NVML_DEVICE_MIG_ENABLE + * @param pendingMode Returns the pending mode, \ref NVML_DEVICE_MIG_DISABLE or + * \ref NVML_DEVICE_MIG_ENABLE + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a currentMode or \a pendingMode are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG mode + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMigMode(nvmlDevice_t device, unsigned int *currentMode, unsigned int *pendingMode); + +/** + * Get GPU instance profile information + * + * Information provided by this API is immutable throughout the lifetime of a MIG mode. + * + * @note This API can be used to enumerate all MIG profiles supported by NVML in a forward compatible + * way by invoking it on \a profile values starting from 0, until the API returns \ref NVML_ERROR_INVALID_ARGUMENT. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * @param profile One of the NVML_GPU_INSTANCE_PROFILE_* + * @param info Returns detailed profile information + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile or \a info are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG or \a profile isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfo(nvmlDevice_t device, unsigned int profile, + nvmlGpuInstanceProfileInfo_t *info); + +/** + * Versioned wrapper around \ref nvmlDeviceGetGpuInstanceProfileInfo that accepts a versioned + * \ref nvmlGpuInstanceProfileInfo_v2_t or later output structure. + * + * @note The caller must set the \ref nvmlGpuInstanceProfileInfo_v2_t.version field to the + * appropriate version prior to calling this function. For example: + * \code + * nvmlGpuInstanceProfileInfo_v2_t profileInfo = + * { .version = nvmlGpuInstanceProfileInfo_v2 }; + * nvmlReturn_t result = nvmlDeviceGetGpuInstanceProfileInfoV(device, + * profile, + * &profileInfo); + * \endcode + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * @param profile One of the NVML_GPU_INSTANCE_PROFILE_* + * @param info Returns detailed profile information + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile, \a info, or \a info->version are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profile isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfoV(nvmlDevice_t device, unsigned int profile, + nvmlGpuInstanceProfileInfo_v2_t *info); + +/** + * GPU instance profile query function that accepts profile ID, instead of profile name. + * It accepts a versioned \ref nvmlGpuInstanceProfileInfo_v2_t or later output structure. + * + * @note The caller must set the \ref nvmlGpuInstanceProfileInfo_v2_t.version field to the + * appropriate version prior to calling this function. For example: + * \code + * nvmlGpuInstanceProfileInfo_v2_t profileInfo = + * { .version = nvmlGpuInstanceProfileInfo_v2 }; + * nvmlReturn_t result = nvmlDeviceGetGpuInstanceProfileInfoV(device, + * profile, + * &profileInfo); + * \endcode + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device The identifier of the target device + * @param profileId One of the profile IDs. + * @param info Returns detailed profile information + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId, \a info, or \a info->version are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profile isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfoByIdV(nvmlDevice_t device, unsigned int profileId, + nvmlGpuInstanceProfileInfo_v2_t *info); + +/** + * Get GPU instance placements. + * + * A placement represents the location of a GPU instance within a device. This API only returns all the possible + * placements for the given profile regardless of whether MIG is enabled or not. + * A created GPU instance occupies memory slices described by its placement. Creation of new GPU instance will + * fail if there is overlap with the already occupied memory slices. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param device The identifier of the target device + * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo + * @param placements Returns placements allowed for the profile. Can be NULL to discover number + * of allowed placements for this profile. If non-NULL must be large enough + * to accommodate the placements supported by the profile. + * @param count Returns number of allowed placemenets for the profile. + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId or \a count are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG or \a profileId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstancePossiblePlacements_v2(nvmlDevice_t device, unsigned int profileId, + nvmlGpuInstancePlacement_t *placements, + unsigned int *count); + +/** + * Get GPU instance profile capacity. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param device The identifier of the target device + * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo + * @param count Returns remaining instance count for the profile ID + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId or \a count are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profileId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceRemainingCapacity(nvmlDevice_t device, unsigned int profileId, + unsigned int *count); + +/** + * Create GPU instance. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * If the parent device is unbound, reset or the GPU instance is destroyed explicitly, the GPU instance handle would + * become invalid. The GPU instance must be recreated to acquire a valid handle. + * + * @param device The identifier of the target device + * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo + * @param gpuInstance Returns the GPU instance handle + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile, \a profileId or \a gpuInstance are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or in vGPU guest + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested GPU instance could not be created + */ +nvmlReturn_t DECLDIR nvmlDeviceCreateGpuInstance(nvmlDevice_t device, unsigned int profileId, + nvmlGpuInstance_t *gpuInstance); + +/** + * Create GPU instance with the specified placement. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * If the parent device is unbound, reset or the GPU instance is destroyed explicitly, the GPU instance handle would + * become invalid. The GPU instance must be recreated to acquire a valid handle. + * + * @param device The identifier of the target device + * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo + * @param placement The requested placement. See \ref nvmlDeviceGetGpuInstancePossiblePlacements_v2 + * @param gpuInstance Returns the GPU instance handle + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile, \a profileId, \a placement or \a gpuInstance + * are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or in vGPU guest + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested GPU instance could not be created + */ +nvmlReturn_t DECLDIR nvmlDeviceCreateGpuInstanceWithPlacement(nvmlDevice_t device, unsigned int profileId, + const nvmlGpuInstancePlacement_t *placement, + nvmlGpuInstance_t *gpuInstance); +/** + * Destroy GPU instance. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param gpuInstance The GPU instance handle + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or in vGPU guest + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_IN_USE If the GPU instance is in use. This error would be returned if processes + * (e.g. CUDA application) or compute instances are active on the + * GPU instance. + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceDestroy(nvmlGpuInstance_t gpuInstance); + +/** + * Get GPU instances for given profile ID. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param device The identifier of the target device + * @param profileId The GPU instance profile ID. See \ref nvmlDeviceGetGpuInstanceProfileInfo + * @param gpuInstances Returns pre-exiting GPU instances, the buffer must be large enough to + * accommodate the instances supported by the profile. + * See \ref nvmlDeviceGetGpuInstanceProfileInfo + * @param count The count of returned GPU instances + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId, \a gpuInstances or \a count are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstances(nvmlDevice_t device, unsigned int profileId, + nvmlGpuInstance_t *gpuInstances, unsigned int *count); + +/** + * Get GPU instances for given instance ID. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param device The identifier of the target device + * @param id The GPU instance ID + * @param gpuInstance Returns GPU instance + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a id or \a gpuInstance are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_NOT_FOUND If the GPU instance is not found. + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceById(nvmlDevice_t device, unsigned int id, nvmlGpuInstance_t *gpuInstance); + +/** + * Get GPU instance information. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param gpuInstance The GPU instance handle + * @param info Return GPU instance information + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance or \a info are invalid + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetInfo(nvmlGpuInstance_t gpuInstance, nvmlGpuInstanceInfo_t *info); + +/** + * Get compute instance profile information. + * + * Information provided by this API is immutable throughout the lifetime of a MIG mode. + * + * @note This API can be used to enumerate all MIG profiles supported by NVML in a forward compatible + * way by invoking it on \a profile values starting from 0, until the API returns \ref NVML_ERROR_INVALID_ARGUMENT. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param gpuInstance The identifier of the target GPU instance + * @param profile One of the NVML_COMPUTE_INSTANCE_PROFILE_* + * @param engProfile One of the NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_* + * @param info Returns detailed profile information + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a engProfile or \a info are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a profile isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceProfileInfo(nvmlGpuInstance_t gpuInstance, unsigned int profile, + unsigned int engProfile, + nvmlComputeInstanceProfileInfo_t *info); + +/** + * Versioned wrapper around \ref nvmlGpuInstanceGetComputeInstanceProfileInfo that accepts a versioned + * \ref nvmlComputeInstanceProfileInfo_v2_t or later output structure. + * + * @note The caller must set the \ref nvmlGpuInstanceProfileInfo_v2_t.version field to the + * appropriate version prior to calling this function. For example: + * \code + * nvmlComputeInstanceProfileInfo_v2_t profileInfo = + * { .version = nvmlComputeInstanceProfileInfo_v2 }; + * nvmlReturn_t result = nvmlGpuInstanceGetComputeInstanceProfileInfoV(gpuInstance, + * profile, + * engProfile, + * &profileInfo); + * \endcode + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param gpuInstance The identifier of the target GPU instance + * @param profile One of the NVML_COMPUTE_INSTANCE_PROFILE_* + * @param engProfile One of the NVML_COMPUTE_INSTANCE_ENGINE_PROFILE_* + * @param info Returns detailed profile information + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a engProfile, \a info, or \a info->version are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a profile isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceProfileInfoV(nvmlGpuInstance_t gpuInstance, unsigned int profile, + unsigned int engProfile, + nvmlComputeInstanceProfileInfo_v2_t *info); + +/** + * Get compute instance profile capacity. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param gpuInstance The identifier of the target GPU instance + * @param profileId The compute instance profile ID. + * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo + * @param count Returns remaining instance count for the profile ID + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profileId or \a availableCount are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceRemainingCapacity(nvmlGpuInstance_t gpuInstance, + unsigned int profileId, unsigned int *count); + +/** + * Get compute instance placements. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * A placement represents the location of a compute instance within a GPU instance. This API only returns all the possible + * placements for the given profile. + * A created compute instance occupies compute slices described by its placement. Creation of new compute instance will + * fail if there is overlap with the already occupied compute slices. + * + * @param gpuInstance The identifier of the target GPU instance + * @param profileId The compute instance profile ID. See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo + * @param placements Returns placements allowed for the profile. Can be NULL to discover number + * of allowed placements for this profile. If non-NULL must be large enough + * to accommodate the placements supported by the profile. + * @param count Returns number of allowed placemenets for the profile. + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profileId or \a count are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profileId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstancePossiblePlacements(nvmlGpuInstance_t gpuInstance, + unsigned int profileId, + nvmlComputeInstancePlacement_t *placements, + unsigned int *count); + +/** + * Create compute instance. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * If the parent device is unbound, reset or the parent GPU instance is destroyed or the compute instance is destroyed + * explicitly, the compute instance handle would become invalid. The compute instance must be recreated to acquire + * a valid handle. + * + * @param gpuInstance The identifier of the target GPU instance + * @param profileId The compute instance profile ID. + * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo + * @param computeInstance Returns the compute instance handle + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a profileId or \a computeInstance + * are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested compute instance could not be created + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceCreateComputeInstance(nvmlGpuInstance_t gpuInstance, unsigned int profileId, + nvmlComputeInstance_t *computeInstance); + +/** + * Create compute instance with the specified placement. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * If the parent device is unbound, reset or the parent GPU instance is destroyed or the compute instance is destroyed + * explicitly, the compute instance handle would become invalid. The compute instance must be recreated to acquire + * a valid handle. + * + * @param gpuInstance The identifier of the target GPU instance + * @param profileId The compute instance profile ID. + * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo + * @param placement The requested placement. See \ref nvmlGpuInstanceGetComputeInstancePossiblePlacements + * @param computeInstance Returns the compute instance handle + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profile, \a profileId or \a computeInstance + * are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_INSUFFICIENT_RESOURCES If the requested compute instance could not be created + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceCreateComputeInstanceWithPlacement(nvmlGpuInstance_t gpuInstance, unsigned int profileId, + const nvmlComputeInstancePlacement_t *placement, + nvmlComputeInstance_t *computeInstance); + +/** + * Destroy compute instance. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param computeInstance The compute instance handle + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a computeInstance is invalid + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_IN_USE If the compute instance is in use. This error would be returned if + * processes (e.g. CUDA application) are active on the compute instance. + */ +nvmlReturn_t DECLDIR nvmlComputeInstanceDestroy(nvmlComputeInstance_t computeInstance); + +/** + * Get compute instances for given profile ID. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param gpuInstance The identifier of the target GPU instance + * @param profileId The compute instance profile ID. + * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo + * @param computeInstances Returns pre-exiting compute instances, the buffer must be large enough to + * accommodate the instances supported by the profile. + * See \ref nvmlGpuInstanceGetComputeInstanceProfileInfo + * @param count The count of returned compute instances + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a gpuInstance, \a profileId, \a computeInstances or \a count + * are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a profileId isn't supported + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstances(nvmlGpuInstance_t gpuInstance, unsigned int profileId, + nvmlComputeInstance_t *computeInstances, unsigned int *count); + +/** + * Get compute instance for given instance ID. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * Requires privileged user. + * + * @param gpuInstance The identifier of the target GPU instance + * @param id The compute instance ID + * @param computeInstance Returns compute instance + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a ID or \a computeInstance are invalid + * - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + * - \ref NVML_ERROR_NOT_FOUND If the compute instance is not found. + */ +nvmlReturn_t DECLDIR nvmlGpuInstanceGetComputeInstanceById(nvmlGpuInstance_t gpuInstance, unsigned int id, + nvmlComputeInstance_t *computeInstance); + +/** + * Get compute instance information. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param computeInstance The compute instance handle + * @param info Return compute instance information + * + * @return + * - \ref NVML_SUCCESS Upon success + * - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a computeInstance or \a info are invalid + * - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation + */ +nvmlReturn_t DECLDIR nvmlComputeInstanceGetInfo_v2(nvmlComputeInstance_t computeInstance, nvmlComputeInstanceInfo_t *info); + +/** + * Test if the given handle refers to a MIG device. + * + * A MIG device handle is an NVML abstraction which maps to a MIG compute instance. + * These overloaded references can be used (with some restrictions) interchangeably + * with a GPU device handle to execute queries at a per-compute instance granularity. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device NVML handle to test + * @param isMigDevice True when handle refers to a MIG device + * + * @return + * - \ref NVML_SUCCESS if \a device status was successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device handle or \a isMigDevice reference is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this check is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceIsMigDeviceHandle(nvmlDevice_t device, unsigned int *isMigDevice); + +/** + * Get GPU instance ID for the given MIG device handle. + * + * GPU instance IDs are unique per device and remain valid until the GPU instance is destroyed. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device Target MIG device handle + * @param id GPU instance ID + * + * @return + * - \ref NVML_SUCCESS if instance ID was successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a id reference is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceId(nvmlDevice_t device, unsigned int *id); + +/** + * Get compute instance ID for the given MIG device handle. + * + * Compute instance IDs are unique per GPU instance and remain valid until the compute instance + * is destroyed. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device Target MIG device handle + * @param id Compute instance ID + * + * @return + * - \ref NVML_SUCCESS if instance ID was successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a id reference is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetComputeInstanceId(nvmlDevice_t device, unsigned int *id); + +/** + * Get the maximum number of MIG devices that can exist under a given parent NVML device. + * + * Returns zero if MIG is not supported or enabled. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device Target device handle + * @param count Count of MIG devices + * + * @return + * - \ref NVML_SUCCESS if \a count was successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a count reference is invalid + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMaxMigDeviceCount(nvmlDevice_t device, unsigned int *count); + +/** + * Get MIG device handle for the given index under its parent NVML device. + * + * If the compute instance is destroyed either explicitly or by destroying, + * resetting or unbinding the parent GPU instance or the GPU device itself + * the MIG device handle would remain invalid and must be requested again + * using this API. Handles may be reused and their properties can change in + * the process. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param device Reference to the parent GPU device handle + * @param index Index of the MIG device + * @param migDevice Reference to the MIG device handle + * + * @return + * - \ref NVML_SUCCESS if \a migDevice handle was successfully created + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a index or \a migDevice reference is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_NOT_FOUND if no valid MIG device was found at \a index + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetMigDeviceHandleByIndex(nvmlDevice_t device, unsigned int index, + nvmlDevice_t *migDevice); + +/** + * Get parent device handle from a MIG device handle. + * + * For Ampere &tm; or newer fully supported devices. + * Supported on Linux only. + * + * @param migDevice MIG device handle + * @param device Device handle + * + * @return + * - \ref NVML_SUCCESS if \a device handle was successfully created + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a migDevice or \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetDeviceHandleFromMigDeviceHandle(nvmlDevice_t migDevice, nvmlDevice_t *device); + +/** @} */ // @defgroup nvmlMultiInstanceGPU + + +/***************************************************************************************************/ +/** @defgroup GPM NVML GPM + * @note For NVIDIA vGPU Software products + * @note (A) GPM is supported only on MIG-backed vGPU profiles that are allocated all of the instance's frame buffer + * @note (B) No GPM support on Windows + * @{ + */ +/***************************************************************************************************/ +/** @defgroup nvmlGpmEnums GPM Enums + * @{ + */ +/***************************************************************************************************/ + +/** + * GPM Metric Identifiers + */ +typedef enum +{ + NVML_GPM_METRIC_GRAPHICS_UTIL = 1, //!< Percentage of time any compute/graphics app was active on the GPU. 0.0 - 100.0 + NVML_GPM_METRIC_SM_UTIL = 2, //!< Percentage of SMs that were busy. 0.0 - 100.0 + NVML_GPM_METRIC_SM_OCCUPANCY = 3, //!< Percentage of warps that were active vs theoretical maximum. 0.0 - 100.0 + NVML_GPM_METRIC_INTEGER_UTIL = 4, //!< Percentage of time the GPU's SMs were doing integer operations. 0.0 - 100.0 + NVML_GPM_METRIC_ANY_TENSOR_UTIL = 5, //!< Percentage of time the GPU's SMs were doing ANY tensor operations. 0.0 - 100.0 + NVML_GPM_METRIC_DFMA_TENSOR_UTIL = 6, //!< Percentage of time the GPU's SMs were doing DFMA tensor operations. 0.0 - 100.0 + NVML_GPM_METRIC_HMMA_TENSOR_UTIL = 7, //!< Percentage of time the GPU's SMs were doing HMMA tensor operations. 0.0 - 100.0 + NVML_GPM_METRIC_IMMA_TENSOR_UTIL = 9, //!< Percentage of time the GPU's SMs were doing IMMA tensor operations. 0.0 - 100.0 + NVML_GPM_METRIC_DRAM_BW_UTIL = 10, //!< Percentage of DRAM bw used vs theoretical maximum. 0.0 - 100.0 */ + NVML_GPM_METRIC_FP64_UTIL = 11, //!< Percentage of time the GPU's SMs were doing non-tensor FP64 math. 0.0 - 100.0 + NVML_GPM_METRIC_FP32_UTIL = 12, //!< Percentage of time the GPU's SMs were doing non-tensor FP32 math. 0.0 - 100.0 + NVML_GPM_METRIC_FP16_UTIL = 13, //!< Percentage of time the GPU's SMs were doing non-tensor FP16 math. 0.0 - 100.0 + NVML_GPM_METRIC_PCIE_TX_PER_SEC = 20, //!< PCIe traffic from this GPU in MiB/sec + NVML_GPM_METRIC_PCIE_RX_PER_SEC = 21, //!< PCIe traffic to this GPU in MiB/sec + NVML_GPM_METRIC_NVDEC_0_UTIL = 30, //!< Percent utilization of NVDEC 0. 0.0 - 100.0 + NVML_GPM_METRIC_NVDEC_1_UTIL = 31, //!< Percent utilization of NVDEC 1. 0.0 - 100.0 + NVML_GPM_METRIC_NVDEC_2_UTIL = 32, //!< Percent utilization of NVDEC 2. 0.0 - 100.0 + NVML_GPM_METRIC_NVDEC_3_UTIL = 33, //!< Percent utilization of NVDEC 3. 0.0 - 100.0 + NVML_GPM_METRIC_NVDEC_4_UTIL = 34, //!< Percent utilization of NVDEC 4. 0.0 - 100.0 + NVML_GPM_METRIC_NVDEC_5_UTIL = 35, //!< Percent utilization of NVDEC 5. 0.0 - 100.0 + NVML_GPM_METRIC_NVDEC_6_UTIL = 36, //!< Percent utilization of NVDEC 6. 0.0 - 100.0 + NVML_GPM_METRIC_NVDEC_7_UTIL = 37, //!< Percent utilization of NVDEC 7. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_0_UTIL = 40, //!< Percent utilization of NVJPG 0. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_1_UTIL = 41, //!< Percent utilization of NVJPG 1. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_2_UTIL = 42, //!< Percent utilization of NVJPG 2. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_3_UTIL = 43, //!< Percent utilization of NVJPG 3. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_4_UTIL = 44, //!< Percent utilization of NVJPG 4. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_5_UTIL = 45, //!< Percent utilization of NVJPG 5. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_6_UTIL = 46, //!< Percent utilization of NVJPG 6. 0.0 - 100.0 + NVML_GPM_METRIC_NVJPG_7_UTIL = 47, //!< Percent utilization of NVJPG 7. 0.0 - 100.0 + NVML_GPM_METRIC_NVOFA_0_UTIL = 50, //!< Percent utilization of NVOFA 0. 0.0 - 100.0 + NVML_GPM_METRIC_NVOFA_1_UTIL = 51, //!< Percent utilization of NVOFA 1. 0.0 - 100.0 + NVML_GPM_METRIC_NVLINK_TOTAL_RX_PER_SEC = 60, //!< NvLink read bandwidth for all links in MiB/sec + NVML_GPM_METRIC_NVLINK_TOTAL_TX_PER_SEC = 61, //!< NvLink write bandwidth for all links in MiB/sec + NVML_GPM_METRIC_NVLINK_L0_RX_PER_SEC = 62, //!< NvLink read bandwidth for link 0 in MiB/sec + NVML_GPM_METRIC_NVLINK_L0_TX_PER_SEC = 63, //!< NvLink write bandwidth for link 0 in MiB/sec + NVML_GPM_METRIC_NVLINK_L1_RX_PER_SEC = 64, //!< NvLink read bandwidth for link 1 in MiB/sec + NVML_GPM_METRIC_NVLINK_L1_TX_PER_SEC = 65, //!< NvLink write bandwidth for link 1 in MiB/sec + NVML_GPM_METRIC_NVLINK_L2_RX_PER_SEC = 66, //!< NvLink read bandwidth for link 2 in MiB/sec + NVML_GPM_METRIC_NVLINK_L2_TX_PER_SEC = 67, //!< NvLink write bandwidth for link 2 in MiB/sec + NVML_GPM_METRIC_NVLINK_L3_RX_PER_SEC = 68, //!< NvLink read bandwidth for link 3 in MiB/sec + NVML_GPM_METRIC_NVLINK_L3_TX_PER_SEC = 69, //!< NvLink write bandwidth for link 3 in MiB/sec + NVML_GPM_METRIC_NVLINK_L4_RX_PER_SEC = 70, //!< NvLink read bandwidth for link 4 in MiB/sec + NVML_GPM_METRIC_NVLINK_L4_TX_PER_SEC = 71, //!< NvLink write bandwidth for link 4 in MiB/sec + NVML_GPM_METRIC_NVLINK_L5_RX_PER_SEC = 72, //!< NvLink read bandwidth for link 5 in MiB/sec + NVML_GPM_METRIC_NVLINK_L5_TX_PER_SEC = 73, //!< NvLink write bandwidth for link 5 in MiB/sec + NVML_GPM_METRIC_NVLINK_L6_RX_PER_SEC = 74, //!< NvLink read bandwidth for link 6 in MiB/sec + NVML_GPM_METRIC_NVLINK_L6_TX_PER_SEC = 75, //!< NvLink write bandwidth for link 6 in MiB/sec + NVML_GPM_METRIC_NVLINK_L7_RX_PER_SEC = 76, //!< NvLink read bandwidth for link 7 in MiB/sec + NVML_GPM_METRIC_NVLINK_L7_TX_PER_SEC = 77, //!< NvLink write bandwidth for link 7 in MiB/sec + NVML_GPM_METRIC_NVLINK_L8_RX_PER_SEC = 78, //!< NvLink read bandwidth for link 8 in MiB/sec + NVML_GPM_METRIC_NVLINK_L8_TX_PER_SEC = 79, //!< NvLink write bandwidth for link 8 in MiB/sec + NVML_GPM_METRIC_NVLINK_L9_RX_PER_SEC = 80, //!< NvLink read bandwidth for link 9 in MiB/sec + NVML_GPM_METRIC_NVLINK_L9_TX_PER_SEC = 81, //!< NvLink write bandwidth for link 9 in MiB/sec + NVML_GPM_METRIC_NVLINK_L10_RX_PER_SEC = 82, //!< NvLink read bandwidth for link 10 in MiB/sec + NVML_GPM_METRIC_NVLINK_L10_TX_PER_SEC = 83, //!< NvLink write bandwidth for link 10 in MiB/sec + NVML_GPM_METRIC_NVLINK_L11_RX_PER_SEC = 84, //!< NvLink read bandwidth for link 11 in MiB/sec + NVML_GPM_METRIC_NVLINK_L11_TX_PER_SEC = 85, //!< NvLink write bandwidth for link 11 in MiB/sec + NVML_GPM_METRIC_NVLINK_L12_RX_PER_SEC = 86, //!< NvLink read bandwidth for link 12 in MiB/sec + NVML_GPM_METRIC_NVLINK_L12_TX_PER_SEC = 87, //!< NvLink write bandwidth for link 12 in MiB/sec + NVML_GPM_METRIC_NVLINK_L13_RX_PER_SEC = 88, //!< NvLink read bandwidth for link 13 in MiB/sec + NVML_GPM_METRIC_NVLINK_L13_TX_PER_SEC = 89, //!< NvLink write bandwidth for link 13 in MiB/sec + NVML_GPM_METRIC_NVLINK_L14_RX_PER_SEC = 90, //!< NvLink read bandwidth for link 14 in MiB/sec + NVML_GPM_METRIC_NVLINK_L14_TX_PER_SEC = 91, //!< NvLink write bandwidth for link 14 in MiB/sec + NVML_GPM_METRIC_NVLINK_L15_RX_PER_SEC = 92, //!< NvLink read bandwidth for link 15 in MiB/sec + NVML_GPM_METRIC_NVLINK_L15_TX_PER_SEC = 93, //!< NvLink write bandwidth for link 15 in MiB/sec + NVML_GPM_METRIC_NVLINK_L16_RX_PER_SEC = 94, //!< NvLink read bandwidth for link 16 in MiB/sec + NVML_GPM_METRIC_NVLINK_L16_TX_PER_SEC = 95, //!< NvLink write bandwidth for link 16 in MiB/sec + NVML_GPM_METRIC_NVLINK_L17_RX_PER_SEC = 96, //!< NvLink read bandwidth for link 17 in MiB/sec + NVML_GPM_METRIC_NVLINK_L17_TX_PER_SEC = 97, //!< NvLink write bandwidth for link 17 in MiB/sec + //Put new metrics for BLACKWELL here... + NVML_GPM_METRIC_C2C_TOTAL_TX_PER_SEC = 100, + NVML_GPM_METRIC_C2C_TOTAL_RX_PER_SEC = 101, + NVML_GPM_METRIC_C2C_DATA_TX_PER_SEC = 102, + NVML_GPM_METRIC_C2C_DATA_RX_PER_SEC = 103, + NVML_GPM_METRIC_C2C_LINK0_TOTAL_TX_PER_SEC = 104, + NVML_GPM_METRIC_C2C_LINK0_TOTAL_RX_PER_SEC = 105, + NVML_GPM_METRIC_C2C_LINK0_DATA_TX_PER_SEC = 106, + NVML_GPM_METRIC_C2C_LINK0_DATA_RX_PER_SEC = 107, + NVML_GPM_METRIC_C2C_LINK1_TOTAL_TX_PER_SEC = 108, + NVML_GPM_METRIC_C2C_LINK1_TOTAL_RX_PER_SEC = 109, + NVML_GPM_METRIC_C2C_LINK1_DATA_TX_PER_SEC = 110, + NVML_GPM_METRIC_C2C_LINK1_DATA_RX_PER_SEC = 111, + NVML_GPM_METRIC_C2C_LINK2_TOTAL_TX_PER_SEC = 112, + NVML_GPM_METRIC_C2C_LINK2_TOTAL_RX_PER_SEC = 113, + NVML_GPM_METRIC_C2C_LINK2_DATA_TX_PER_SEC = 114, + NVML_GPM_METRIC_C2C_LINK2_DATA_RX_PER_SEC = 115, + NVML_GPM_METRIC_C2C_LINK3_TOTAL_TX_PER_SEC = 116, + NVML_GPM_METRIC_C2C_LINK3_TOTAL_RX_PER_SEC = 117, + NVML_GPM_METRIC_C2C_LINK3_DATA_TX_PER_SEC = 118, + NVML_GPM_METRIC_C2C_LINK3_DATA_RX_PER_SEC = 119, + NVML_GPM_METRIC_C2C_LINK4_TOTAL_TX_PER_SEC = 120, + NVML_GPM_METRIC_C2C_LINK4_TOTAL_RX_PER_SEC = 121, + NVML_GPM_METRIC_C2C_LINK4_DATA_TX_PER_SEC = 122, + NVML_GPM_METRIC_C2C_LINK4_DATA_RX_PER_SEC = 123, + NVML_GPM_METRIC_C2C_LINK5_TOTAL_TX_PER_SEC = 124, + NVML_GPM_METRIC_C2C_LINK5_TOTAL_RX_PER_SEC = 125, + NVML_GPM_METRIC_C2C_LINK5_DATA_TX_PER_SEC = 126, + NVML_GPM_METRIC_C2C_LINK5_DATA_RX_PER_SEC = 127, + NVML_GPM_METRIC_C2C_LINK6_TOTAL_TX_PER_SEC = 128, + NVML_GPM_METRIC_C2C_LINK6_TOTAL_RX_PER_SEC = 129, + NVML_GPM_METRIC_C2C_LINK6_DATA_TX_PER_SEC = 130, + NVML_GPM_METRIC_C2C_LINK6_DATA_RX_PER_SEC = 131, + NVML_GPM_METRIC_C2C_LINK7_TOTAL_TX_PER_SEC = 132, + NVML_GPM_METRIC_C2C_LINK7_TOTAL_RX_PER_SEC = 133, + NVML_GPM_METRIC_C2C_LINK7_DATA_TX_PER_SEC = 134, + NVML_GPM_METRIC_C2C_LINK7_DATA_RX_PER_SEC = 135, + NVML_GPM_METRIC_C2C_LINK8_TOTAL_TX_PER_SEC = 136, + NVML_GPM_METRIC_C2C_LINK8_TOTAL_RX_PER_SEC = 137, + NVML_GPM_METRIC_C2C_LINK8_DATA_TX_PER_SEC = 138, + NVML_GPM_METRIC_C2C_LINK8_DATA_RX_PER_SEC = 139, + NVML_GPM_METRIC_C2C_LINK9_TOTAL_TX_PER_SEC = 140, + NVML_GPM_METRIC_C2C_LINK9_TOTAL_RX_PER_SEC = 141, + NVML_GPM_METRIC_C2C_LINK9_DATA_TX_PER_SEC = 142, + NVML_GPM_METRIC_C2C_LINK9_DATA_RX_PER_SEC = 143, + NVML_GPM_METRIC_C2C_LINK10_TOTAL_TX_PER_SEC = 144, + NVML_GPM_METRIC_C2C_LINK10_TOTAL_RX_PER_SEC = 145, + NVML_GPM_METRIC_C2C_LINK10_DATA_TX_PER_SEC = 146, + NVML_GPM_METRIC_C2C_LINK10_DATA_RX_PER_SEC = 147, + NVML_GPM_METRIC_C2C_LINK11_TOTAL_TX_PER_SEC = 148, + NVML_GPM_METRIC_C2C_LINK11_TOTAL_RX_PER_SEC = 149, + NVML_GPM_METRIC_C2C_LINK11_DATA_TX_PER_SEC = 150, + NVML_GPM_METRIC_C2C_LINK11_DATA_RX_PER_SEC = 151, + NVML_GPM_METRIC_C2C_LINK12_TOTAL_TX_PER_SEC = 152, + NVML_GPM_METRIC_C2C_LINK12_TOTAL_RX_PER_SEC = 153, + NVML_GPM_METRIC_C2C_LINK12_DATA_TX_PER_SEC = 154, + NVML_GPM_METRIC_C2C_LINK12_DATA_RX_PER_SEC = 155, + NVML_GPM_METRIC_C2C_LINK13_TOTAL_TX_PER_SEC = 156, + NVML_GPM_METRIC_C2C_LINK13_TOTAL_RX_PER_SEC = 157, + NVML_GPM_METRIC_C2C_LINK13_DATA_TX_PER_SEC = 158, + NVML_GPM_METRIC_C2C_LINK13_DATA_RX_PER_SEC = 159, + NVML_GPM_METRIC_HOSTMEM_CACHE_HIT = 160, + NVML_GPM_METRIC_HOSTMEM_CACHE_MISS = 161, + NVML_GPM_METRIC_PEERMEM_CACHE_HIT = 162, + NVML_GPM_METRIC_PEERMEM_CACHE_MISS = 163, + NVML_GPM_METRIC_DRAM_CACHE_HIT = 164, + NVML_GPM_METRIC_DRAM_CACHE_MISS = 165, + NVML_GPM_METRIC_NVENC_0_UTIL = 166, + NVML_GPM_METRIC_NVENC_1_UTIL = 167, + NVML_GPM_METRIC_NVENC_2_UTIL = 168, + NVML_GPM_METRIC_NVENC_3_UTIL = 169, + NVML_GPM_METRIC_GR0_CTXSW_CYCLES_ELAPSED = 170, + NVML_GPM_METRIC_GR0_CTXSW_CYCLES_ACTIVE = 171, + NVML_GPM_METRIC_GR0_CTXSW_REQUESTS = 172, + NVML_GPM_METRIC_GR0_CTXSW_CYCLES_PER_REQ = 173, + NVML_GPM_METRIC_GR0_CTXSW_ACTIVE_PCT = 174, + NVML_GPM_METRIC_GR1_CTXSW_CYCLES_ELAPSED = 175, + NVML_GPM_METRIC_GR1_CTXSW_CYCLES_ACTIVE = 176, + NVML_GPM_METRIC_GR1_CTXSW_REQUESTS = 177, + NVML_GPM_METRIC_GR1_CTXSW_CYCLES_PER_REQ = 178, + NVML_GPM_METRIC_GR1_CTXSW_ACTIVE_PCT = 179, + NVML_GPM_METRIC_GR2_CTXSW_CYCLES_ELAPSED = 180, + NVML_GPM_METRIC_GR2_CTXSW_CYCLES_ACTIVE = 181, + NVML_GPM_METRIC_GR2_CTXSW_REQUESTS = 182, + NVML_GPM_METRIC_GR2_CTXSW_CYCLES_PER_REQ = 183, + NVML_GPM_METRIC_GR2_CTXSW_ACTIVE_PCT = 184, + NVML_GPM_METRIC_GR3_CTXSW_CYCLES_ELAPSED = 185, + NVML_GPM_METRIC_GR3_CTXSW_CYCLES_ACTIVE = 186, + NVML_GPM_METRIC_GR3_CTXSW_REQUESTS = 187, + NVML_GPM_METRIC_GR3_CTXSW_CYCLES_PER_REQ = 188, + NVML_GPM_METRIC_GR3_CTXSW_ACTIVE_PCT = 189, + NVML_GPM_METRIC_GR4_CTXSW_CYCLES_ELAPSED = 190, + NVML_GPM_METRIC_GR4_CTXSW_CYCLES_ACTIVE = 191, + NVML_GPM_METRIC_GR4_CTXSW_REQUESTS = 192, + NVML_GPM_METRIC_GR4_CTXSW_CYCLES_PER_REQ = 193, + NVML_GPM_METRIC_GR4_CTXSW_ACTIVE_PCT = 194, + NVML_GPM_METRIC_GR5_CTXSW_CYCLES_ELAPSED = 195, + NVML_GPM_METRIC_GR5_CTXSW_CYCLES_ACTIVE = 196, + NVML_GPM_METRIC_GR5_CTXSW_REQUESTS = 197, + NVML_GPM_METRIC_GR5_CTXSW_CYCLES_PER_REQ = 198, + NVML_GPM_METRIC_GR5_CTXSW_ACTIVE_PCT = 199, + NVML_GPM_METRIC_GR6_CTXSW_CYCLES_ELAPSED = 200, + NVML_GPM_METRIC_GR6_CTXSW_CYCLES_ACTIVE = 201, + NVML_GPM_METRIC_GR6_CTXSW_REQUESTS = 202, + NVML_GPM_METRIC_GR6_CTXSW_CYCLES_PER_REQ = 203, + NVML_GPM_METRIC_GR6_CTXSW_ACTIVE_PCT = 204, + NVML_GPM_METRIC_GR7_CTXSW_CYCLES_ELAPSED = 205, + NVML_GPM_METRIC_GR7_CTXSW_CYCLES_ACTIVE = 206, + NVML_GPM_METRIC_GR7_CTXSW_REQUESTS = 207, + NVML_GPM_METRIC_GR7_CTXSW_CYCLES_PER_REQ = 208, + NVML_GPM_METRIC_GR7_CTXSW_ACTIVE_PCT = 209, + NVML_GPM_METRIC_MAX = 210, //!< Maximum value above +1. Note that changing this should also change NVML_GPM_METRICS_GET_VERSION due to struct size change +} nvmlGpmMetricId_t; + +/** @} */ // @defgroup nvmlGpmEnums + + +/***************************************************************************************************/ +/** @defgroup nvmlGpmStructs GPM Structs + * @{ + */ +/***************************************************************************************************/ + +/** + * Handle to an allocated GPM sample allocated with nvmlGpmSampleAlloc(). Free this with nvmlGpmSampleFree(). + */ +typedef struct nvmlGpmSample_st* nvmlGpmSample_t; + +/** + * GPM metric information. + */ +typedef struct +{ + unsigned int metricId; //!< IN: NVML_GPM_METRIC_? define of which metric to retrieve + nvmlReturn_t nvmlReturn; //!< OUT: Status of this metric. If this is nonzero, then value is not valid + double value; //!< OUT: Value of this metric. Is only valid if nvmlReturn is 0 (NVML_SUCCESS) + struct + { + char *shortName; + char *longName; + char *unit; + } metricInfo; //!< OUT: Metric name and unit. Those can be NULL if not defined +} nvmlGpmMetric_t; + +/** + * GPM buffer information. + */ +typedef struct +{ + unsigned int version; //!< IN: Set to NVML_GPM_METRICS_GET_VERSION + unsigned int numMetrics; //!< IN: How many metrics to retrieve in metrics[] + nvmlGpmSample_t sample1; //!< IN: Sample buffer + nvmlGpmSample_t sample2; //!< IN: Sample buffer + nvmlGpmMetric_t metrics[NVML_GPM_METRIC_MAX]; //!< IN/OUT: Array of metrics. Set metricId on call. See nvmlReturn and value on return +} nvmlGpmMetricsGet_t; + +#define NVML_GPM_METRICS_GET_VERSION 1 + +/** + * GPM device information. + */ +typedef struct +{ + unsigned int version; //!< IN: Set to NVML_GPM_SUPPORT_VERSION + unsigned int isSupportedDevice; //!< OUT: Indicates device support +} nvmlGpmSupport_t; + +#define NVML_GPM_SUPPORT_VERSION 1 + +/** @} */ // @defgroup nvmlGPMStructs + +/***************************************************************************************************/ +/** @defgroup nvmlGpmFunctions GPM Functions + * @{ + */ +/***************************************************************************************************/ + +/** + * Calculate GPM metrics from two samples. + * + * For Hopper &tm; or newer fully supported devices. + * + * To retrieve metrics, the user must first allocate the two sample buffers at \a metricsGet->sample1 + * and \a metricsGet->sample2 by calling \a nvmlGpmSampleAlloc(). Next, the user should fill in the ID of each metric + * in \a metricsGet->metrics[i].metricId and specify the total number of metrics to retrieve in \a metricsGet->numMetrics, + * The version should be set to NVML_GPM_METRICS_GET_VERSION in \a metricsGet->version. The user then calls the + * \a nvmlGpmSampleGet() API twice to obtain 2 samples of counters. + * + * @note The interval between these two \a nvmlGpmSampleGet() calls should be greater than 100ms due to the + * internal sample refresh rate. Finally, the user calls \a nvmlGpmMetricsGet to retrieve the metrics, which will + * be stored at \a metricsGet->metrics + * + * + * @param metricsGet IN/OUT: populated \a nvmlGpmMetricsGet_t struct + * + * @return + * - \ref NVML_SUCCESS on success + * - Nonzero NVML_ERROR_? enum on error + */ +nvmlReturn_t DECLDIR nvmlGpmMetricsGet(nvmlGpmMetricsGet_t *metricsGet); + + +/** + * Free an allocated sample buffer that was allocated with \ref nvmlGpmSampleAlloc() + * + * For Hopper &tm; or newer fully supported devices. + * + * @param gpmSample Sample to free + * + * @return + * - \ref NVML_SUCCESS on success + * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid pointer is provided + */ +nvmlReturn_t DECLDIR nvmlGpmSampleFree(nvmlGpmSample_t gpmSample); + + +/** + * Allocate a sample buffer to be used with NVML GPM . You will need to allocate + * at least two of these buffers to use with the NVML GPM feature + * + * For Hopper &tm; or newer fully supported devices. + * + * @param gpmSample Where the allocated sample will be stored + * + * @return + * - \ref NVML_SUCCESS on success + * - \ref NVML_ERROR_INVALID_ARGUMENT if an invalid pointer is provided + * - \ref NVML_ERROR_MEMORY if system memory is insufficient + */ +nvmlReturn_t DECLDIR nvmlGpmSampleAlloc(nvmlGpmSample_t *gpmSample); + +/** + * Read a sample of GPM metrics into the provided \a gpmSample buffer. After + * two samples are gathered, you can call nvmlGpmMetricGet on those samples to + * retrive metrics + * + * For Hopper &tm; or newer fully supported devices. + * + * @note The interval between two \a nvmlGpmSampleGet() calls should be greater than 100ms due to + * the internal sample refresh rate. + * + * @param device Device to get samples for + * @param gpmSample Buffer to read samples into + * + * @return + * - \ref NVML_SUCCESS on success + * - Nonzero NVML_ERROR_? enum on error + */ +nvmlReturn_t DECLDIR nvmlGpmSampleGet(nvmlDevice_t device, nvmlGpmSample_t gpmSample); + +/** + * Read a sample of GPM metrics into the provided \a gpmSample buffer for a MIG GPU Instance. + * + * After two samples are gathered, you can call nvmlGpmMetricGet on those + * samples to retrive metrics + * + * For Hopper &tm; or newer fully supported devices. + * + * @note The interval between two \a nvmlGpmMigSampleGet() calls should be greater than 100ms due to + * the internal sample refresh rate. + * + * @param device Device to get samples for + * @param gpuInstanceId MIG GPU Instance ID + * @param gpmSample Buffer to read samples into + * + * @return + * - \ref NVML_SUCCESS on success + * - Nonzero NVML_ERROR_? enum on error + */ +nvmlReturn_t DECLDIR nvmlGpmMigSampleGet(nvmlDevice_t device, unsigned int gpuInstanceId, nvmlGpmSample_t gpmSample); + +/** + * Indicate whether the supplied device supports GPM + * + * For Hopper &tm; or newer fully supported devices. + * + * @param device NVML device to query for + * @param gpmSupport Structure to indicate GPM support \a nvmlGpmSupport_t. Indicates + * GPM support per system for the supplied device + * + * @return + * - NVML_SUCCESS on success + * - Nonzero NVML_ERROR_? enum if there is an error in processing the query + */ +nvmlReturn_t DECLDIR nvmlGpmQueryDeviceSupport(nvmlDevice_t device, nvmlGpmSupport_t *gpmSupport); + +/* GPM Stream State */ +/** + * Get GPM stream state. + * + * For Hopper &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param device The identifier of the target device + * @param state Returns GPM stream state + * NVML_FEATURE_DISABLED or NVML_FEATURE_ENABLED + * + * @return + * - \ref NVML_SUCCESS if \a current GPM stream state were successfully queried + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a state is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlGpmQueryIfStreamingEnabled(nvmlDevice_t device, unsigned int *state); + +/** + * Set GPM stream state. + * + * For Hopper &tm; or newer fully supported devices. + * Supported on Linux, Windows TCC. + * + * @param device The identifier of the target device + * @param state GPM stream state, + * NVML_FEATURE_DISABLED or NVML_FEATURE_ENABLED + * + * @return + * - \ref NVML_SUCCESS if \a current GPM stream state is successfully set + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid + * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device + */ +nvmlReturn_t DECLDIR nvmlGpmSetStreamingEnabled(nvmlDevice_t device, unsigned int state); + +/** @} */ // @defgroup nvmlGpmFunctions +/** @} */ // @defgroup GPM + +#define NVML_DEV_CAP_EGM (1 << 0) // Extended GPU memory +/** + * Device capabilities + */ +typedef struct +{ + unsigned int version; //!< the API version number + unsigned int capMask; //!< OUT: Bit mask of capabilities. +} nvmlDeviceCapabilities_v1_t; +typedef nvmlDeviceCapabilities_v1_t nvmlDeviceCapabilities_t; +#define nvmlDeviceCapabilities_v1 NVML_STRUCT_VERSION(DeviceCapabilities, 1) + +/** + * Get device capabilities + * + * See \ref nvmlDeviceCapabilities_v1_t for more information on the struct. + * + * @param device The identifier of the target device + * @param caps Returns GPU's capabilities + * + * @return + * - \ref NVML_SUCCESS If the query is success + * - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid or \a counters is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED If the device does not support this feature + * - \ref NVML_ERROR_GPU_IS_LOST If the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH If the provided version is invalid/unsupported + * - \ref NVML_ERROR_UNKNOWN On any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetCapabilities(nvmlDevice_t device, + nvmlDeviceCapabilities_t *caps); + + +/* + * Generic bitmask to hold 255 bits, represented by 8 elements of 32 bits + */ +#define NVML_255_MASK_BITS_PER_ELEM 32 +#define NVML_255_MASK_NUM_ELEMS 8 +#define NVML_255_MASK_BIT_SET(index, nvmlMask) \ + nvmlMask.mask[index / NVML_255_MASK_BITS_PER_ELEM] |= (1 << (index % NVML_255_MASK_BITS_PER_ELEM)) + +#define NVML_255_MASK_BIT_GET(index, nvmlMask) \ + nvmlMask.mask[index / NVML_255_MASK_BITS_PER_ELEM] & (1 << (index % NVML_255_MASK_BITS_PER_ELEM)) + +#define NVML_255_MASK_BIT_SET_PTR(index, nvmlMask) \ + nvmlMask->mask[index / NVML_255_MASK_BITS_PER_ELEM] |= (1 << (index % NVML_255_MASK_BITS_PER_ELEM)) + +#define NVML_255_MASK_BIT_GET_PTR(index, nvmlMask) \ + nvmlMask->mask[index / NVML_255_MASK_BITS_PER_ELEM] & (1 << (index % NVML_255_MASK_BITS_PER_ELEM)) + +typedef struct +{ + unsigned int mask[NVML_255_MASK_NUM_ELEMS]; //profileId is used and + * the rest of the structure is ignored. + * + * @return + * - \ref NVML_SUCCESS if the Desired Profile was successfully set + * - \ref NVML_ERROR_INVALID_ARGUMENT if device is invalid or structure was NULL + * - \ref NVML_ERROR_NO_PERMISSION if user does not have permission to change the profile number + * - \ref NVML_ERROR_NOT_SUPPORTED if this feature is not supported by the device + * + **/ +nvmlReturn_t DECLDIR nvmlDevicePowerSmoothingActivatePresetProfile(nvmlDevice_t device, + nvmlPowerSmoothingProfile_t *profile); + +/** + * Update the value of a specific profile parameter contained within \ref nvmlPowerSmoothingProfile_v1_t. + * Requires root/admin permissions. + * + * For Blackwell &tm; or newer fully supported devices. + * + * NVML_POWER_SMOOTHING_PROFILE_PARAM_PERCENT_TMP_FLOOR expects a value as a percentage from 00.00-100.00% + * NVML_POWER_SMOOTHING_PROFILE_PARAM_RAMP_UP_RATE expects a value in W/s + * NVML_POWER_SMOOTHING_PROFILE_PARAM_RAMP_DOWN_RATE expects a value in W/s + * NVML_POWER_SMOOTHING_PROFILE_PARAM_RAMP_DOWN_HYSTERESIS expects a value in ms + * + * @param device The identifier of the target device + * @param profile Reference to \ref nvmlPowerSmoothingProfile_v1_t struct + * + * @return + * - \ref NVML_SUCCESS if the Active Profile was successfully set + * - \ref NVML_ERROR_INVALID_ARGUMENT if device is invalid or profile parameter/value was invalid + * - \ref NVML_ERROR_NO_PERMISSION if user does not have permission to change any profile parameters + * - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the structure version is not supported + * + **/ +nvmlReturn_t DECLDIR nvmlDevicePowerSmoothingUpdatePresetProfileParam(nvmlDevice_t device, + nvmlPowerSmoothingProfile_t *profile); +/** + * Enable or disable the Power Smoothing Feature. + * Requires root/admin permissions. + * + * For Blackwell &tm; or newer fully supported devices. + * + * See \ref nvmlEnableState_t for details on allowed states + * + * @param device The identifier of the target device + * @param state Reference to \ref nvmlPowerSmoothingState_v1_t + * + * @return + * - \ref NVML_SUCCESS if the feature state was successfully set + * - \ref NVML_ERROR_INVALID_ARGUMENT if device is invalid or state is NULL + * - \ref NVML_ERROR_NO_PERMISSION if user does not have permission to change feature state + * - \ref NVML_ERROR_NOT_SUPPORTED if this feature is not supported by the device + * + **/ +nvmlReturn_t DECLDIR nvmlDevicePowerSmoothingSetState(nvmlDevice_t device, + nvmlPowerSmoothingState_t *state); +/** @} */ // @defgroup + +/** + * Retrieves the counts of SRAM unique uncorrected ECC errors + * + * For Blackwell &tm; or newer fully supported devices. + * + * Reads SRAM unique uncorrected ECC error counts. The total number of unique errors is returned by + * \a errorCounts->entryCount. Error counts are returned as an array of in the caller-supplied buffer pointed at by + * \a errorCounts->entries. Each error count entry holds the location/address of the unique error, the error count and + * whether the error is parity or not. + * + * To read SRAM unique uncorrected ECC error counts, first determine the size of buffer required to hold the error + * counts by invoking the function with \a errorCounts->entries set to NULL. The required array size is returned in + * \a errorCounts->entryCount. The caller should allocate a buffer of size "errorCounts->entryCount * + * sizeof(nvmlEccSramUniqueUncorrectedErrorCounts_t)". Invoke the function again with the allocated buffer passed in + * \a errorCounts->entries. This time \a errorCounts->entryCount will be taken as the entry array size that caller + * allocates for \a errorCounts->entries. + * + * On successful return of the second query, the function updates \a errorCounts->entries with all unique errors. This + * may fail if \a errorCounts->entryCount is smaller than the actual number of unique errors. This can happen in cases + * like new errors occur since the previous query of \a errorCounts->entryCount. No matter the query succeeds or not, + * the latest number of unique errors will be returned in \a errorCounts->entryCount. + * + * @note The query is only supported when ECC mode is enabled. + * + * @param device The identifier of the target device + * @param errorCounts Pointer to caller-supplied array which returns the unique error count entries + * + * @return + * - \ref NVML_SUCCESS if \a utilization has been populated + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a errorCounts->entryCount is NULL + * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature or ECC mods is not enabled + * - \ref NVML_ERROR_INSUFFICIENT_SIZE if the allocated error entry array is not big enough + * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetSramUniqueUncorrectedEccErrorCounts(nvmlDevice_t device, + nvmlEccSramUniqueUncorrectedErrorCounts_t *errorCounts); + +/** + * NVML API versioning support + */ + +#ifdef NVML_NO_UNVERSIONED_FUNC_DEFS +nvmlReturn_t DECLDIR nvmlInit(void); +nvmlReturn_t DECLDIR nvmlDeviceGetCount(unsigned int *deviceCount); +nvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex(unsigned int index, nvmlDevice_t *device); +nvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId(const char *pciBusId, nvmlDevice_t *device); +nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo(nvmlDevice_t device, nvmlPciInfo_t *pci); +nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo_v2(nvmlDevice_t device, nvmlPciInfo_t *pci); +nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci); +nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); +nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures_v2(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); +nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures_v3(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); +nvmlReturn_t DECLDIR nvmlDeviceRemoveGpu(nvmlPciInfo_t *pciInfo); +nvmlReturn_t DECLDIR nvmlEventSetWait(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms); +nvmlReturn_t DECLDIR nvmlDeviceGetAttributes(nvmlDevice_t device, nvmlDeviceAttributes_t *attributes); +nvmlReturn_t DECLDIR nvmlComputeInstanceGetInfo(nvmlComputeInstance_t computeInstance, nvmlComputeInstanceInfo_t *info); +nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v1_t *infos); +nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses_v2(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v2_t *infos); +nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v1_t *infos); +nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses_v2(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v2_t *infos); +nvmlReturn_t DECLDIR nvmlDeviceGetMPSComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v1_t *infos); +nvmlReturn_t DECLDIR nvmlDeviceGetMPSComputeRunningProcesses_v2(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_v2_t *infos); +nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstancePossiblePlacements(nvmlDevice_t device, unsigned int profileId, nvmlGpuInstancePlacement_t *placements, unsigned int *count); +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseInfo(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuLicenseInfo_t *licenseInfo); +nvmlReturn_t DECLDIR nvmlDeviceGetDriverModel(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending); +#endif // #ifdef NVML_NO_UNVERSIONED_FUNC_DEFS + +#if defined(NVML_NO_UNVERSIONED_FUNC_DEFS) +// We don't define APIs to run new versions if this guard is present so there is +// no need to undef +#elif defined(__NVML_API_VERSION_INTERNAL) +#undef nvmlDeviceGetGraphicsRunningProcesses +#undef nvmlDeviceGetComputeRunningProcesses +#undef nvmlDeviceGetMPSComputeRunningProcesses +#undef nvmlDeviceGetAttributes +#undef nvmlComputeInstanceGetInfo +#undef nvmlEventSetWait +#undef nvmlDeviceGetGridLicensableFeatures +#undef nvmlDeviceRemoveGpu +#undef nvmlDeviceGetNvLinkRemotePciInfo +#undef nvmlDeviceGetPciInfo +#undef nvmlDeviceGetCount +#undef nvmlDeviceGetHandleByIndex +#undef nvmlDeviceGetHandleByPciBusId +#undef nvmlInit +#undef nvmlBlacklistDeviceInfo_t +#undef nvmlGetBlacklistDeviceCount +#undef nvmlGetBlacklistDeviceInfoByIndex +#undef nvmlDeviceGetGpuInstancePossiblePlacements +#undef nvmlVgpuInstanceGetLicenseInfo +#undef nvmlDeviceGetDriverModel +#undef nvmlDeviceSetPowerManagementLimit + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkgs/cuda-13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.a b/pkgs/cuda-13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.a new file mode 100644 index 0000000000000000000000000000000000000000..2bbacd8fd8f49767e01c9adbd66d2a32416a4a4f GIT binary patch literal 557156 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

>=Uw>jTk=~I4@dzkZgi(g?ppXWSi-Q;9E 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 Pk&=I}CI9=srTPB{Z_=_5 literal 0 HcmV?d00001 diff --git a/pkgs/cuda-13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.so b/pkgs/cuda-13.0/targets/x86_64-linux/lib/stubs/libnvidia-ml.so new file mode 100755 index 0000000000000000000000000000000000000000..699c13c3acd9f2a161470be6aff2f8dd0f85321e GIT binary patch literal 71600 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/dev/null) + if [[ $rotational -eq 0 ]]; then + echo 2 + return + fi + + local transport=$(lsblk -d -o NAME,TRAN /dev/$disk 2>/dev/null | grep $disk | awk '{print $2}') + if [[ $transport == "sas" ]]; then + echo 3 + else + echo 4 # SATA OR OTHER + fi +} + +get_disk_size() { + local disk=$1 + cat /sys/block/$disk/size 2>/dev/null +} + +is_installed_node() { + local disks=$(lsblk -d -n -o NAME,TYPE | grep disk | awk '{print $1}') + + for disk in $disks; do + local partitions=$(lsblk -n -o NAME /dev/$disk | grep -E "^${disk}p?[0-9]+" || true) + + for part in $partitions; do + local mount_point="/mnt/tmp_${part}" + mkdir -p $mount_point 2>/dev/null + + if mount -t ext4 -o ro /dev/$part $mount_point 2>/dev/null || \ + mount -t xfs -o ro /dev/$part $mount_point 2>/dev/null; then + + if [[ -f $mount_point/.sunhpc-release ]]; then + umount $mount_point + rmdir $mount_point 2>/dev/null + echo "yes" + return 0 + fi + umount $mount_point + fi + rmdir $mount_point 2>/dev/null + done + done + + echo "no" +} + +select_best_disk() { + local disks=() + + for disk in /sys/block/*; do + local disk_name=$(basename $disk) + if [[ $disk_name =~ ^(loop|zram|ram|sr|fd|dm-) ]]; then + continue + fi + if [[ -e /dev/$disk_name ]] && [[ $(cat /sys/block/$disk_name/removable 2>/dev/null) -eq 0 ]]; then + disks+=($disk_name) + fi + done + + if [[ ${#disks[@]} -eq 0 ]]; then + echo "" + return 1 + fi + + declare -A disk_priority + declare -A disk_size + + for disk in "${disks[@]}"; do + disk_priority[$disk]=$(get_disk_priority $disk) + disk_size[$disk]=$(get_disk_size $disk) + done + + local sorted_disks=($(for disk in "${disks[@]}"; do + echo "${disk_priority[$disk]}:${disk_size[$disk]}:$disk" + done | sort -n -t: -k1,1 -k2,2rn | cut -d: -f3)) + + echo "${sorted_disks[0]}" +} + +# 智能计算 Root 分区大小 +# 参数: $1 = 磁盘总大小(GB), $2 = 期望的默认大小(GB) +# 返回: 合适的 root 分区大小(GB) +calculate_root_size() { + local disk_total_gb=$1 + local default_root_gb=${2:-70} + local min_root_gb=30 + local max_root_gb=100 + + # 如果磁盘总容量小于最小要求(70GB + boot + swap = 约75GB) + if [[ $disk_total_gb -lt 75 ]]; then + # 磁盘太小,使用最小 root 分区 + echo $min_root_gb + elif [[ $disk_total_gb -lt 100 ]]; then + # 磁盘在 75-100GB 之间,使用 40-50GB + echo $((disk_total_gb - 45)) # 预留 boot+swap+state 空间 + elif [[ $disk_total_gb -lt 150 ]]; then + # 磁盘在 100-150GB 之间,使用 60GB + echo 60 + elif [[ $disk_total_gb -lt 250 ]]; then + # 磁盘在 150-250GB 之间,使用默认 70GB + echo $default_root_gb + else + # 大磁盘,限制最大 100GB + echo $max_root_gb + fi +} + +calculate_state_size() { + local disk_total_sectors=$1 + local root_size_sectors=$2 + echo $((disk_total_sectors - root_size_sectors)) +} + +get_disk_size_gb() { + local disk=$1 + local total_sectors=$(cat /sys/block/$disk/size 2>/dev/null) + local total_gb=$((total_sectors * 512 / 1024 / 1024 / 1024)) + echo $total_gb +} + +get_disk_type() { + local disk=$1 + + if [[ $disk == nvme* ]]; then + echo "NVMe" + elif [[ $(cat /sys/block/$disk/queue/rotational 2>/dev/null) -eq 0 ]]; then + echo "SSD" + else + local transport=$(lsblk -d -o NAME,TRAN /dev/$disk 2>/dev/null | grep $disk | awk '{print $2}') + if [[ $transport == "sas" ]]; then + echo "SAS" + else + echo "SATA" + fi + fi +} + +generate_ks_partition() { + local disk=$1 + local is_upgrade=$2 + + # 获取磁盘总容量(扇区和GB) + local total_sectors=$(cat /sys/block/$disk/size) + local total_gb=$(get_disk_size_gb $disk) + local disk_type=$(get_disk_type $disk) + + # 智能计算 root 分区大小 + local root_gb=$(calculate_root_size $total_gb 70) + local root_size_sectors=$((root_gb * 1024 * 1024 * 1024 / 512)) + + # 计算剩余空间给 state 分区 + local remaining_sectors=$((total_sectors - root_size_sectors)) + local remaining_gb=$((remaining_sectors * 512 / 1024 / 1024 / 1024)) + + # 计算 boot 和 swap 预留空间 + local boot_gb=1 + local swap_gb=4 + local reserved_gb=$((boot_gb + swap_gb)) + + cat << EOF +# ================================================== +# Disk Partition Information +# ================================================== +# Installation Type : $([ "$is_upgrade" == "yes" ] && echo "Upgrade" || echo "Fresh") Installation +# Disk Device : /dev/$disk +# Disk Type : $disk_type +# Disk Total : $total_gb GB ($total_sectors sectors) +# +# Partition Plan: +# - /boot : ${boot_gb}GB (reserved) +# - swap : ${swap_gb}GB (reserved) +# - / : ${root_gb}GB ($root_size_sectors sectors) +# - /state : ${remaining_gb}GB ($remaining_sectors sectors) +# ================================================== +EOF + + cat << EOF +zerombr +ignoredisk --only-use=$disk +clearpart --all --initlabel +part /boot --fstype="xfs" --size=1024 --ondisk=$disk +part swap --fstype="swap" --size=4096 --ondisk=$disk +part / --fstype="xfs" --size=$((root_gb * 1024)) --ondisk=$disk +EOF + + if [[ $is_upgrade == "yes" ]]; then + cat << EOF +part /state/partition1 --fstype=xfs --size=1 --grow --ondisk=$disk +EOF + fi +} + +main() { + local is_installed=$(is_installed_node) + + if [[ $is_installed == "yes" ]]; then + echo "# Detected: Already installed node (found .sunhpc-release)" + local found_disk="" + local disks=$(lsblk -d -n -o NAME,TYPE | grep disk | awk '{print $1}') + + for disk in $disks; do + local partitions=$(lsblk -n -o NAME /dev/$disk | grep -E "^${disk}p?[0-9]+" || true) + for part in $partitions; do + local mount_point="/mnt/tmp_${part}" + mkdir -p $mount_point 2>/dev/null + if mount -t ext4 -o ro /dev/$part $mount_point 2>/dev/null || \ + mount -t xfs -o ro /dev/$part $mount_point 2>/dev/null; then + if [[ -f $mount_point/.sunhpc-release ]]; then + found_disk=$disk + umount $mount_point + rmdir $mount_point 2>/dev/null + break 2 + fi + umount $mount_point + fi + rmdir $mount_point 2>/dev/null + done + done + + if [[ -n $found_disk ]]; then + echo "# Found existing installation on disk: /dev/$found_disk" + generate_ks_partition $found_disk "yes" + else + echo "# ERROR: Cannot find disk with .sunhpc-release, using default" + local best_disk=$(select_best_disk) + generate_ks_partition $best_disk "yes" + fi + else + echo "# Detected: Fresh installation" + local best_disk=$(select_best_disk) + + if [[ -z $best_disk ]]; then + echo "# ERROR: No disk found" + exit 1 + fi + + echo "# Selected best disk: /dev/$best_disk" + generate_ks_partition $best_disk "no" + fi +} + +main diff --git a/pkgs/ks/init.sh b/pkgs/ks/init.sh new file mode 100644 index 0000000..0c17134 --- /dev/null +++ b/pkgs/ks/init.sh @@ -0,0 +1,753 @@ +#!/bin/bash +# ============================================================================ +# Sun HPC 系统初始化脚本 +# 功能:系统安装完成后自动配置 HPC 计算节点环境 +# 版本:1.0 +# ============================================================================ + +set -e + +# ============================================================================ +# 配置变量(根据实际环境修改) +# ============================================================================ + +# 日志文件 +LOG_FILE="/var/log/sunhpc-init.log" + +FRONTEND_IP="172.16.9.254" + +# HTTP 服务器地址 +HTTP_SERVER="http://${FRONTEND_IP}" + +# YUM 仓库配置 +YUM_REPO_NAME="sunhpc-local" +YUM_REPO_BASEURL="${HTTP_SERVER}/rocky/9.7" +YUM_REPO_GPGCHECK=0 + +# 主机名映射文件(在 HTTP 服务器上) +HOSTNAME_MAP_URL="${HTTP_SERVER}/ks/hostname-map.txt" + +# MOTD 文件 URL +MOTD_URL="${HTTP_SERVER}/ks/motd" + +# NTP 服务器 +NTP_SERVER="ntp.aliyun.com" + +# DNS 服务器 +DNS_SERVERS="114.114.114.114 223.5.5.5" + +# ============================================================================ +# 颜色输出函数 +# ============================================================================ + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE +} + +log_step() { + echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE +} + +# ============================================================================ +# 基础环境准备 +# ============================================================================ + +init_log() { + # 创建日志文件 + touch $LOG_FILE + chmod 644 $LOG_FILE + log_info "==========================================" + log_info "Sun HPC Node Initialization Started" + log_info "==========================================" +} + +check_network() { + log_step "Checking network connectivity..." + + # 测试网络连接 + if ping -c 1 -W 3 172.16.9.254 &>/dev/null; then + log_info "Network connectivity: OK" + return 0 + else + log_warn "Cannot reach HTTP server, will retry later" + return 1 + fi +} + +# ============================================================================ +# 1. 创建 .sunhpc-release 文件 +# ============================================================================ + +create_release_file() { + log_step "Creating .sunhpc-release file..." + + cat > /.sunhpc-release << EOF +Sun HPC Platform Release 1.0 +Build Date: $(date '+%Y-%m-%d %H:%M:%S') +Hostname: $(hostname) +Kernel: $(uname -r) +Architecture: $(uname -m) +EOF + + chmod 644 /.sunhpc-release + log_info "Created /.sunhpc-release file" +} + +# ============================================================================ +# 2. 配置主机名和 /etc/hosts +# ============================================================================ + +configure_hostname() { + log_step "Configuring hostname and /etc/hosts..." + + local mac=$(ip link show | grep -oP 'ether \K[0-9a-f:]+' | head -1 | tr '[:upper:]' '[:lower:]') + local hostname="" + + # 从 HTTP 服务器获取主机名映射 + if check_network; then + # 下载主机名映射文件 + local map_file="/tmp/hostname-map.txt" + curl -s -o "$map_file" "$HOSTNAME_MAP_URL" 2>/dev/null + + if [[ -f "$map_file" ]]; then + # 根据 MAC 地址查找主机名 + hostname=$(grep -i "$mac" "$map_file" | awk '{print $2}' | head -1) + + # 如果没有找到,根据 IP 最后一段生成 + if [[ -z "$hostname" ]]; then + local ip_addr=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1) + local ip_last=$(echo $ip_addr | awk -F'.' '{print $4}') + hostname="cn$(printf "%03d" $ip_last)" + log_warn "No hostname mapping for MAC $mac, using generated: $hostname" + fi + else + log_warn "Cannot download hostname map, using default" + local ip_addr=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1) + local ip_last=$(echo $ip_addr | awk -F'.' '{print $4}') + hostname="cn$(printf "%03d" $ip_last)" + fi + else + # 网络不通时使用默认主机名 + hostname="node-$(hostname -s)" + fi + + # 设置主机名 + hostnamectl set-hostname "$hostname" + log_info "Hostname set to: $hostname" + + # 备份原始 hosts 文件 + cp /etc/hosts /etc/hosts.bak.$(date +%Y%m%d) + + # 构建新的 hosts 文件 + cat > /etc/hosts << EOF +127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 +::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 + +# Sun HPC Node Configuration +$ip_addr $hostname + +# Management Node +$FRONTEND_IP cluster + +# Optional: Add other compute nodes here +# 172.16.9.1 cn001 +# 172.16.9.2 cn002 +EOF + + # 尝试下载完整的集群 hosts 文件 + if check_network; then + local cluster_hosts="${HTTP_SERVER}/ks/cluster-hosts.txt" + if wget --spider -q "$cluster_hosts" 2>/dev/null; then + wget -q -O /tmp/cluster-hosts.txt "$cluster_hosts" + cat /tmp/cluster-hosts.txt >> /etc/hosts + log_info "Downloaded cluster hosts configuration" + else + log_warn "$cluster_hosts not found on server." + fi + fi + + log_info "Updated /etc/hosts" +} + +# ============================================================================ +# 3. 配置 MOTD (Message of The Day) +# ============================================================================ + +configure_motd() { + log_step "Configuring MOTD..." + + # 备份原始 MOTD + if [[ -f /etc/motd ]]; then + cp /etc/motd /etc/motd.bak.$(date +%Y%m%d) + fi + + # 尝试从服务器下载 MOTD + if check_network; then + if wget --spider -q "$MOTD_URL" 2>/dev/null; then + wget -q -O /etc/motd "$MOTD_URL" + log_info "Downloaded MOTD from server" + else + log_warn "Cannot download MOTD, creating default" + create_default_motd + fi + else + create_default_motd + fi + + chmod 644 /etc/motd +} + +create_default_motd() { + cat > /etc/motd << EOF +=========================================================== + Sun HPC Platform - Compute Node +=========================================================== + Welcome to Sun High Performance Computing Cluster + + System Information: + -------------------- + Hostname....: $(hostname) + IP Address..: $(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1) + OS Version..: $(cat /etc/redhat-release 2>/dev/null || echo "Rocky Linux") + Kernel......: $(uname -r) + Architecture: $(uname -m) + CPU Cores...: $(nproc) + Memory......: $(free -h | awk '/^Mem:/{print $2}') + + Important URLs: + -------------------- + • Documentation : http://172.16.9.254/docs + • Job Submission : http://172.16.9.254/slurm + • Monitoring: http : http://172.16.9.254/monitor + + Slurm Commands: + -------------------- + sinfo - View partition information + squeue - View job queue + srun - Run interactive job + sbatch - Submit batch job + scancel - Cancel job + +=========================================================== + * Unauthorized access is prohibited + * All activities are logged and monitored + * For support: hpc@sun.com or ext. 12345 +=========================================================== +EOF +} + +# ============================================================================ +# 4. 配置 YUM 本地仓库 +# ============================================================================ + +configure_yum_repo() { + log_step "Configuring YUM repository..." + + local repo_file="/etc/yum.repos.d/${YUM_REPO_NAME}.repo" + + # 备份现有 repo 文件 + if [[ -f "$repo_file" ]]; then + cp "$repo_file" "${repo_file}.bak.$(date +%Y%m%d)" + fi + + # 创建仓库配置文件 + cat > "$repo_file" << EOF +[${YUM_REPO_NAME}] +name=Sun HPC Local Repository +baseurl=${YUM_REPO_BASEURL} +enabled=1 +gpgcheck=${YUM_REPO_GPGCHECK} +priority=1 +EOF + + # 如果是 Rocky 8/9,可能需要配置 appstream + if [[ -d "/etc/yum.repos.d" ]]; then + local appstream_repo="/etc/yum.repos.d/${YUM_REPO_NAME}-appstream.repo" + cat > "$appstream_repo" << EOF +[${YUM_REPO_NAME}-appstream] +name=Sun HPC Local AppStream Repository +baseurl=${YUM_REPO_BASEURL}-appstream +enabled=1 +gpgcheck=${YUM_REPO_GPGCHECK} +priority=1 +EOF + fi + + # 清理 YUM 缓存并测试 + yum clean all &>/dev/null + yum makecache &>/dev/null + + if [[ $? -eq 0 ]]; then + log_info "YUM repository configured successfully" + else + log_warn "YUM repository configured but cache generation failed (network may be down)" + fi + + # 显示启用的仓库 + log_info "Enabled repositories:" + yum repolist 2>/dev/null | grep -E "^${YUM_REPO_NAME}" | tee -a $LOG_FILE +} + +# ============================================================================ +# 5. 配置 DNS 解析 +# ============================================================================ + +configure_dns() { + log_step "Configuring DNS resolution..." + + # 备份 resolv.conf + cp /etc/resolv.conf /etc/resolv.conf.bak.$(date +%Y%m%d) 2>/dev/null || true + + # 配置 DNS + cat > /etc/resolv.conf << EOF +# Sun HPC DNS Configuration +nameserver ${DNS_SERVERS%% *} +$(for dns in ${DNS_SERVERS}; do echo "nameserver $dns"; done | tail -n +2) + +# Local domain +search sunhpc.local local +EOF + + # 防止 NetworkManager 覆盖 resolv.conf + if [[ -f /etc/NetworkManager/NetworkManager.conf ]]; then + if ! grep -q "dns=none" /etc/NetworkManager/NetworkManager.conf; then + sed -i '/^\[main\]/a dns=none' /etc/NetworkManager/NetworkManager.conf + systemctl restart NetworkManager 2>/dev/null || true + fi + fi + + log_info "DNS configured: ${DNS_SERVERS}" +} + +# ============================================================================ +# 6. 配置 NTP 时间同步 +# ============================================================================ + +configure_ntp() { + log_step "Configuring NTP time synchronization..." + + # 使用 chrony (Rocky 8/9 默认) + if command -v chronyd &>/dev/null; then + # 备份配置 + cp /etc/chrony.conf /etc/chrony.conf.bak.$(date +%Y%m%d) + + # 配置 chrony + cat > /etc/chrony.conf << EOF +# Sun HPC NTP Configuration +server ${NTP_SERVER} iburst +pool 2.rocky.pool.ntp.org iburst + +# Record the rate at which the system clock gains/losses time. +driftfile /var/lib/chrony/drift + +# Allow the system clock to be stepped in the first three updates +makestep 1.0 3 + +# Enable kernel synchronization of the real-time clock (RTC) +rtcsync + +# Specify file containing keys for NTP authentication +keyfile /etc/chrony.keys + +# Specify directory for log files +logdir /var/log/chrony +EOF + + # 重启 chrony + systemctl restart chronyd &>/dev/null + systemctl enable chronyd &>/dev/null + + log_info "Chrony NTP configured with server: ${NTP_SERVER}" + else + # 使用 ntpd (旧系统) + if command -v ntpd &>/dev/null; then + cat > /etc/ntp.conf << EOF +server ${NTP_SERVER} iburst +restrict default nomodify notrap nopeer noquery +restrict 127.0.0.1 +restrict ::1 +driftfile /var/lib/ntp/drift +EOF + systemctl restart ntpd &>/dev/null + systemctl enable ntpd &>/dev/null + log_info "NTP configured with server: ${NTP_SERVER}" + else + log_warn "No NTP service found (chronyd or ntpd)" + fi + fi +} + +# ============================================================================ +# 7. 配置 SSH 服务 +# ============================================================================ + +configure_ssh() { + log_step "Configuring SSH service..." + + # 备份配置 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d) + + # 优化 SSH 配置 + sed -i 's/#PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config + sed -i 's/#PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config + sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config + sed -i 's/#UseDNS.*/UseDNS no/' /etc/ssh/sshd_config + sed -i 's/#GSSAPIAuthentication.*/GSSAPIAuthentication no/' /etc/ssh/sshd_config + + # 重启 SSH 服务 + systemctl restart sshd &>/dev/null + + log_info "SSH service configured" +} + +# ============================================================================ +# 8. 配置防火墙 +# ============================================================================ + +configure_firewall() { + log_step "Configuring firewall..." + + # 检查 firewalld 是否运行 + if systemctl is-active firewalld &>/dev/null; then + # 开放常用端口 + firewall-cmd --permanent --add-service=ssh &>/dev/null + firewall-cmd --permanent --add-service=dhcp &>/dev/null + firewall-cmd --permanent --add-port=873/tcp &>/dev/null # rsync + firewall-cmd --permanent --add-port=111/udp &>/dev/null # rpcbind + + # 重新加载 + firewall-cmd --reload &>/dev/null + + log_info "Firewall configured" + else + log_warn "Firewalld not running, skipping configuration" + fi +} + +# ============================================================================ +# 9. 安装常用软件包 +# ============================================================================ + +install_packages() { + log_step "Installing common packages..." + + local packages=( + wget curl vim nano + htop iotop iftop + net-tools bind-utils + telnet nc tcpdump + rsync tree lsof + gcc make autoconf automake + openssl-devel zlib-devel + nfs-utils cifs-utils + ntpdate + ) + + if check_network; then + for pkg in "${packages[@]}"; do + if rpm -q "$pkg" &>/dev/null; then + log_info "Package already installed: $pkg" + else + log_info "Installing package: $pkg" + yum install -y "$pkg" &>> $LOG_FILE || log_warn "Failed to install: $pkg" + fi + done + else + log_warn "Network unavailable, skipping package installation" + fi +} + +# ============================================================================ +# 11. 配置用户环境 +# ============================================================================ + +configure_user_env() { + log_step "Configuring user environment..." + + # 创建共享目录 + mkdir -p /share/{apps,home} + mkdir -p /state/partition1/{tmp,work} + + # 设置权限 + chmod 755 /share + chmod 1777 /state/partition1/tmp + + # 配置全局环境变量 + cat > /etc/profile.d/sunhpc.sh << 'EOF' +# Sun HPC Environment Variables +export SHARE_HOME=/share +export STATE_HOME=/state/partition1 +EOF + + chmod 644 /etc/profile.d/sunhpc.sh + log_info "User environment configured" +} + +# ============================================================================ +# 12. 配置系统优化参数 +# ============================================================================ + +configure_sysctl() { + log_step "Configuring system optimization..." + + cat > /etc/sysctl.d/99-sunhpc.conf << EOF +# Sun HPC System Optimization + +# Network optimization +net.core.rmem_max = 134217728 +net.core.wmem_max = 134217728 +net.ipv4.tcp_rmem = 4096 87380 134217728 +net.ipv4.tcp_wmem = 4096 65536 134217728 +net.core.netdev_max_backlog = 5000 +net.ipv4.tcp_max_syn_backlog = 8192 +net.ipv4.tcp_sack = 1 +net.ipv4.tcp_timestamps = 1 + +# Memory optimization +vm.swappiness = 10 +vm.dirty_ratio = 30 +vm.dirty_background_ratio = 5 +vm.vfs_cache_pressure = 50 + +# File system +fs.file-max = 1048576 +fs.inotify.max_user_watches = 1048576 + +# Process scheduler +kernel.sched_autogroup_enabled = 0 +kernel.sched_migration_cost_ns = 5000000 +EOF + + sysctl -p /etc/sysctl.d/99-sunhpc.conf &>/dev/null + log_info "System optimization configured" +} + +# ============================================================================ +# 13. 配置系统限制 +# ============================================================================ + +configure_limits() { + log_step "Configuring system limits..." + + cat > /etc/security/limits.d/99-sunhpc.conf << EOF +# Sun HPC System Limits +* soft nofile 1048576 +* hard nofile 1048576 +* soft nproc 131072 +* hard nproc 131072 +* soft memlock unlimited +* hard memlock unlimited +root soft nofile 1048576 +root hard nofile 1048576 +EOF + + log_info "System limits configured" +} + +# ============================================================================ +# 14. 配置定时任务 +# ============================================================================ + +configure_crontab() { + log_step "Configuring cron jobs..." + + cat > /etc/cron.d/sunhpc << EOF +# Sun HPC Cron Jobs + +# Sync time every hour +0 * * * * root /usr/sbin/chronyc -a makestep &>/dev/null + +# Clean old logs daily +0 2 * * * root find /var/log -name "*.log" -mtime +30 -delete 2>/dev/null + +# Report node status every 5 minutes +*/5 * * * * root /usr/local/bin/node-status-report &>/dev/null +EOF + + chmod 644 /etc/cron.d/sunhpc + log_info "Cron jobs configured" +} + +# ============================================================================ +# 15. 创建节点状态上报脚本 +# ============================================================================ + +create_report_script() { + log_step "Creating node status report script..." + + cat > /usr/local/bin/node-status-report << 'EOF' +#!/bin/bash +# Node status report script for Sun HPC + +HTTP_SERVER="http://172.16.9.254" +NODE_NAME=$(hostname) +IP_ADDR=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1) +LOAD_AVG=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1) +MEM_TOTAL=$(free -g | awk '/^Mem:/{print $2}') +MEM_USED=$(free -g | awk '/^Mem:/{print $3}') +DISK_USED=$(df -h / | awk 'NR==2{print $5}' | sed 's/%//') +SLURM_STATUS=$(systemctl is-active slurm-slurmd 2>/dev/null || echo "unknown") + +# Build status JSON +STATUS_JSON="{\"node\":\"$NODE_NAME\",\"ip\":\"$IP_ADDR\",\"load\":$LOAD_AVG,\"mem_total\":$MEM_TOTAL,\"mem_used\":$MEM_USED,\"disk_used\":$DISK_USED,\"slurm\":\"$SLURM_STATUS\",\"timestamp\":\"$(date -Iseconds)\"}" + +# Send to management node +curl -s -X POST -H "Content-Type: application/json" -d "$STATUS_JSON" ${HTTP_SERVER}/api/node-status &>/dev/null +EOF + + chmod +x /usr/local/bin/node-status-report + log_info "Node status report script created" +} + +# ============================================================================ +# 16. 配置日志轮转 +# ============================================================================ + +configure_logrotate() { + log_step "Configuring log rotation..." + + cat > /etc/logrotate.d/sunhpc << EOF +/var/log/sunhpc-init.log { + daily + rotate 30 + compress + delaycompress + missingok + notifempty + create 644 root root +} +EOF + + log_info "Log rotation configured" +} + +# ============================================================================ +# 17. 清理临时文件 +# ============================================================================ + +cleanup() { + log_step "Cleaning up temporary files..." + + # 删除临时文件 + rm -f /tmp/hostname-map.txt 2>/dev/null + rm -f /tmp/cluster-hosts.txt 2>/dev/null + + # 清除 YUM 缓存 + yum clean all &>/dev/null + + log_info "Cleanup completed" +} + +# ============================================================================ +# 18. 生成初始化完成报告 +# ============================================================================ + +generate_report() { + log_step "Generating initialization report..." + + cat > /root/init-report.txt << EOF +=========================================== +Sun HPC Node Initialization Report +=========================================== +Init Time: $(date '+%Y-%m-%d %H:%M:%S') +Hostname: $(hostname) +IP Address: $(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1) +MAC Address: $(ip link show | grep -oP 'ether \K[0-9a-f:]+' | head -1) + +Services Status: +- NetworkManager: $(systemctl is-active NetworkManager) +- chronyd: $(systemctl is-active chronyd 2>/dev/null || echo "stopped") +- sshd: $(systemctl is-active sshd) +- slurm-slurmd: $(systemctl is-active slurm-slurmd 2>/dev/null || echo "stopped") +- firewalld: $(systemctl is-active firewalld) + +YUM Repositories: +$(yum repolist) + +Files Created: +- /.sunhpc-release +- /etc/hosts (updated) +- /etc/motd (updated) +- /etc/yum.repos.d/sunhpc-local.repo +- /etc/chrony.conf (updated) +- /etc/security/limits.d/99-sunhpc.conf +- /etc/sysctl.d/99-sunhpc.conf + +=========================================== +EOF + + cat /root/init-report.txt >> $LOG_FILE + log_info "Initialization report saved to /root/init-report.txt" +} + +# ============================================================================ +# 主函数 +# ============================================================================ + +main() { + log_info "Starting Sun HPC node initialization..." + + # 执行所有初始化步骤 + init_log + check_network + create_release_file + configure_hostname + configure_motd + configure_yum_repo + configure_dns + configure_ntp + configure_ssh + configure_firewall + install_packages + configure_slurm + configure_user_env + configure_sysctl + configure_limits + configure_crontab + create_report_script + configure_logrotate + cleanup + generate_report + + log_info "==========================================" + log_info "Sun HPC node initialization completed!" + log_info "==========================================" + + # 显示关键信息 + echo "" + echo -e "${GREEN}=== Initialization Complete ===${NC}" + echo -e "Hostname: $(hostname)" + echo -e "Release file: $(cat /.sunhpc-release | head -1)" + echo -e "Log file: $LOG_FILE" + echo -e "Report: /root/init-report.txt" + echo "" +} + +# ============================================================================ +# 脚本入口 +# ============================================================================ + +# 检查是否需要重启 +if [[ "$1" == "--reboot" ]]; then + main + log_info "Rebooting in 5 seconds..." + sleep 5 + reboot +else + main + log_info "Initialization completed. You may reboot if needed." +fi diff --git a/pkgs/ks/ipxe.sh b/pkgs/ks/ipxe.sh new file mode 100644 index 0000000..b559b2c --- /dev/null +++ b/pkgs/ks/ipxe.sh @@ -0,0 +1,21 @@ +#!ipxe + +:main_menu +menu iPXE boot menu + +item rocky9 Install Rocky Linux 9 +item local Boot from Local Disk + +choose --default rocky9 --timeout 5000 selected || goto local + +:rocky9 +echo Booting RockyLinux from networking +kernel http://172.16.9.254/rocky/9.7/isolinux/vmlinuz \ + net.ifnames=0 biosdevname=0 \ + inst.repo=http://172.16.9.254/rocky/9.7 \ + inst.ks=http://172.16.9.254/ks/rhel.ks +initrd http://172.16.9.254/rocky/9.7/isolinux/initrd.img +boot + +:local +exit diff --git a/pkgs/ks/rhel.ks b/pkgs/ks/rhel.ks new file mode 100644 index 0000000..a7be3ec --- /dev/null +++ b/pkgs/ks/rhel.ks @@ -0,0 +1,60 @@ +graphical + +%addon com_redhat_kdump --disable +%end + +timezone Asia/Shanghai --utc +keyboard --xlayouts='us' +lang en_US.UTF-8 + +selinux --disabled + +url --url="http://172.16.9.254/rocky/9.7" + +# Network information +network --bootproto=dhcp --device=link --ipv6=auto --activate + +# Partition clearing information +#zerombr +#clearpart --all --initlabel +#autopart --type=lvm +%include /tmp/diskinfo + +#ignoredisk --only-use=sda +#part /boot --fstype="xfs" --ondisk=sda --size=1024 +#part swap --fstype="swap" --ondisk=sda --size=4096 +#part / --fstype="xfs" --ondisk=sda --size=97278 +#part /home --fstype="xfs" --ondisk=sda --size=20480 + +%packages +@^minimal-environment +@standard +@development +vim +wget +curl +autofs +nfs-utils +nfs4-acl-tools +sssd-nfs-idmap +pcp-pmda-nfsclient +%end + +# Root password +rootpw --iscrypted $6$muqhPjb0F9IM2/Fg$pPaVF7DTjs/zz91vHMrcL8jPLQoLFCjUUxHkIZao9C6OFbBPof2AtmTRfvO4Ix.8al3dnMz8/aAbd88sHSQTK. +user --name=kelvin --password=$6$kAz6MRJFIpIyhKuv$YZntcNpyoSYRMD6y5qmZIIBiklzaskqHWE4A0oXI8vX492bcL/.z6xF3MjVDgVJzZ0FaNDSy8BFeEhD9mfr67/ --iscrypted --gecos="kelvin" + +#reboot + +%pre --interpreter=/bin/bash +curl -o /tmp/dfmt.sh http://172.16.9.254/ks/dfmt.sh +chmod +x /tmp/dfmt.sh + +/tmp/dfmt.sh > /tmp/diskinfo +%end + +%post +curl -s -o /tmp/init.sh http://172.16.9.254/ks/init.sh +chmod +x /tmp/init.sh +/tmp/init.sh +%end diff --git a/pkgs/pxelinux/tftpboot/boot/bootx64.efi b/pkgs/pxelinux/tftpboot/boot/bootx64.efi new file mode 100755 index 0000000000000000000000000000000000000000..3dc370ea5f827c341ddc2817d39f911113b4a8ce GIT binary patch literal 959224 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

|kQ__px)+NKW2GxmIVWwF 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

oG1e=k-{5`_ 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∨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 z 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 PoA&zK3E%xgx#qV#Q_8 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 z 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

BA_T9QjMb`$H^2%13Fg&TGQ8!HNH25VWHh68 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 b^bQOI!wB=hYnHDJv{wB8_`5?d+~rZH1cScG literal 0 HcmV?d00001 diff --git a/sunhpc b/sunhpc new file mode 100755 index 0000000..b614586 --- /dev/null +++ b/sunhpc @@ -0,0 +1,1570 @@ +#!/bin/bash +set -eo pipefail +#set -eou pipefail + +R='\e[1;31m' +AR='\e[0;31m' + +G='\e[1;92m' +AG='\e[0;92m' + +C='\e[1;36m' # 亮青色 +AC='\e[0;36m' # 暗青色 + +Y='\e[1;33m' # 亮黄色 +AY='\e[0;33m' # 暗黄色 + +H='\e[0;90m' # 暗灰色 (推荐) +LH='\e[1;31m' # 亮黑色 +AH='\e[1;90m' # 亮灰色 + +B='\e[0;37m' # 白色 +B='\e[0;30m' # 黑色 +NC='\e[0m' # No Color + +# ====================== 公共工具函数 ====================== +# 错误输出函数 +error() { + echo -e "${AR}[E] $*${NC}" >&2 + exit 1 +} + +# 信息输出函数 +info() { + echo -e "${AG}[I]${NC} ${AC}$*${NC}" +} + +# 警告输出函数 +warn() { + echo -e "${AY}[W] $*${NC}" +} + +# 清理最后一行 +cline() { + echo -ne "\r\033[K" +} + +COLUMNS=$(( $(tput cols 2>/dev/null || echo 80) - 8 )) +SSEP=$(printf "%${COLUMNS}s" "" | tr " " "-") +DSEP=$(printf "%${COLUMNS}s" "" | tr " " "=") + +status_dnf_packages="/tmp/status_dnf_packages" + +# ====================== 全局关联数组定义(核心优化) ====================== +# 全局选项:verbose/debug/help/nodes 等,支持 GLOBAL_OPTS[v] 判断 +declare -A GLOBAL_OPTS=( + [v]="" # -v + [verbose]="" # --verbose + [d]="" # -d + [debug]="" # --debug + [h]="" # -h + [help]="" # --help + [nodes]="" # -n/--nodes 节点值 +) + +# 子命令栈(数组:存储 exec/list node/serv autofs) +CMD_STACK=() +# 公共参数集合(-开头) +PUBLIC_ARGS=() +# 子命令专属参数(--开头) +PRIVATE_ARGS=() +# 默认节点列表(会自动从 nodes 文件覆盖) +DEFAULT_NODES=("localhost") +# 全局生效节点数组(所有子命令共享) +GLOBAL_NODES=() +declare -A GLOBAL_PORT +declare -A global_env + +ask() { + # 基本用法:ask "是否删除文件?" - 无默认值,必须输入 y/yes 或 n/no + # ask "是否继续?" "y" - 默认继续,直接回车相当于 y + # ask "是否继续?" "n" - 默认取消,直接回车相当于 n + # if ask "警告:即将删除所有文件,是否继续?" "n"; then + local prompt="$1" + local default="$2" + local answer + + # 构建提示信息 + if [ "$default" = "y" ]; then + prompt="$prompt [Y/n]: " + elif [ "$default" = "n" ]; then + prompt="$prompt [y/N]: " + else + prompt="$prompt [y/n]: " + fi + + while true; do + read -p "$prompt" answer + # 如果用户直接回车,使用默认值 + if [ -z "$answer" ] && [ -n "$default" ]; then + answer="$default" + fi + # 转换为小写进行比较 + answer=$(echo "$answer" | tr '[:upper:]' '[:lower:]') + case "$answer" in + y|yes) return 0 ;; + n|no) return 1 ;; + *) echo "请输入 y/yes 或 n/no" ;; + esac + done +} + +load_os_envs() { + interfaces=$(ls /sys/class/net | grep -v lo) + for iface in $interfaces; do + readarray -t config <<< "$(nmcli -g IP4.ADDRESS,IP4.GATEWAY,IP4.DNS device show $iface 2>/dev/null)" + + # IP地址 + ip_addr=$(echo "${config[0]}" | cut -d: -f2 | cut -d'/' -f1) + global_env["${iface}_ip"]="${ip_addr:-}" + + # 网关 + gateway=$(echo "${config[1]}" | cut -d: -f2) + global_env["${iface}_gateway"]="${gateway:-}" + + # DNS + dns=$(echo "${config[2]}" | cut -d: -f2- | tr ' ' ',' | sed 's/,$//') + global_env["${iface}_dns"]="${dns:-223.5.5.5,223.6.6.6}" + + # CIDR掩码 + cidr=$(nmcli -g IP4.ADDRESS device show $iface 2>/dev/null | head -1 | cut -d'/' -f2) + global_env["${iface}_mask"]="${cidr:-24}" + done +} + +getFileArgs(){ + # 调用模式: getFileArgs myfile "true" 未指定文件时只返回错误码 + # 调用模式: result=$(getFileArgs myfile "true") 返回文件 + # 调用模式: getFileArgs myfile 未指定文件时直接退出脚本,默认值: false + + local -n filename=$1 + local isForce=${2:-"false"} # 默认值为 "false" + + # 检查 file 参数是否传入 + if [[ -z "${GLOBAL_OPTS[file]-}" ]]; then + local err_msg="未指定文件,请使用 -f 或 --file 参数" + + if [[ "$isForce" == "false" ]]; then + error "$err_msg" + else + warn "$err_msg" + return 1 # 返回非0表示失败 + fi + fi + + # 检查文件是否存在 + if [[ -f "${GLOBAL_OPTS[file]}" ]] || [[ -d "${GLOBAL_OPTS[file]}" ]]; then + filename="${GLOBAL_OPTS[file]}" + return 0 + else + local err_msg="错误:文件或目录不存在 -> ${GLOBAL_OPTS[file]}" + + if [[ "$isForce" == "false" ]]; then + error "$err_msg" + else + warn "$err_msg" + return 1 + fi + fi +} + +# ====================== 核心函数:加载环境变量信息 ============== +load_conf_envs() { + + while read -r key val; do + # 跳过空行、注释行 + [[ -z "$key" || "$key" == \#* ]] && continue + + global_env["$key"]="$val" + done < "$config_file" +} + +# ============================================================ +# 辅助函数:打印所有环境变量(调试用) +# ============================================================ +print_global_env() { + for key in "${!global_env[@]}"; do + printf "%-20s = %s\n" "$key" "${global_env[$key]}" + done + echo "======================================" +} + +# ============================================================ +# 辅助函数:获取指定网卡IP +# ============================================================ +get_interface_ip() { + local interface="$1" + if ip link show "$interface" &>/dev/null; then + ip addr show "$interface" | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1 + else + echo "" + fi +} + +# ============================================================ +# 辅助函数:获取指定网卡MAC地址 +# ============================================================ +get_interface_mac() { + local interface="$1" + if ip link show "$interface" &>/dev/null; then + ip link show "$interface" | grep -oP '(?<=link/ether\s)[0-9a-f:]+' | head -1 + else + echo "" + fi +} + +# ============================================================ +# 辅助函数:快速获取系统信息摘要 +# ============================================================ +show_system_summary() { + cat <&1 | tee "$log_file" | while IFS= read -r line; do + count=$((count + 1)) + local current_time=$(date +%s) + local elapsed=$((current_time - start_time)) + local elapsed_min=$((elapsed / 60)) + local elapsed_sec=$((elapsed % 60)) + + # 提取关键信息(去掉路径等冗余信息) + local short_line=$(echo "$line" | sed 's|/home/[^/]*/|~/|g' | cut -c1-60) + + printf "\r${AC}[B] [%s]${NR} ${H}[%d]${NR} %02d:%02d - %.60s" \ + "$description" $count $elapsed_min $elapsed_sec "$short_line" + done + + exit_code=${PIPESTATUS[0]} + + # 清除最后一行进度信息 + echo -ne "\r\033[K" + + if [ $exit_code -eq 0 ]; then + info "[$description] - 完成! (共 $count 步, 耗时 $(($(date +%s) - start_time))秒)" + info "日志已保存: $log_file" + else + warn "❌ $description - 失败! (退出码: $exit_code, 共 $count 步)" + warn "请查看日志: $log_file" + return $exit_code + fi +} + +# 过滤安装包 +filter_pkgs(){ + local -n input_array=$1 # 输入的包数组 + local -n output_array=$2 # 输出的包数组 + + output_array=() # 清空输出数组 + for pkg in ${input_array[@]}; do + #grep -q $pkg $status_dnf_packages && continue + if ! rpm -q "$pkg" &>/dev/null; then + #echo "$pkg" >> $status_dnf_packages + output_array+=("$pkg") + else + info "Skip installation, already installed - $pkg" + fi + done +} + +cidr_to_netmask() { + local cidr=$1 + local masks=( + "0.0.0.0" # 0 + "128.0.0.0" # 1 + "192.0.0.0" # 2 + "224.0.0.0" # 3 + "240.0.0.0" # 4 + "248.0.0.0" # 5 + "252.0.0.0" # 6 + "254.0.0.0" # 7 + "255.0.0.0" # 8 + "255.128.0.0" # 9 + "255.192.0.0" # 10 + "255.224.0.0" # 11 + "255.240.0.0" # 12 + "255.248.0.0" # 13 + "255.252.0.0" # 14 + "255.254.0.0" # 15 + "255.255.0.0" # 16 + "255.255.128.0" # 17 + "255.255.192.0" # 18 + "255.255.224.0" # 19 + "255.255.240.0" # 20 + "255.255.248.0" # 21 + "255.255.252.0" # 22 + "255.255.254.0" # 23 + "255.255.255.0" # 24 + "255.255.255.128" # 25 + "255.255.255.192" # 26 + "255.255.255.224" # 27 + "255.255.255.240" # 28 + "255.255.255.248" # 29 + "255.255.255.252" # 30 + "255.255.255.254" # 31 + "255.255.255.255" # 32 + ) + echo "${masks[$cidr]}" +} + +get_subnet_address() { + local ip="$1" + local mask="$2" + + IFS=. read -r i1 i2 i3 i4 <<< "$ip" + IFS=. read -r m1 m2 m3 m4 <<< "$mask" + + n1=$((i1 & m1)) + n2=$((i2 & m2)) + n3=$((i3 & m3)) + n4=$((i4 & m4)) + + echo "$n1.$n2.$n3.$n4" + +} +# ====================== pxe server functions ==================== +pxe_dhcp_build() { + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + interface="${GLOBAL_OPTS[interface]}" + ipaddr=${global_env[${interface}_ip]} + netcidr=${global_env[${interface}_mask]} + netmask=$(cidr_to_netmask 24) + subnet=$(get_subnet_address $ipaddr $netmask) + + IFS=. read -r i1 i2 i3 i4 <<< "$ipaddr" + start_ip="$i1.$i2.$i3.10" + ender_ip="$i1.$i2.$i3.90" + tests_ip="$i1.$i2.$i3.252" + + info "DHCP Interface name: $interface" + info "DHCP IP Address : $ipaddr" + info "DHCP IP Netmask : $netmask" + info "DHCP IP Subnets : $subnet" + info "DHCP Start IPAddr : $start_ip" + info "DHCP End IPAddr : $ender_ip" + + nopkgs=() + pkgs=("dhcp-server dhcp-common") + filter_pkgs pkgs nopkgs + + local cmd=("dnf -y install ${nopkgs[*]}") + [[ -z ${nopkgs[@]} ]] || run_with_progress "DNF 安装DHCP服务..." "$cmd" "$log_file" + + dhcp_config="/etc/dhcp/dhcpd.conf" + + { + echo "option domain-name \"`hostname -s`\";" + echo "option domain-name-servers 8.8.8.8;" + echo "default-lease-time 600;" + echo "max-lease-time 7200;" + echo "ddns-update-style none;" + echo "" + echo "allow booting;" + echo "allow bootp;" + echo "" + echo "option arch code 93 = unsigned integer 16;" + echo "" + echo "subnet ${subnet} netmask ${netmask} {" + echo " option routers ${ipaddr};" + echo " range $start_ip $ender_ip;" + echo "" + echo " next-server ${ipaddr};" + echo "" + echo ' host test_host_bond {' + echo ' option dhcp-client-identifier "test_host_bond";' + echo " fixed-address $tests_ip;" + echo ' }' + echo ' if option arch= 00:07 or option arch = 00:09 {' + echo ' # UEFI x64' + echo ' filename "/EFI/x86/grub.efi";' + echo ' } else if option arch = 00:0b {' + echo ' # UEFI ARM64' + echo ' filename "/EFI/aarch64/bootaa64.efi";' + echo ' } else {' + echo ' # Legcy BIOS' + echo ' filename "pxelinux.0";' + echo ' }' + echo '}' + } > ${dhcp_config} + + # sed -i 's/\$DHCPDARGS/eth0/' /usr/lib/systemd/system/dhcpd.service + dhcp_systemd="/usr/lib/systemd/system/dhcpd.service" + grep -q "DHCPDARGS" $dhcp_systemd &>/dev/null && \ + sed -i "s/\$DHCPDARGS/${interface}/" $dhcp_systemd &>/dev/null + + systemctl daemon-reload && systemctl restart dhcpd.service + systemctl is-enabled dhcpd &>/dev/null || systemctl enable dhcpd.service &>/dev/null + + systemctl is-active dhcpd &>/dev/null && info "DHCP 服务已经配置成功..." \ + || warn "DHCP 服务部署失败,请查看服务信息 systemctl status dhcpd.service" + +} + +pxe_tftp_build() { + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + nopkgs=() + pkgs=("tftp-server tftp syslinux") + filter_pkgs pkgs nopkgs + + local cmd=("dnf -y install ${nopkgs[*]}") + [[ -z ${nopkgs[@]} ]] || run_with_progress "DNF 安装TFTP服务..." "$cmd" "$log_file" + + tftp_server_conf="/usr/lib/systemd/system/tftp.service" + tftp_socket_conf="/usr/lib/systemd/system/tftp.socket" + tftp_pxe_dirs="/var/lib/tftpboot" + + [[ -e "$tftp_pxe_dirs" ]] || mkdir -p "$tftp_pxe_dirs/pxelinux.cfg" + chmod -R 755 $tftp_pxe_dirs + + # Pxe 启动文件配置 + src_pxelinux="/usr/share/syslinux" + src_files=("pxelinux.0 menu.c32 ldlinux.c32") + for fname in ${src_files[@]}; do + src_file="$src_pxelinux/$fname" + dst_file="$tftp_pxe_dirs/$fname" + + [[ -f $src_file ]] || warn "$src_file not found!" + + if [[ -f $dst_file ]]; then + info "The $fname already exists, Skipt shis copy..." + else + info "Copying the $fname to $dst_file" + /usr/bin/cp $src_file $dst_file + fi + done + + # 文件配置 + if ! getFileArgs myfile "true"; then + warn " 必须指定系统ISO文件或挂载位置,例如: " + warn " -f /root/Rocky-9.7-x86_64-dvd.iso 或 -f /mnt/cdrom/" + exit 1 + fi + + echo "------------> $myfile" + + exit 1 + + # -c 允许创建新文件(上传) -p 使用普通系统权限检查 + { + echo '[Unit]' + echo 'Description=Tftp Server' + echo 'Requires=tftp.socket' + echo 'Documentation=man:in.tftpd' + echo '' + echo '[Service]' + echo "ExecStart=/usr/sbin/in.tftpd -c -p -s "$tftp_pxe_dirs"" + echo 'StandardInput=socket' + echo '' + echo '[Install]' + echo 'WantedBy=multi-user.target' + echo 'Also=tftp-server.socket' + } > ${tftp_server_conf} + + systemctl daemon-reload && systemctl restart tftp.socket + systemctl is-enabled tftp.socket &>/dev/null || systemctl enable tftp.socket &>/dev/null + + info "TFTP 服务端口: 69" + systemctl is-active tftp.socket &>/dev/null && info "TFTP 服务已经配置成功..." \ + || warn "TFTP 服务部署失败,请查看服务信息 systemctl status tftp.socket" +} + +pxe_http_build() { + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + + nopkgs=() + pkgs=("httpd") + filter_pkgs pkgs nopkgs + + local cmd=("dnf -y install ${nopkgs[*]}") + [[ -z ${nopkgs[@]} ]] || run_with_progress "DNF 安装HTTPD服务..." "$cmd" "$log_file" + + http_root_conf="/etc/httpd" + http_html_dirs="/var/www/html" + http_serv_conf="/usr/lib/systemd/system/httpd.service" + + custom_conf="$http_root_conf/conf.d/sunhpc.conf" + { + echo 'Alias /rocky97 /var/www/html/rocky97' + echo '' + echo 'UseCanonicalName Off' + echo "ServerName `hostname -f`" + echo '' + echo "" + echo " Options Indexes FollowSymLinks" + echo " AllowOverride None" + echo " Require all granted" + echo "" + echo " EnableSendfile on" + echo "" + } > ${custom_conf} + + #systemctl daemon-reload && systemctl restart httpd + #systemctl is-enabled httpd &>/dev/null || systemctl enable httpd &>/dev/null + + + info "HTTP 服务端口: 80,443" + if systemctl is-active httpd &>/dev/null ; then + info "HTTP 服务已经配置成功..." + info "后续配置: " + info " 拷贝系统ISO文件到 $rocky_repo_src" + info " # rsync -ah --info=progress2 /mnt/ /srv/repos/rocky/9.7/" + else + warn "HTTP 服务部署失败,请查看服务信息 systemctl status httpd.service" + fi + + if getFileArgs myfile "true"; then + local mnt_iso_dirs=$myfile + if [[ -f $myfile ]]; then + mnt_dst_dirs="/mnt/cdrom" + [[ -e "$mnt_dst_dirs" ]] && umount $mnt_dst_dirs &>/dev/null || mkdir -p $mnt_dst_dirs + info "Mount path: $mnt_dst_dirs" + mount $myfile $mnt_dst_dirs &>/dev/null + mnt_iso_dirs=$mnt_dst_dirs + fi + + rpmname=$(find $mnt_iso_dirs -iname "rocky-release-*.rpm") + filename=$(basename "$rpmname" .rpm) + distro=$(echo "$filename" | cut -d'-' -f1) # rocky + version=$(echo "$filename" | cut -d'-' -f3) # 9.7 + distro=${distro:-"linux"} + version=${version:-"1.0"} + + rocky_repo_distro="/srv/repos/$distro" + rocky_repo_version="$rocky_repo_distro/$version" + rocky_html_dst="$http_html_dirs/$distro" + [[ ! -e $rocky_repo_version ]] && mkdir -p $rocky_repo_version + [[ ! -e $rocky_html_dst ]] && ln -s $rocky_repo_distro $rocky_html_dst + + info "拷贝系统镜像到本地: $rocky_repo_src" + info " 系统发行版: $distro" + info " 系统版本 : $version" + info " 源地址 : $mnt_iso_dirs" + info " 目的地址 : $rocky_repo_version" + + rsync -ah --info=progress2 "$mnt_iso_dirs" "$rocky_repo_version/" + info "测试访问: curl -L http://`hostname -s`/$distro/$version/" + else + info "后续配置: " + info " 拷贝系统ISO文件到 $rocky_repo_src" + info " # rsync -ah --info=progress2 /mnt/ /srv/repos/rocky/9.7/" + fi +} + +pxe_dnsmasq_build() { + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + nopkgs=() + pkgs=("syslinux dnsmasq dnsmasq-utils ipxe-bootimgs") + filter_pkgs pkgs nopkgs + + local cmd=("dnf -y install ${nopkgs[*]}") + [[ -z ${nopkgs[@]} ]] || run_with_progress "DNF 安装 dnsmasq 服务..." "$cmd" "$log_file" + + # -n 非空True,-z 为空True + [[ -n ${global_env[interface]} ]] && iface=${global_env[interface]} || \ + error "请指定DHCP监听接口命名, 编辑 $config_file 文件, 例如: interface eth1" + + [[ -n ${global_env[server]} ]] && ipaddr=${global_env[server]} || \ + error "请指定监听接口IP地址, 编辑 $config_file 文件, 例如: server 172.16.9.254" + + [[ -n ${global_env[dns]} ]] && dnsip=${global_env[dns]} || dnsip="223.5.5.5" + + [[ -n ${global_env[range]} ]] && iprange=${global_env[range]} || \ + error "请指定DHCP网络IP地址范围, 编辑 $config_file 文件, 例如: range 172.16.9.1,172.16.9.100" + + vmlinuz="http://$ipaddr/rocky/isolinux/vmlinuz" + [[ -n ${global_env[vmlinuz]} ]] && vmlinuz=${global_env[vmlinuz]} || \ + error "请指定vmlinuz web路径, 编辑 $config_file 文件, 例如: vmlinuz http://$ipaddr/rocky/isolinux/vmlinuz" + + initrd="http://$ipaddr/rocky/isolinux/initrd.img" + [[ -n ${global_env[initrd]} ]] && initrd=${global_env[initrd]} || \ + error "请指定initrd web路径, 编辑 $config_file 文件, 例如: initrd http://$ipaddr/rocky/isolinux/initrd.img" + [[ -n ${global_env[ks]} ]] && ks=${global_env[ks]} || \ + error "请指定ks web路径, 编辑 $config_file 文件, 例如: ks http://$ipaddr/ks/ks.ks" + [[ -n ${global_env[repo]} ]] && repo=${global_env[repo]} || \ + error "请指定ks web路径, 编辑 $config_file 文件, 例如: repo http://$ipaddr/rocky/" + + kargs="net.ifnames=0 biosdevname=0" + [[ -n ${global_env[kargs]} ]] && kargs="$kargs ${global_env[kargs]}" + + ipxeboot="http://$ipaddr/ks/boot.ipxe" + [[ -n ${global_env[bootipxe]} ]] && ipxeboot=${global_env[bootipxe]} + + htmlroot="/var/www/html" + [[ -n ${global_env[htmlroot]} ]] && htmlroot=${global_env[htmlroot]} + + + boot_root="/srv/pxelinux/tftpboot" + dnsmasq_conf="/etc/dnsmasq.d/sunhpc.conf" + + [[ -e "$boot_root/boot" ]] || mkdir -p "$boot_root/boot" + { + echo "interface=$interface" + echo "bind-interfaces" + echo "" + echo "enable-tftp" + echo "tftp-root=${boot_root}" + echo "" + echo "# Gateway:3, DNS:6" + echo "dhcp-range=$iprange,12h" + echo "dhcp-option=3,${ipaddr}" + echo "dhcp-option=6,$dnsip" + echo "" + echo "dhcp-match=set:bios,option:client-arch,0" + echo "dhcp-match=set:uefi,option:client-arch,7" + echo "dhcp-match=set:uefi,option:client-arch,9" + echo "" + echo "dhcp-boot=tag:bios,boot/undionly.kpxe" + echo "dhcp-boot=tag:uefi,boot/bootx64.efi" + echo "dhcp-boot=tag:ipxe,$ipxeboot" + } > ${dnsmasq_conf} + + ipxeconf="$htmlroot$(echo "$htmlroot" | cut -d'/' -f4-)" + echo "----ipxeconf----> $ipxeconf" + +} +# ====================== server functions ======================== +slurm_build() { + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + FILE_CONF="slurm_build.conf" + REPOS_DIRS="/etc/yum.repos.d/*.repo" + SEARCH_STR="mirrors.ustc.edu.cn" + log_file="slurm_build.log" + EPEL_C="/etc/yum.repos.d/epel.repo" + REPO_C="/etc/yum.repos.d/slurm.repo" + DST_DIR="/srv/repos/slurm/packages" + + STATUS="$DST_DIR/.installed" + init_db_flags="/var/lib/mysql/.initialized" + slurmctld_flags="/etc/slurm/.slurmctld" + slurmdbd_flags="/etc/slurm/.slurmdbd" + slurmd_flags="/etc/slurm/.slurmd" + + + # 检查 file 参数是否传入 + if [[ -z "${GLOBAL_OPTS[file]-}" ]]; then + echo "错误:未指定文件,请使用 -f 或 --file 参数" + exit 1 + fi + + # 检查文件是否存在 + if [[ ! -f "${GLOBAL_OPTS[file]}" ]]; then + echo "错误:文件不存在 → ${GLOBAL_OPTS[file]}" + exit 1 + fi + + info "${DSEP}" + info "🔨 开始 Slurm 构建安装(断点续跑模式)" + info "${DSEP}" + + dnf config-manager --enable crb + [ -f "$EPEL_C" ] && info "EPEL Repo is enabled" || dnf -y install epel-release + + local cmd="dnf -y install @development yum-utils dnf-utils rpm-build" + [[ -f $STATUS ]] || run_with_progress "DNF 安装系统开发依赖包..." "$cmd" "$log_file" + + local pkgs="munge munge-devel mariadb mariadb-devel \ + gtk2 gtk2-devel gtk3 gtk3-devel http-parser http-parser-devel \ + json-c json-c-devel libyaml libyaml-devel libjwt libjwt-devel \ + wget python3 readline-devel pam-devel perl-ExtUtils-MakeMaker \ + perl-devel perl-JSON-PP createrepo_c hdf5 hdf5-devel man2html \ + man2html-core pam pam-devel freeipmi freeipmi-devel numactl \ + numactl-devel pmix pmix-devel hwloc hwloc-devel lua lua-devel \ + ucx ucx-devel jq lz4-devel mariadb-server mariadb-devel" + + nopkgs=() + filter_pkgs pkgs nopkgs + + cmd=("dnf -y install ${nopkgs[*]}") + [[ -z ${nopkgs[@]} ]] || run_with_progress "DNF 安装系统基础依赖包..." "$cmd" "$log_file" + + export CPPFLAGS="-I$PWD/deps_pkgs/cuda-13.0/targets/x86_64-linux/include ${CPPFLAGS}" + export LDFLAGS="-L$PWD/deps_pkgs/cuda-13.0/targets/x86_64-linux/lib/stubs ${LDFLAGS}" + + [[ -f $STATUS ]] && info "Slurm 已经存在 ..." || info "开始制作 Slurm rpm 安装包 ..." + + TARFILE=${GLOBAL_OPTS[file]} + local cmd="rpmbuild -ta \ + --with slurmrestd --with hdf5 --with hwloc --with muma \ + --with pmix --with nvml --with lua --with ucx --with jwt --with freeipmi \ + $TARFILE" + + [[ -f $STATUS ]] || run_with_progress "Slurm RPM 构建..." "$cmd" "$log_file" + + mkdir -pv $DST_DIR + find $HOME/rpmbuild/RPMS/ -iname "*.rpm" -exec mv {} $DST_DIR \; + + { + echo "[slurm]" + echo "name=Slurm Local Repository" + echo "baseurl=file:///$DST_DIR" + echo "gpgcheck=0" + echo "enabled=1" + } > "$REPO_C" + touch $DST_DIR/.installed + + #createrepo_c $DST_DIR 2>&1 | tee $log_file + info "SLURM 部署完成, Repos: $DST_DIR" + + local pkgs="pcp-pmda-slurm slurm slurm-perlapi \ + slurm-contribs slurm-devel slurm-libpmi slurm-pam_slurm \ + slurm-sackd slurm-slurmctld slurm-slurmd \ + slurm-slurmdbd slurm-slurmrestd \ + slurm-example-configs" + + nopkgs=() + filter_pkgs pkgs nopkgs + + cmd=("dnf -y install ${nopkgs[*]}") + [[ -z ${nopkgs[@]} ]] || run_with_progress "Slurm 服务安装..." "$cmd" "$log_file" + + # 开始配置 MariaDB 数据库 + slurm_db_conf="/etc/my.cnf.d/slurm.cnf" + { + echo "[mysqld]" + echo "innodb_buffer_pool_size = 2G" + echo "innodb_log_file_size = 64M" + echo "innodb_lock_wait_timeout = 900" + } > "$slurm_db_conf" + systemctl is-active mariadb &>/dev/null || systemctl start mariadb &>/dev/null + systemctl is-enabled mariadb &>/dev/null || systemctl enable mariadb &>/dev/null + + DB_ROOT_PASSWORD="admin_b101" + # 静默执行初始化数据库: mysql_secure_installation + [[ -f $init_db_flags ]] && info "Database already initialized, skipping mysql_secure_installation" \ + || mysql_secure_installation </dev/null 2>&1; then + info "MariaDB initialization and securing completed successfully!" + else + warn "Error: Authentication failed. Please check the logs." + fi + info "数据库初始化密码: $DB_ROOT_PASSWORD" + info "重新设置密码: " + info " systemctl stop mariadb" + info " mysqld_safe --skip-grant-tables &" + info " mysql -u root" + info " flush privileges;" + info " alter user 'root'@'localhost' identified by 'new_pass'" + info " exit" + info "killall mysqld" + info "systemctl start mariadb" + + SLURM_DB_PW="admin_b101" + SLURM_DB_NM="slurm_acct_db" + + info "开始创建 Slurm 基础数据库: ${SLURM_DB_NM}" + info "Slurm Database User: slurm" + info "Slurm Database Pass: $SLURM_DB_PW" + + [[ -f $init_db_flags ]] || mysql -u root -p${DB_ROOT_PASSWORD} <<-EOSQL +CREATE DATABASE IF NOT EXISTS ${SLURM_DB_NM}; +DROP USER IF EXISTS 'slurm'@'localhost'; +CREATE USER IF NOT EXISTS 'slurm'@'localhost' identified by '${SLURM_DB_PW}'; +GRANT ALL PRIVILEGES ON ${SLURM_DB_NM}.* TO 'slurm'@'localhost' WITH GRANT OPTION; +FLUSH PRIVILEGES; +EOSQL + touch ${init_db_flags} + + # 配置 slurmdbd 服务 + slurm_root="/etc/slurm" + slurm_dbdc="$slurm_root/slurmdbd.conf" + slurm_ctld="$slurm_root/slurm.conf" + getent passwd slurm &>/dev/null || useradd -r -b /var/lib -s /sbin/nologin slurm + getent passwd slurm &>/dev/null || useradd -r -b /var/lib -s /sbin/nologin slurmrestd + + touch ${slurm_dbdc} + chown slurm:slurm ${slurm_dbdc} + chmod 600 ${slurm_dbdc} + + mkdir -p "/var/log/slurm" + mkdir -p "/var/run/slurmdbd" + chown -R slurm:slurm "/var/log/slurm" + chown -R slurm:slurm "/var/run/slurmdbd" + + [[ -f $slurmdbd_flags ]] && info "SlurmDBD Service is configuration finisheld..." \ + || cat > ${slurm_dbdc} <<-EOSLURMDBD +AuthType=auth/munge +LogFile=/var/log/slurm/slurmdbd.log +PidFile=/var/run/slurmdbd/slurmdbd.pid + +DbdHost=`hostname -s` +DbdPort=6819 +SlurmUser=slurm +DebugLevel=info + +StorageType=accounting_storage/mysql +StorageHost=localhost +StoragePort=3306 +StorageUser=slurm +StoragePass=${SLURM_DB_PW} +StorageLoc=${SLURM_DB_NM} + +ArchiveEvents=yes +ArchiveJobs=yes +ArchiveResvs=yes +ArchiveSteps=no +ArchiveSuspend=no +ArchiveTXN=no +ArchiveUsage=no +PurgeEventAfter=1month +PurgeJobAfter=12month +PurgeResvAfter=1month +PurgeStepAfter=1month +PurgeSuspendAfter=1month +PurgeTXNAfter=12month +PurgeUsageAfter=24month +EOSLURMDBD + touch $slurmdbd_flags + + if [[ ! -f $slurmdbd_flags ]]; then + systemctl restart slurmdbd &>/dev/null + systemctl is-enabled slurmdbd &>/dev/null || systemctl enable slurmdbd &>/dev/null + fi + + # 配置 slurmctl 服务 + nodeinfo=$(slurmd -C | head -1) + [[ -f $slurmctld_flags ]] && info "SlurmCTLD Service is configuration finisheld..." \ + || cat > ${slurm_ctld} <<-EOSLURMCTLD +ClusterName=cluster +ControlMachine=`hostname -s` +AuthType=auth/munge +SlurmUser=slurm +SlurmdUser=root +SlurmctldPort=6817 +SlurmdPort=6818 + +StateSaveLocation=/var/spool/slurm/ctld +SlurmdSpoolDir=/var/spool/slurm/d +SlurmctldPidFile=/var/run/slurmctld.pid +SlurmdPidFile=/var/run/slurmd.pid +ProctrackType=proctrack/linuxproc +SchedulerType=sched/backfill +SelectType=select/cons_tres +SelectTypeParameters=CR_Core + +AccountingStorageType=accounting_storage/slurmdbd +AccountingStorageHost=localhost +AccountingStoragePort=6819 +MailProg=/bin/true + +${nodeinfo} State=UNKNOWN +PartitionName=control Nodes=cluster Default=YES MaxTime=INFINITE State=UP +EOSLURMCTLD + touch $slurmctld_flags + + if [[ ! -f $slurmctld_flags ]]; then + systemctl restart slurmctld &>/dev/null + systemctl is-enabled slurmctld &>/dev/null || systemctl enable slurmctld &>/dev/null + fi + + echo "$SSEP" + /usr/bin/sacctmgr show clusters format=cluster,controlhost,controlport,qos + #/usr/bin/sacctmgr show clusters format=cluster,controlhost,controlport --noheader + echo "$SSEP" + /usr/bin/sinfo -N -l | tail -n +2 + echo "$SSEP" +} + +# ====================== 核心函数:节点解析 ====================== +load_nodes_from_file() { + local nodes_file="./nodes" + + # 如果文件不存在,使用默认内置节点 + if [[ ! -f "${nodes_file}" ]]; then + log_debug "节点文件 ${nodes_file} 不存在,使用内置默认节点" + return + fi + + # 读取文件,去空行、去注释、去重、去前后空格 + mapfile -t lines < "${nodes_file}" + DEFAULT_NODES=() + for line in "${lines[@]}"; do + # 跳过空行/空白行 + [ -z "${line// /}" ] && continue + + # 把一行切成数组(按空格分割) + cols=($line) + + node="${cols[0]}" # 节点名称(必须) + port="${cols[1]:-22}" # 端口不存在 -> 默认 22 + addr="${cols[2]:-}" # IP 不存在 -> 默认空字符串 + + # 按空格分割成数组 + GLOBAL_PORT["$node"]=${port} + + # 去掉空格 + 跳过空行/注释行 + clean_line=$(echo "${node}" | xargs) + [[ -z "${clean_line}" || "${clean_line}" =~ ^# ]] && continue + DEFAULT_NODES+=("${node}") + done + + log_info "成功从 nodes 文件加载节点:${#DEFAULT_NODES[@]} 个" + log_debug "nodes 文件节点列表:${DEFAULT_NODES[*]}" +} + +parse_nodes() { + local node_val="$1" + GLOBAL_NODES=() + + if [[ "$node_val" == "all" ]]; then + GLOBAL_NODES=("${DEFAULT_NODES[@]}") + else + IFS=',' read -ra tmp <<< "$node_val" + GLOBAL_NODES=("${tmp[@]}") + fi + + GLOBAL_OPTS[nodes]="$node_val" +} + +# 检查节点状态(online/offline/auth/pass) +check_node_status() { + local node="$1" + port=${GLOBAL_PORT[$node]} + + # 检查网络连通性 + if ! ping -c 1 -W 1 "$node" &>/dev/null; then + echo "offline" + return + fi + + # 检查是否是本机 + localhost=$(hostname -s) + if [[ "$node" == "localhost" || "$node" == $localhost ]]; then + echo "localhost" + return + fi + + # 检查SSH免密登录 + if ssh -o ConnectTimeout=1 -o BatchMode=yes -o StrictHostKeyChecking=accept-new -p $port "$node" true &>/dev/null; then + echo "online,auth" + else + echo "online,pass" + fi +} + +list_node() { + echo "$SSEP" + printf "${G}%-12s %-15s %-8s %s${NC}\n" "Nodename" "Status" "Port" "Days" + echo "$SSEP" + for node in "${GLOBAL_NODES[@]}"; do + status=$(check_node_status "$node") + port=${GLOBAL_PORT[$node]} + + if [[ "$status" == "offline" ]]; then + uptime_days="---" + else + uptime_days=$(ssh -o ConnectTimeout=1 -o BatchMode=yes -p$port "$node" "uptime \ + | awk -F'up|days' '{print \$2}' | tr -d ',' | xargs" 2>/dev/null || echo "---") + fi + + printf "%-12s %-15s %-8s %s\n" "$node" "$status" "$port" "$uptime_days" + done + echo "$SSEP" +} + +run_cmd() { + local node="$1" + local cmds="$2" + local output="" + local exit_code=0 + + # 获取本机主机名(自动识别管理节点) + local localhost=$(hostname -s) + if [[ "$node" == "$localhost" || "$node" == "localhost" ]]; then + # ====================== 本机:直接执行 ====================== + output=$(eval "$cmds" 2>&1) + exit_code=$? + else + # ====================== 远程:SSH 执行 ====================== + output=$(ssh -o ConnectTimeout=1 -o BatchMode=yes "$node" "$cmds" 2>&1) + exit_code=$? + fi + + + if [[ $exit_code -eq 0 ]]; then + info "执行成功: ${node}" + else + warn "执行失败: ${node} (${R}Code${NC}: ${R}$exit_code${NC})" + fi + echo "$DSEP" + + echo "$output" +} + + + +# ====================== 核心函数: 同步文件路径处理 ====================== +sync_file_path() { + local src_file="$1" + + # ======================== 核心规则 ======================== + # 1. 如果源是 绝对路径(/开头),直接返回原路径(系统目录) + if [[ "$src_file" == /* ]]; then + echo "$src_file" + return + fi + + # 2. 如果源是 相对路径(linux/alls/* 或 linux/节点/*) + # 自动去掉 linux/xxx/ 前缀,剩余部分自动变成 绝对路径(前面加 /) + # 支持:etc usr opt var home root 任意目录,无限扩展 + # ================================================== + local rel_path + rel_path=$(echo "$src_file" | sed -E 's#^linux/(alls|[-_a-zA-Z0-9]+)/##') + + # 拼接为绝对路径 + echo "/$rel_path" +} + +sync_file_all() { + load_nodes "$NODE_ARG" + + # ===================== 美化打印节点列表(固定缩进 + 自动换行) ===================== + local indent=" " # 11个空格 + local line="" + local count=0 + local max_per_line=5 # 每行显示几个节点 + + info "开始同步所有节点文件,节点列表:" + for node in "${NODES[@]}"; do + line+="$node " + count=$((count + 1)) + + if [[ $count -ge $max_per_line ]]; then + echo -e "${indent}${line}" + line="" + count=0 + fi + done + + # 打印剩余不足一行的节点 + if [[ -n "$line" ]]; then + echo -e "${indent}${line}" + fi + # ================================================================================ + for node_dir in linux/*; do + [[ -d "$node_dir" ]] || continue + + for sub_dir in "$node_dir"/*; do + [[ -d "$sub_dir" ]] || continue + + info "处理源目录:$sub_dir" + + for node in "${NODES[@]}"; do + if [[ "$node_dir" == "linux/alls" || "$node_dir" == "linux/$node" ]]; then + target=$(sync_file_path "$sub_dir") + info "同步 ${Y}$sub_dir${NC} -> ${R}$node${NC}:${Y}$target${NC}" + rsync -avzAP --info=progress2 --exclude='.*' "$sub_dir"/ "$node":"$target"/ + fi + done + done + done + + info "同步完成!" +} + +sync_file_single() { + local src_file="$1" + [[ -z "$src_file" ]] && error "请使用 -f 指定文件路径" + [[ -e "$src_file" ]] || error "文件不存在:$src_file" + + load_nodes "$NODE_ARG" + + local indent=" " # 11个空格 + local line="" + local count=0 + local max_per_line=5 # 每行显示几个节点 + + info "开始同步所有节点文件,节点列表:" + for node in "${NODES[@]}"; do + line+="$node " + count=$((count + 1)) + + if [[ $count -ge $max_per_line ]]; then + echo -e "${indent}${line}" + line="" + count=0 + fi + done + + # 打印剩余不足一行的节点 + if [[ -n "$line" ]]; then + echo -e "${indent}${line}" + fi + + target=$(sync_file_path "$src_file") + for node in "${NODES[@]}"; do + info "同步 ${Y}$src_file${NC} -> ${R}$node${NC}:${Y}$target${NC}" + rsync -avzAP --info=progress2 "$src_file" "$node":"$target" + done + info "同步完成!" +} +# ====================== 帮助文档 ====================== +show_help() { + cat < [OPTIONS] + +公共参数: + -v, --verbose 详细输出 + -d, --debug 调试模式 + -h, --help 帮助信息 + -n, --nodes 指定节点(all 或 node1,node2,node3) + +支持命令: + sunhpc pxe dhcp 部署dhcp服务 + sunhpc pxe tftp 部署tftp服务 + sunhpc pxe http 部署http服务 + sunhpc pxe dnsmasq 部署pxe服务 + sunhpc exec 批量执行命令 + sunhpc sync file 执行同步任务 + sunhpc list node 查看节点列表 + sunhpc show vimrc 显示Vimrc变量 + sunhpc show system 显示系统信息 + sunhpc serv slurm 构建 slurm 服务 + sunhpc serv autofs 构建 autofs 服务 + sunhpc create syncfile 显示系统信息 + +Report bugs to: +Htool URL: https://gitea.sunhpc.com +Gitea URL: https://gitea.sunhpc.com/htool.git +EOF +} + +show_help_sync() { + cat < [OPTIONS] + +公共参数: + -v, --verbose 详细输出 + -d, --debug 调试模式 + -h, --help 帮助信息 + -n, --nodes 指定节点(all 或 node1,node2,node3) + +命令示例: + sunhpc sync file -f/--file 同步单个文件 + sunhpc sync file -a/--all 同步所有文件 + +Report bugs to: +Htool URL: https://gitea.sunhpc.com +Gitea URL: https://gitea.sunhpc.com/htool.git +EOF +} + +show_help_slurm() { + cat < [OPTIONS] + +公共参数: + -v, --verbose 详细输出 + -d, --debug 调试模式 + -h, --help 帮助信息 + -n, --nodes 指定节点(all 或 node1,node2,node3) + +命令示例: + sunhpc serv slurm -b/--build 构建Slurm安装包 + sunhpc serv slurm -i/--install -m/master 安装Slurm到管理节点 + sunhpc serv slurm -i/--install -c/compute 安装Slurm到计算节点 + +Report bugs to: +Htool URL: https://gitea.sunhpc.com +Gitea URL: https://gitea.sunhpc.com/htool.git +EOF +} + +# ====================== Verbose/Debug 输出工具 ====================== +log_info() { + if [[ -n "${GLOBAL_OPTS[v]}" || -n "${GLOBAL_OPTS[verbose]}" ]]; then + echo -e "\033[32m[I]\033[0m $1" + fi +} + +log_debug() { + if [[ -n "${GLOBAL_OPTS[d]}" || -n "${GLOBAL_OPTS[debug]}" ]]; then + echo -e "\033[33m[D]\033[0m $1" + fi +} + +# ====================== 子命令执行 ====================== +run_pxe_dhcp() { + log_debug "--------- run_pxe_dhcp----------------" + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + # -n 非空True,-z 为空True + [[ -n ${GLOBAL_OPTS[interface]} ]] && pxe_dhcp_build || \ + warn "请指定DHCP监听接口命名, 例如: sunhpc pxe dhcp -i eth0" +} +run_pxe_tftp() { + log_debug "--------- run_pxe_tftp----------------" + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + pxe_tftp_build +} +run_pxe_http() { + log_debug "--------- run_pxe_http----------------" + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + pxe_http_build +} + +run_init() { + + [[ -n "${GLOBAL_OPTS[interface]}" ]] && iface="${GLOBAL_OPTS[interface]}" || \ + error "必须指定一个网络接口,例如: -i/--interface eth1" + + [[ -n "${GLOBAL_OPTS[html]-}" ]] && html="${GLOBAL_OPTS[html]}" || \ + error "必须指定 html 路径,例如: --html /var/www/html" + + ipaddr=${global_env[${iface}_ip]} + netcidr=${global_env[${iface}_mask]} + netmask=$(cidr_to_netmask 24) + subnet=$(get_subnet_address $ipaddr $netmask) + + IFS=. read -r i1 i2 i3 i4 <<< "$ipaddr" + start_ip="$i1.$i2.$i3.10" + ender_ip="$i1.$i2.$i3.90" + + + tmpdir=$(find -L $html -name ".treeinfo") + tmpdir=$(dirname ${tmpdir#$html}) + + echo "iface---------> $iface" + echo "addr----------> $ipaddr" + echo "startip-------> $start_ip" + echo "enderip-------> $ender_ip" + echo "htmlroot------> $html" + echo "reporoot------> $tmpdir" + exit 1 + + { + echo "interface $iface" + echo "server $ipaddr" + echo "range $start_ip,$ender_ip" + echo "htmlroot $html" + echo "reporoot $tmpdir" + } > ${config_file} + #gen_config_file +} + +run_exec() { + log_debug "--------- run_exec----------------" + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + local cmds=$1 + [[ -z "$cmds" ]] && error "请指定要执行的命令,例如:sunhpc exec \"df -h\"" + + echo "$DSEP" + info "执行命令: $cmds" + + localhost=$(hostname -s) + for node in "${GLOBAL_NODES[@]}"; do + if [[ "$node" != "$localhost" || "$node" != "localhost" ]]; then + status=$(check_node_status "$node") + if [[ "$status" == "offline" ]]; then + warn "$node 节点离线,跳过执行" + continue + fi + if [[ "$status" == "online,pass" ]]; then + warn "$node 需要密码登录,跳过执行" + continue + fi + fi + + # ========== 核心:自动本机/远程执行 ========== + run_cmd "$node" "$cmds" + + done + echo "$SSEP" + info "命令执行完成!" + echo "$SSEP" +} + +run_sync() { + log_debug "--------- run_sync----------------" + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + case "${PRIVATE_ARGS[@]}" in + -a|--all) sync_file_all ;; + -f|--file) sync_file_single ;; + *) show_help_sync ;; + esac + +} + +run_list_node() { + log_debug "--------- run_list_node----------------" + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + log_info "执行 list node" + log_info "当前节点列表:${GLOBAL_NODES[*]}" + list_node +} + +run_show_vimrc() { + cat <<-EOF +" 开启语法高亮 +syntax enable + +" 设置缩进为4个空格 +set tabstop=4 +set softtabstop=4 +set shiftwidth=4 + +" 用空格替代Tab键(禁止输入真实Tab) +set expandtab + +" 自动缩进(写代码更方便) +set autoindent +set smartindent +EOF +} + +run_serv_slurm() { + log_debug "--------- run_serv_slurm------------------" + case "${PRIVATE_ARGS[@]}" in + -b|--build) slurm_build ;; + *) show_help_slurm ;; + esac +} + +run_serv_autofs() { + log_debug "--------- run_serv_autofs----------------" + log_debug "当前节点:${GLOBAL_NODES[*]}" + log_debug "公共参数:${PUBLIC_ARGS[*]}" + log_debug "私有参数:${PRIVATE_ARGS[*]}" + + log_info "执行 server autofs" + if [[ " ${PRIVATE_ARGS[@]} " =~ " --build " ]]; then + log_debug "检测到 --build 参数,开始构建..." + echo "✅ 正在构建 autofs 服务" + fi +} + +create_sync_file() { + dirspath=( + "/etc/passwd" + "/etc/shadow" + "/etc/group" + "/etc/slurm" + "/etc/systemd/system" + "/usr/lib/systemd/system" + ) + + local base="${1:-.}" + local name="${2:-linux}" + local all_dir="${base}/${name}/all" + + mkdir -p "${all_dir}" || return 1 + for d in "${dirspath}"; do + if [[ -f $d ]]; then + src_dir=$(dirname "$d") + dst_dir="${all_dir}/$src_dir" + mkdir -p "${dst_dir}" + /usr/bin/cp $d ${dst_dir} + else + mkdir -p "${all_dir}/${d}" + fi + done + + for n in ${GLOBAL_NODES[@]}; do + mkdir -p "${base}/${name}/${n}" + done + +} + +# ====================== 命令路由 ====================== +dispatch() { + # 优先显示帮助 + if [[ -n "${GLOBAL_OPTS[h]}" || -n "${GLOBAL_OPTS[help]}" || ${#CMD_STACK[@]} -eq 0 ]]; then + show_help + exit 0 + fi + + log_debug "$DSEP" + log_debug "解析子命令:${CMD_STACK[*]}" + log_debug "专属参数 :${PRIVATE_ARGS[*]}" + + case "${CMD_STACK[0]}" in + pxe) + case "${CMD_STACK[1]}" in + dhcp) run_pxe_dhcp ;; + tftp) run_pxe_tftp;; + http) run_pxe_http;; + dnsmasq) pxe_dnsmasq_build;; + *) show_help;; + esac + ;; + exec) + run_exec "${CMD_STACK[1]}" + ;; + sync) + case "${CMD_STACK[1]}" in + file) run_sync ;; + *) show_help ;; + esac + ;; + list) + case "${CMD_STACK[1]}" in + node) run_list_node ;; + *) show_help ;; + esac + ;; + show) + case "${CMD_STACK[1]}" in + vimrc) run_show_vimrc ;; + system) show_system_summary ;; + *) show_help;; + esac + ;; + serv) + case "${CMD_STACK[1]}" in + slurm) run_serv_slurm ;; + autofs) run_serv_autofs ;; + *) show_help;; + esac + ;; + create) + case "${CMD_STACK[1]}" in + syncfile) create_sync_file ;; + *) show_help ;; + esac + ;; + *) show_help ;; + esac +} + +# ====================== 核心函数:参数解析 ====================== +parse_args() { + while [[ $# -gt 0 ]]; do + local arg="$1" + case "$arg" in + # 公共短参数:-v -d -h -n + -v) GLOBAL_OPTS[v]=1; GLOBAL_OPTS[verbose]=1; PUBLIC_ARGS+=("$arg"); shift ;; + -d) GLOBAL_OPTS[d]=1; GLOBAL_OPTS[debug]=1; PUBLIC_ARGS+=("$arg"); shift ;; + -h) GLOBAL_OPTS[h]=1; GLOBAL_OPTS[help]=1; PUBLIC_ARGS+=("$arg"); shift ;; + -f) GLOBAL_OPTS[file]=$2; PUBLIC_ARGS+=("$arg" "$2"); shift 2 ;; + -i) GLOBAL_OPTS[interface]=$2; PUBLIC_ARGS+=("$arg" "$2"); shift 2 ;; + -n) parse_nodes "$2"; PUBLIC_ARGS+=("$arg" "$2"); shift 2 ;; + + # 公共长参数:--verbose --debug --help --nodes + --verbose) GLOBAL_OPTS[verbose]=1; GLOBAL_OPTS[v]=1; PUBLIC_ARGS+=("$arg"); shift ;; + --debug) GLOBAL_OPTS[debug]=1; GLOBAL_OPTS[d]=1; PUBLIC_ARGS+=("$arg"); shift ;; + --help) GLOBAL_OPTS[help]=1; GLOBAL_OPTS[h]=1; PUBLIC_ARGS+=("$arg"); shift ;; + --file) GLOBAL_OPTS[file]=$2; PUBLIC_ARGS+=("$arg" "$2"); shift 2 ;; + --html) GLOBAL_OPTS[html]=$2; PUBLIC_ARGS+=("$arg" "$2"); shift 2 ;; + --interface) GLOBAL_OPTS[interface]=$2; PUBLIC_ARGS+=("$arg" "$2"); shift 2 ;; + --nodes) parse_nodes "$2"; PUBLIC_ARGS+=("$arg" "$2"); shift 2 ;; + + # -- 专属短参数(子命令私有) + -*) PRIVATE_ARGS+=("$arg"); shift ;; + # -- 专属长参数(子命令私有) + --*) PRIVATE_ARGS+=("$arg"); shift ;; + + # 子命令(无 - / --) + *) CMD_STACK+=("$arg"); shift ;; + esac + done +} + +# ====================== 主入口 ====================== +main() { + # 配置文件 + config_file="htool.conf" + + # load system env + load_os_envs + + # 启动时先加载 nodes 文件 + load_nodes_from_file + + # 默认使用文件中的节点 + GLOBAL_NODES=("${DEFAULT_NODES[@]}") + + parse_args "$@" + + # 获取基础信息存储变量 + if [[ -e $config_file ]]; then + load_conf_envs + else + run_init + fi + + dispatch +} + +main "$@"