This rust crate provides Rust bindings for the AMD System Management Interface (AMD-SMI) library. It allows you to interact with AMD GPUs and retrieve various information using Rust.
- [Adding New API and Tests](#adding-new-api-and-tests)
## Overview
The AMD SMI Rust binding crate automates the generation of bindings and ensures safety, maintainability, and ease of use. The implementation consists of two main steps:
1.**Generating Bindings with `bindgen`**:
- The `build.rs` script uses `bindgen` to automatically generate Rust FFI (Foreign Function Interface) bindings for the AMD SMI C library. This step exports all enums, structs, unions, and unsafe functions from the C library into Rust, providing a comprehensive low-level interface to the AMD SMI library.
2.**Implementing Safe Rust Wrappers**:
- The generated bindings are then wrapped in safe Rust functions. These safe wrappers handle error checking, resource management, and provide a more idiomatic Rust interface. This ensures that users of the library can interact with the AMD SMI functions without dealing with unsafe code directly.
## Hello World Example
Here is a simple "Hello World" example to get you started with the AMD SMI Rust bindings. This example initializes the AMD SMI library, retrieves the GPU information, and prints it to the console.
```
use amdsmi::*;
fn main() {
// Initialize the AMD SMI library
if let Err(e) = amdsmi_init(AmdsmiInitFlagsT::AmdsmiInitAmdGpus) {
eprintln!("Failed to initialize AMD SMI: {}", e);
return;
}
// Get socket handles
let socket_handles = match amdsmi_get_socket_handles() {
Ok(handles) => handles,
Err(e) => {
eprintln!("Failed to get socket handles: {}", e);
amdsmi_shut_down().expect("Failed to shutdown AMD SMI");
return;
}
};
for socket_handle in socket_handles {
// Get processor handles for each socket handle
let processor_handles = match amdsmi_get_processor_handles(socket_handle) {
Ok(handles) => handles,
Err(e) => {
eprintln!(
"Failed to get processor handles for socket {:?}: {}",
socket_handle, e
);
continue;
}
};
for processor_handle in processor_handles {
// Get GPU ID using the processor handle
match amdsmi_get_gpu_id(processor_handle) {
Ok(gpu_id) => println!("GPU ID: {}", gpu_id),
Err(e) => eprintln!("Failed to get GPU ID: {}", e),
Err(e) => eprintln!("Failed to get GPU VRAM vendor: {}", e),
}
// Get GPU BDF using the processor handle
match amdsmi_get_gpu_device_bdf(processor_handle) {
Ok(gpu_bdf) => println!("GPU BDF: {}", gpu_bdf),
Err(e) => eprintln!("Failed to get GPU BDF: {}", e),
}
println!();
}
}
// Shutdown the AMD SMI library
if let Err(e) = amdsmi_shut_down() {
eprintln!("Failed to shutdown AMD SMI: {}", e);
}
}
```
## Directory Structure
```
amd-smi/rust-interface
├── Cargo.toml # Cargo configuration file
├── CMakeLists.txt # CMake configuration file for building the AMD SMI library
├── build.rs # Build script for generating bindings
├── src/
│ ├── lib.rs # Library entry point
│ ├── amdsmi.rs # Main module for AMD SMI bindings
│ ├── utils.rs # Utility functions and helpers
│ └── amdsmi_wrapper.rs # Automatically generate FFI bindings by `bindgen`
└── examples # Example programs demonstrating usage
```
## Building
To build this Rust binding, you need to have Rust and Cargo installed.
### Option 1: Using CMake
Navigate to the project's root directory and use the project's CMake build system. You need to define the `BUILD_RUST_WRAPPER` option. This will build this Rust interface and integrate it with the rest of the project.
```sh
mkdir build
cd build
cmake -DBUILD_RUST_WRAPPER=ON ..
make
sudo make install
```
### Option 2: Using Cargo
Alternatively, you can navigate to the `rust-interface` folder and build the project using Cargo.
The `amdsmi_wrapper.rs` file contains automatically generated FFI (Foreign Function Interface) bindings from the AMD SMI C library. **Do not edit this file manually** as any changes will be overwritten during regeneration. Bindings are not automatically regenerated during normal builds unless the `AMDSMI_GENERATE_RUST_WRAPPER` environment variable is explicitly set.
Replace `example_name` with the name of the example you want to run. For example, if you have an example named `amdsmi_get_gpu_info`, you can run it as follows:
- To regenerate the bindings using `bindgen` according to the latest `amdsmi.h`, set the `AMDSMI_GENERATE_RUST_WRAPPER` environment variable and rebuild (see [Regenerating FFI Bindings](#regenerating-ffi-bindings)).