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