Skip to content

Commit 5af5a22

Browse files
committed
pciclient: add AMD GPU detection via PCI enumeration
Signed-off-by: Gaurav Sharma <[email protected]>
1 parent a30299e commit 5af5a22

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

sources/pciclient/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ pciclient provides util functions that can:
88
mod private;
99

1010
use private::{
11-
call_list_devices, check_efa_attachment, check_inf1_attachment, check_inf2_attachment,
12-
check_neuron_attachment, PciClient,
11+
call_list_devices, check_amd_gpu_attachment, check_efa_attachment, check_inf1_attachment,
12+
check_inf2_attachment, check_neuron_attachment, PciClient,
1313
};
1414

1515
use bon::Builder;
@@ -123,6 +123,11 @@ pub fn is_neuron_attached() -> Result<bool> {
123123
check_neuron_attachment(PciClient {})
124124
}
125125

126+
/// Call `lspci` and check if there is any AMD GPU device attached.
127+
pub fn is_amd_gpu_attached() -> Result<bool> {
128+
check_amd_gpu_attachment(PciClient {})
129+
}
130+
126131
/// Call `lspci` and check if there are inf1 devices attached
127132
pub fn is_inf1_instance() -> Result<bool> {
128133
check_inf1_attachment(PciClient {})

sources/pciclient/src/private.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414

1515
const AMAZON_VENDOR_CODE: &str = "1d0f";
1616
const EFA_KEYWORD: &str = "efa";
17+
const AMD_VENDOR_CODE: &str = "1002";
1718

1819
// Neuron devices specific to inf1 instance types
1920
lazy_static! {
@@ -34,6 +35,12 @@ lazy_static! {
3435
};
3536
}
3637

38+
lazy_static! {
39+
static ref AMD_GPU_DEVICES: HashSet<&'static str> = hashset! {
40+
"75a3" // AMD Instinct MI355X
41+
};
42+
}
43+
3744
const LSPCI_PATH: &str = "/usr/bin/lspci";
3845

3946
pub(crate) trait CommandExecutor {
@@ -183,6 +190,19 @@ pub(crate) fn check_neuron_attachment<T: CommandExecutor>(command_executor: T) -
183190
}))
184191
}
185192

193+
/// Call `lspci` and check if there is any AMD GPU device attached.
194+
/// Internal usage, adding command_executor as parameter allows us to better unit test.
195+
/// For external usage, check [`crate::is_amd_gpu_attached`].
196+
pub(crate) fn check_amd_gpu_attachment<T: CommandExecutor>(command_executor: T) -> Result<bool> {
197+
let list_devices_param = ListDevicesParam::builder()
198+
.vendor(AMD_VENDOR_CODE.to_string())
199+
.build();
200+
let list_device_results = call_list_devices(command_executor, list_devices_param)?;
201+
Ok(list_device_results
202+
.iter()
203+
.any(|device_info| AMD_GPU_DEVICES.contains(&device_info.device.as_str())))
204+
}
205+
186206
/// Call `lspci` and check if there is any inf1-specific Neuron device attached.
187207
/// Internal usage, adding command_executor as parameter allows us to better unit test.
188208
/// For external usage, check [`crate::is_inf1_instance`].
@@ -228,8 +248,8 @@ mod test {
228248
use crate::{ListDevicesOutput, ListDevicesParam, Result};
229249

230250
use super::{
231-
call_list_devices, check_efa_attachment, check_inf1_attachment, check_neuron_attachment,
232-
parse_list_devices_output, CommandExecutor,
251+
call_list_devices, check_amd_gpu_attachment, check_efa_attachment, check_inf1_attachment,
252+
check_neuron_attachment, parse_list_devices_output, CommandExecutor,
233253
};
234254

235255
struct MockPciClient {
@@ -436,6 +456,31 @@ mod test {
436456
assert!(check_inf1_attachment_result.unwrap());
437457
}
438458

459+
#[test]
460+
fn test_is_amd_gpu_attached() {
461+
let mock_pci_client = MockPciClient {
462+
// AMD Instinct MI355X device has vendor 1002 for AMD, device code 75a3.
463+
output: vec![
464+
r#"00:1e.0 "0300" "1002" "75a3" -p00 "1002" "0123""#.to_string(),
465+
r#"00:1f.0 "0302" "10de" "1eb8" -ra1 -p00 "10de" "12a2""#.to_string(),
466+
],
467+
};
468+
let check_amd_gpu_attachment_result = check_amd_gpu_attachment(mock_pci_client);
469+
assert!(check_amd_gpu_attachment_result.is_ok());
470+
assert!(check_amd_gpu_attachment_result.unwrap());
471+
}
472+
473+
#[test]
474+
fn test_is_amd_gpu_attached_negative_case() {
475+
let mock_pci_client = MockPciClient {
476+
// Below is an actual output from lspci for ena device (not AMD GPU).
477+
output: vec![r#"00:06.0 "0200" "1d0f" "ec20" -p00 "1d0f" "ec20""#.to_string()],
478+
};
479+
let check_amd_gpu_attachment_result = check_amd_gpu_attachment(mock_pci_client);
480+
assert!(check_amd_gpu_attachment_result.is_ok());
481+
assert!(!check_amd_gpu_attachment_result.unwrap());
482+
}
483+
439484
#[test]
440485
fn test_is_inf1_attached_negative_case() {
441486
let mock_pci_client = MockPciClient {

0 commit comments

Comments
 (0)