File: README.md

package info (click to toggle)
amdsmi 7.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,428 kB
  • sloc: cpp: 42,484; python: 22,906; ansic: 12,578; sh: 762; makefile: 20
file content (265 lines) | stat: -rw-r--r-- 9,581 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# AMD SMI Rust Binding

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.

## Table of Contents

- [Overview](#overview)
- [Hello World Example](#hello-world-example)
- [Directory Structure](#directory-structure)
- [Building](#building)
- [Regenerating FFI Bindings](#regenerating-ffi-bindings)
- [Running Tests](#running-tests)
- [Running Examples](#running-examples)
- [Generating Documentation](#generating-documentation)
- [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),
            }

            // Get GPU revision using the processor handle
            match amdsmi_get_gpu_revision(processor_handle) {
                Ok(gpu_revision) => println!("GPU Revision: {}", gpu_revision),
                Err(e) => eprintln!("Failed to get GPU revision: {}", e),
            }

            // Get GPU vendor name using the processor handle
            match amdsmi_get_gpu_vendor_name(processor_handle) {
                Ok(gpu_vendor_name) => println!("GPU Vendor Name: {}", gpu_vendor_name),
                Err(e) => eprintln!("Failed to get GPU vendor name: {}", e),
            }

            // Get GPU VRAM vendor using the processor handle
            match amdsmi_get_gpu_vram_vendor(processor_handle) {
                Ok(gpu_vram_vendor) => println!("GPU VRAM Vendor: {}", gpu_vram_vendor),
                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.

```sh
cd rust-interface
cargo build
```


### Regenerating FFI Bindings

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.

To force regeneration of the bindings, you can:

```sh
# Using CMake
cd build
cmake -DBUILD_RUST_WRAPPER=ON -DREGENERATE_RUST_WRAPPER=ON ..
make

# Or using Cargo with environment variable (recommended)
cd rust-interface
AMDSMI_GENERATE_RUST_WRAPPER=1 cargo build
```

## Running Tests

To run the tests, use the following command:

```sh
cargo test --doc -- --show-output --test-threads=1
```

This command will execute all the unit tests that are defined in the API's example code within the API's documentation comments.

## Running Examples

To run the examples, use the following command:

```sh
cargo run --example example_name
```

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:

```sh
cargo run --example amdsmi_get_gpu_info
```

## Generating Documentation

To generate the documentation for the project, use the following command:

```sh
cargo doc --open
```

This will generate the documentation and open it in your default web browser.

## Adding New API and Tests

### Adding New API

1. **Update Bindings**:
   - 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)).

2. **Define the API**:
   - Add the new API function in the appropriate Rust file, e.g., `src/amdsmi.rs`.
   - Implement the function to use the `call_unsafe!` macro to call the `bindgen` generated unsafe rust FFI function in `amdsmi_wrapper.rs`.

3. **Document the API**:
   - Use Rust doc comments `///` to document the new API function. Include a description, parameters, return values, and examples.

### Adding Tests

Include examples in the documentation comments of your functions. These examples will be compiled and run as tests when you run `cargo test`.


### Example of New API

Here is an example of adding a new API function and documenting it with a doc test:

```rust
/// Retrieves the GPU ID for a given processor handle.
///
/// This function returns the GPU ID associated with the specified processor handle.
/// The GPU ID is a unique identifier for the GPU.
///
/// # Arguments
///
/// * `processor_handle` - A handle to the processor for which the GPU ID is being queried.
///
/// # Returns
///
/// * `AmdsmiResult<u32>` - Returns `Ok(u32)` containing the GPU ID if successful, or an error if it fails.
///
/// # Example
///
/// ```rust
/// # use amdsmi::*;
/// #
/// # fn main() {
/// #   // Initialize the AMD SMI library
/// #   amdsmi_init(AmdsmiInitFlagsT::AmdsmiInitAmdGpus).expect("Failed to initialize AMD SMI");
/// #
///     // Example processor_handle, assuming the number of processors is greater than zero
///     let processor_handle = amdsmi_get_processor_handles!()[0];
///
///     // Retrieve the GPU ID
///     match amdsmi_get_gpu_id(processor_handle) {
///         Ok(gpu_id) => println!("GPU ID: {}", gpu_id),
///         Err(e) => panic!("Failed to get GPU ID: {}", e),
///     }
/// #
/// #   // Shut down the AMD SMI library
/// #   amdsmi_shut_down().expect("Failed to shut down AMD SMI");
/// # }
/// ```
///
/// # Errors
///
/// This function will return the error in [`AmdsmiStatusT`] if the underlying `amdsmi_wrapper::amdsmi_get_gpu_id` call fails.
pub fn amdsmi_get_gpu_id(processor_handle: AmdsmiProcessorHandle) -> AmdsmiResult<u16> {
    let mut id: u16 = 0;
    call_unsafe!(amdsmi_wrapper::amdsmi_get_gpu_id(processor_handle, &mut id));
    Ok(id)
}
```