- name
- library-amd-smi
- description
- AMD SMI C++ library for GPU/CPU/NIC monitoring and management. Use when working with AMD hardware monitoring, GPU temperature, power, memory, clocks, PCIe, XGMI, SDMA (System DMA), AINIC (AI NIC) network interfaces, or any amdsmi.h functions.
# AMD SMI C++ Library
AMD System Management Interface library for monitoring and managing AMD GPUs, CPUs, and AI NICs.
## Header and Linking
```cpp
#include "amd_smi/amdsmi.h"
```
```bash
# Build (GPU-only)
g++ -I/opt/rocm/include source.cc -L/opt/rocm/lib -lamd_smi -o output
# Build with NIC/CPU support (enables amdsmi_get_processor_handles_by_type)
g++ -DENABLE_ESMI_LIB -I/opt/rocm/include source.cc -L/opt/rocm/lib -lamd_smi -o output
# Set LD_LIBRARY_PATH for runtime
export LD_LIBRARY_PATH=/opt/rocm/lib:$LD_LIBRARY_PATH
# Test with fake AINIC devices (for development without hardware)
AMDSMI_FAKE_AINIC=1 ./output
```
## Initialization Pattern
Every AMD SMI application must initialize and shut down properly:
```cpp
amdsmi_status_t ret;
// Initialize for GPUs only
ret = amdsmi_init(AMDSMI_INIT_AMD_GPUS);
// Or for CPUs only
ret = amdsmi_init(AMDSMI_INIT_AMD_CPUS);
// Or for AI NICs only
ret = amdsmi_init(AMDSMI_INIT_AMD_NICS);
// Or for all processors
ret = amdsmi_init(AMDSMI_INIT_ALL_PROCESSORS);
// ... use the library ...
// Clean up - MUST be called
ret = amdsmi_shut_down();
```
## Core Concepts
### Handles Hierarchy
```
Socket → Processor (GPU/CPU/NIC) → Core (for CPUs)
```
- **Socket handle**: Physical hardware socket
- **Processor handle**: GPU, CPU, or NIC within a socket (may change between app restarts)
- **Device handles are NOT persistent** across processes
### Getting Handles
```cpp
// Get socket count and handles
uint32_t socket_count = 0;
amdsmi_get_socket_handles(&socket_count, nullptr); // Get count
std::vector<amdsmi_socket_handle> sockets(socket_count);
amdsmi_get_socket_handles(&socket_count, sockets.data());
// Get processor handles for a socket (GPUs only - does NOT return NICs!)
uint32_t device_count = 0;
amdsmi_get_processor_handles(sockets[0], &device_count, nullptr);
std::vector<amdsmi_processor_handle> processors(device_count);
amdsmi_get_processor_handles(sockets[0], &device_count, processors.data());
// Get processors by type (supports ALL processor types including NICs)
processor_type_t type = AMDSMI_PROCESSOR_TYPE_AMD_GPU;
amdsmi_get_processor_handles_by_type(socket, type, nullptr, &count);
```
### Processor Handle Functions Comparison
| Function | Returns | Use Case |
|----------|---------|----------|
| `amdsmi_get_processor_handles()` | **GPUs only** | Legacy GPU-only code |
| `amdsmi_get_processor_handles_by_type()` | GPUs, NICs, CPUs, APUs | **Recommended** - supports all processor types |
**CRITICAL**: `amdsmi_get_processor_handles()` only returns GPU processors. It will **NOT** return NICs, CPUs, or other processor types even if they exist in the system. For NICs, CPUs, or mixed workloads, you **MUST** use `amdsmi_get_processor_handles_by_type()` with the appropriate processor type constant.
```cpp
// WRONG - will miss NICs!
auto handles = amdsmi_get_processor_handles(socket, &count, nullptr);
// CORRECT - explicitly query for NICs
amdsmi_get_processor_handles_by_type(socket, AMDSMI_PROCESSOR_TYPE_AMD_NIC, nullptr, &count);
// CORRECT - explicitly query for GPUs (preferred over legacy function)
amdsmi_get_processor_handles_by_type(socket, AMDSMI_PROCESSOR_TYPE_AMD_GPU, nullptr, &count);
```
### Processor Types
- `AMDSMI_PROCESSOR_TYPE_AMD_GPU` - AMD GPU
- `AMDSMI_PROCESSOR_TYPE_AMD_CPU` - AMD CPU
- `AMDSMI_PROCESSOR_TYPE_AMD_CPU_CORE` - CPU core
- `AMDSMI_PROCESSOR_TYPE_AMD_APU` - AMD APU
- `AMDSMI_PROCESSOR_TYPE_AMD_NIC` - AI Network Interface Card
## Common GPU Queries
### Temperature
```cpp
int64_t temp;
amdsmi_get_temp_metric(processor, AMDSMI_TEMPERATURE_TYPE_EDGE,
AMDSMI_TEMP_CURRENT, &temp);
// Temperature types: EDGE, JUNCTION, HOTSPOT, VRAM, HBM_0-3, PLX
// Metrics: CURRENT, MAX, MIN, CRITICAL, EMERGENCY, SHUTDOWN
```
### Power
```cpp
amdsmi_power_info_t power_info;
amdsmi_get_power_info(processor, &power_info);
// power_info.current_socket_power, average_socket_power, etc.
// Power cap
amdsmi_power_cap_info_t cap_info;
amdsmi_get_power_cap_info(processor, 0, &cap_info);
```
### Memory
```cpp
// Total memory
uint64_t total;
amdsmi_get_gpu_memory_total(processor, AMDSMI_MEM_TYPE_VRAM, &total);
// Memory usage
uint64_t used;
amdsmi_get_gpu_memory_usage(processor, AMDSMI_MEM_TYPE_VRAM, &used);
// Memory types: VRAM, VIS_VRAM, GTT
```
### Clocks
```cpp
amdsmi_clk_info_t clk_info;
amdsmi_get_clock_info(processor, AMDSMI_CLK_TYPE_GFX, &clk_info);
// clk_info.clk (current), max_clk, min_clk
// Clock types: GFX, MEM, SOC, SYS, DF, DCEF, VCLK0/1, DCLK0/1, PCIE
```
### GPU Activity/Utilization
```cpp
amdsmi_engine_usage_t usage;
amdsmi_get_gpu_activity(processor, &usage);
// usage.gfx_activity, umc_activity, mm_activity (percentages)
uint32_t busy_percent;
amdsmi_get_gpu_busy_percent(processor, &busy_percent);
```
### Process List with Resource Usage
```cpp
// Get processes running on GPU
uint32_t num_processes = 0;
amdsmi_get_gpu_process_list(processor, &num_processes, nullptr); // Get count
std::vector<amdsmi_proc_info_t> proc_list(num_processes);
amdsmi_get_gpu_process_list(processor, &num_processes, proc_list.data());
for (const auto& proc : proc_list) {
std::cout << "PID: " << proc.pid << " Name: " << proc.name << std::endl;
std::cout << " Memory: " << proc.mem / 1024 << " KB" << std::endl;
std::cout << " GTT: " << proc.memory_usage.gtt_mem / 1024 << " KB" << std::endl;
std::cout << " VRAM: " << proc.memory_usage.vram_mem / 1024 << " KB" << std::endl;
std::cout << " CPU: " << proc.memory_usage.cpu_mem / 1024 << " KB" << std::endl;
std::cout << " GFX engine: " << proc.engine_usage.gfx << " ns" << std::endl;
std::cout << " ENC engine: " << proc.engine_usage.enc << " ns" << std::endl;
std::cout << " SDMA usage: " << proc.sdma_usage << " us" << std::endl;
std::cout << " CU occupancy: " << proc.cu_occupancy << std::endl;
std::cout << " Evicted time: " << proc.evicted_time << " ms" << std::endl;
}
```
#### amdsmi_proc_info_t Structure
```cpp
typedef struct {
uint32_t pid; // Process ID
char name[AMDSMI_MAX_STRING_LENGTH]; // Process name
uint64_t mem; // Total memory (bytes)
struct {
uint64_t gtt_mem; // GTT memory usage (bytes)
uint64_t cpu_mem; // CPU memory usage (bytes)
uint64_t vram_mem; // VRAM memory usage (bytes)
} memory_usage;
struct {
uint64_t gfx; // GFX engine usage (nanoseconds)
uint64_t enc; // Encoder engine usage (nanoseconds)
} engine_usage;
char container_name[AMDSMI_MAX_STRING_LENGTH];
uint32_t cu_occupancy; // Number of CUs utilized
uint32_t evicted_time; // Queue eviction time (milliseconds)
uint64_t sdma_usage; // SDMA usage (microseconds)
} amdsmi_proc_info_t;
```
### Device Info
```cpp
// Board info (product name, serial, etc.)
amdsmi_board_info_t board_info;
amdsmi_get_gpu_board_info(processor, &board_info);
// ASIC info
amdsmi_asic_info_t asic_info;
amdsmi_get_gpu_asic_info(processor, &asic_info);
// VRAM info
amdsmi_vram_info_t vram_info;
amdsmi_get_gpu_vram_info(processor, &vram_info);
// UUID
char uuid[AMDSMI_GPU_UUID_SIZE];
amdsmi_get_gpu_device_uuid(processor, nullptr, uuid);
// BDF (Bus:Device.Function)
amdsmi_bdf_t bdf;
amdsmi_get_gpu_device_bdf(processor, &bdf);
```
### PCIe Info
```cpp
amdsmi_pcie_info_t pcie_info;
amdsmi_get_pcie_info(processor, &pcie_info);
// pcie_info.pcie_static (slot_type, max_width, max_speed)
// pcie_info.pcie_metric (current width, speed, bandwidth)
// PCIe throughput
uint64_t sent, received, max_pkt_sz;
amdsmi_get_gpu_pci_throughput(processor, &sent, &received, &max_pkt_sz);
```
### Fan Speed
```cpp
int64_t speed;
amdsmi_get_gpu_fan_speed(processor, 0, &speed);
int64_t max_speed;
amdsmi_get_gpu_fan_speed_max(processor, 0, &max_speed);
int64_t rpm;
amdsmi_get_gpu_fan_rpms(processor, 0, &rpm);
```
### Firmware Info
```cpp
amdsmi_fw_info_t fw_info;
amdsmi_get_fw_info(processor, &fw_info);
// fw_info.fw_list[i].fw_id, fw_version
```
## Common CPU Queries
```cpp
// CPU socket power
uint32_t power;
amdsmi_get_cpu_socket_power(processor, &power); // milliwatts
// CPU temperature
uint32_t temp;
amdsmi_get_cpu_socket_temperature(processor, &temp);
// CPU energy
uint64_t energy;
amdsmi_get_cpu_socket_energy(processor, &energy);
// Core boost limit
uint32_t boost;
amdsmi_get_cpu_core_boostlimit(core_processor, &boost);
```
## AI NIC (Network Interface Card) Functions
### Build Requirements for NIC Support
```bash
# NIC functions require -DENABLE_ESMI_LIB to access amdsmi_get_processor_handles_by_type
g++ -DENABLE_ESMI_LIB -I/opt/rocm/include source.cc -L/opt/rocm/lib -lamd_smi -o output
# Test without hardware using fake AINIC devices
AMDSMI_FAKE_AINIC=1 ./output
```
### NIC Discovery
**IMPORTANT**: `amdsmi_get_processor_handles()` does NOT return NIC processors. You MUST use `amdsmi_get_processor_handles_by_type()` with `AMDSMI_PROCESSOR_TYPE_AMD_NIC`.
```cpp
// Initialize with NIC support (or AMDSMI_INIT_ALL_PROCESSORS for mixed workloads)
amdsmi_init(AMDSMI_INIT_AMD_NICS);
// Get socket handles
uint32_t socket_count = 0;
amdsmi_get_socket_handles(&socket_count, nullptr);
std::vector<amdsmi_socket_handle> sockets(socket_count);
amdsmi_get_socket_handles(&socket_count, sockets.data());
// Get NIC processor handles (two-call pattern) - MUST use _by_type for NICs!
uint32_t nic_count = 0;
amdsmi_get_processor_handles_by_type(sockets[0],
AMDSMI_PROCESSOR_TYPE_AMD_NIC,
nullptr, &nic_count);
std::vector<amdsmi_processor_handle> nics(nic_count);
amdsmi_get_processor_handles_by_type(sockets[0],
AMDSMI_PROCESSOR_TYPE_AMD_NIC,
nics.data(), &nic_count);
```
### NIC Data Structures
在 GitHub 查看