ironaccelerator_neuron/
drv.rs1#![allow(clippy::drop_non_drop)]
9
10use core::ffi::c_void;
11
12use libloading::{Library, Symbol};
13use once_cell::sync::OnceCell;
14
15pub type NrtStatus = u32;
16pub const NRT_SUCCESS: NrtStatus = 0;
17
18pub type NrtModelHandle = *mut c_void;
19pub type NrtTensorSetHandle = *mut c_void;
20pub type NrtTensorHandle = *mut c_void;
21
22pub type NrtLoadFn = unsafe extern "C" fn(
23 neff: *const u8,
24 neff_size: usize,
25 start_nc: i32,
26 nc_count: i32,
27 model: *mut NrtModelHandle,
28) -> NrtStatus;
29pub type NrtUnloadFn = unsafe extern "C" fn(model: NrtModelHandle) -> NrtStatus;
30pub type NrtExecuteFn = unsafe extern "C" fn(
31 model: NrtModelHandle,
32 input_set: NrtTensorSetHandle,
33 output_set: NrtTensorSetHandle,
34) -> NrtStatus;
35pub type NrtAllocTensorSetFn = unsafe extern "C" fn(out: *mut NrtTensorSetHandle) -> NrtStatus;
36pub type NrtFreeTensorSetFn = unsafe extern "C" fn(set: NrtTensorSetHandle) -> NrtStatus;
37pub type NrtAddTensorToSetFn = unsafe extern "C" fn(
38 set: NrtTensorSetHandle,
39 name: *const core::ffi::c_char,
40 tensor: NrtTensorHandle,
41) -> NrtStatus;
42
43type NrtInitFn =
44 unsafe extern "C" fn(framework: u32, framework_version: *const core::ffi::c_char) -> NrtStatus;
45type NrtGetTotalNcCountFn = unsafe extern "C" fn(count: *mut u32) -> NrtStatus;
46type NrtGetVersionFn = unsafe extern "C" fn(out: *mut core::ffi::c_char, out_len: u32) -> NrtStatus;
47
48static LIB: OnceCell<Option<Loaded>> = OnceCell::new();
49
50pub struct Loaded {
51 _lib: Library,
52 total_cores: u32,
53 version: String,
54 pub nrt_load: Option<NrtLoadFn>,
55 pub nrt_unload: Option<NrtUnloadFn>,
56 pub nrt_execute: Option<NrtExecuteFn>,
57 pub nrt_alloc_tensor_set: Option<NrtAllocTensorSetFn>,
58 pub nrt_free_tensor_set: Option<NrtFreeTensorSetFn>,
59 pub nrt_add_tensor_to_set: Option<NrtAddTensorToSetFn>,
60}
61
62unsafe impl Send for Loaded {}
63unsafe impl Sync for Loaded {}
64
65#[cfg(any(target_os = "linux", target_os = "android"))]
66const LIB_CANDIDATES: &[&str] = &[
67 "libnrt.so.1",
68 "libnrt.so",
69 "/opt/aws/neuron/lib/libnrt.so.1",
70];
71#[cfg(not(any(target_os = "linux", target_os = "android")))]
72const LIB_CANDIDATES: &[&str] = &[];
73
74pub(crate) fn loaded() -> Option<&'static Loaded> {
75 LIB.get_or_init(load).as_ref()
76}
77
78fn load() -> Option<Loaded> {
79 for name in LIB_CANDIDATES {
80 let lib = match unsafe { Library::new(*name) } {
81 Ok(l) => l,
82 Err(_) => continue,
83 };
84 unsafe {
85 let init: Symbol<NrtInitFn> = match lib.get(b"nrt_init\0") {
86 Ok(s) => s,
87 Err(_) => continue,
88 };
89 let tag = b"ironaccelerator\0" as *const _ as *const core::ffi::c_char;
92 if init(0, tag) != NRT_SUCCESS {
93 continue;
94 }
95 let count_fn: Symbol<NrtGetTotalNcCountFn> = match lib.get(b"nrt_get_total_nc_count\0")
96 {
97 Ok(s) => s,
98 Err(_) => continue,
99 };
100 let mut count: u32 = 0;
101 if count_fn(&mut count) != NRT_SUCCESS {
102 continue;
103 }
104 let version = lib
105 .get::<NrtGetVersionFn>(b"nrt_get_version\0")
106 .ok()
107 .and_then(|f| read_version(*f))
108 .unwrap_or_default();
109 drop(init);
110 drop(count_fn);
111
112 let nrt_load = lib.get::<NrtLoadFn>(b"nrt_load\0").ok().map(|s| *s);
116 let nrt_unload = lib.get::<NrtUnloadFn>(b"nrt_unload\0").ok().map(|s| *s);
117 let nrt_execute = lib.get::<NrtExecuteFn>(b"nrt_execute\0").ok().map(|s| *s);
118 let nrt_alloc_tensor_set = lib
119 .get::<NrtAllocTensorSetFn>(b"nrt_allocate_tensor_set\0")
120 .ok()
121 .map(|s| *s);
122 let nrt_free_tensor_set = lib
123 .get::<NrtFreeTensorSetFn>(b"nrt_free_tensor_set\0")
124 .ok()
125 .map(|s| *s);
126 let nrt_add_tensor_to_set = lib
127 .get::<NrtAddTensorToSetFn>(b"nrt_add_tensor_to_tensor_set\0")
128 .ok()
129 .map(|s| *s);
130
131 return Some(Loaded {
132 _lib: lib,
133 total_cores: count,
134 version,
135 nrt_load,
136 nrt_unload,
137 nrt_execute,
138 nrt_alloc_tensor_set,
139 nrt_free_tensor_set,
140 nrt_add_tensor_to_set,
141 });
142 }
143 }
144 None
145}
146
147unsafe fn read_version(f: NrtGetVersionFn) -> Option<String> {
148 let mut buf = vec![0i8; 128];
149 let status = f(buf.as_mut_ptr() as *mut _, buf.len() as u32);
150 if status != NRT_SUCCESS {
151 return None;
152 }
153 let bytes: Vec<u8> = buf
154 .iter()
155 .take_while(|&&c| c != 0)
156 .map(|&c| c as u8)
157 .collect();
158 String::from_utf8(bytes).ok()
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum NeuronGen {
163 Inf1,
165 Trn1,
167 Trn2,
169 Unknown,
170}
171
172pub fn is_available() -> bool {
173 loaded().is_some()
174}
175
176pub fn total_cores() -> u32 {
177 loaded().map(|l| l.total_cores).unwrap_or(0)
178}
179
180pub fn version() -> Option<&'static str> {
181 loaded().map(|l| l.version.as_str())
182}
183
184pub fn detect_generation() -> NeuronGen {
188 if let Ok(t) = std::env::var("NEURON_INSTANCE_TYPE") {
189 let t = t.to_ascii_lowercase();
190 if t.starts_with("trn2") {
191 return NeuronGen::Trn2;
192 }
193 if t.starts_with("trn1") || t.starts_with("inf2") {
194 return NeuronGen::Trn1;
195 }
196 if t.starts_with("inf1") {
197 return NeuronGen::Inf1;
198 }
199 }
200 match version()
201 .and_then(|v| v.split('.').next())
202 .and_then(|m| m.parse::<u32>().ok())
203 {
204 Some(n) if n >= 3 => NeuronGen::Trn2,
205 Some(2) => NeuronGen::Trn1,
206 Some(1) => NeuronGen::Inf1,
207 _ => NeuronGen::Unknown,
208 }
209}