()
| 147 | |
| 148 | impl RocmBackend { |
| 149 | pub fn new() -> std::result::Result<Self, String> { |
| 150 | let ffi = Box::new(RocmFfi::load()?); |
| 151 | |
| 152 | let err = unsafe { (ffi.hip_init)(0) }; |
| 153 | if err != 0 { return Err(format!("hipInit: error {err}")); } |
| 154 | |
| 155 | // Two-layer defense against HIP's broken atexit cleanup: |
| 156 | // 1. SIGABRT handler catches abort() from HIP's assertion failures |
| 157 | // 2. atexit handler terminates before HIP's cleanup runs (LIFO order) |
| 158 | if !HIP_INITIALIZED.swap(true, Ordering::Relaxed) { |
| 159 | unsafe { |
| 160 | let mut sa: libc::sigaction = std::mem::zeroed(); |
| 161 | sa.sa_sigaction = hip_sigabrt_handler as *const () as libc::sighandler_t; |
| 162 | libc::sigemptyset(&mut sa.sa_mask); |
| 163 | sa.sa_flags = libc::SA_NODEFER; |
| 164 | libc::sigaction(libc::SIGABRT, &sa, std::ptr::null_mut()); |
| 165 | libc::atexit(hip_atexit_handler); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | let mut count = 0i32; |
| 170 | unsafe { (ffi.hip_get_device_count)(&mut count) }; |
| 171 | if count == 0 { return Err("no HIP devices".into()); } |
| 172 | |
| 173 | unsafe { (ffi.hip_set_device)(0) }; |
| 174 | |
| 175 | let mut name = [0u8; 256]; |
| 176 | unsafe { (ffi.hip_device_get_name)(name.as_mut_ptr() as *mut i8, 256, 0) }; |
| 177 | let name = std::ffi::CStr::from_bytes_until_nul(&name) |
| 178 | .unwrap_or_default().to_string_lossy(); |
| 179 | |
| 180 | let mut free = 0usize; |
| 181 | let mut total = 0usize; |
| 182 | unsafe { (ffi.hip_mem_get_info)(&mut free, &mut total) }; |
| 183 | |
| 184 | log::info!("ROCm backend: {} ({:.1} GiB free / {:.1} GiB total)", |
| 185 | name, free as f64 / 1e9, total as f64 / 1e9); |
| 186 | |
| 187 | let mut handle = std::ptr::null_mut(); |
| 188 | let err = unsafe { (ffi.rocblas_create_handle)(&mut handle) }; |
| 189 | if err != 0 { return Err(format!("rocblas_create_handle: error {err}")); } |
| 190 | |
| 191 | let mut stream = std::ptr::null_mut(); |
| 192 | let err = unsafe { (ffi.hip_stream_create)(&mut stream) }; |
| 193 | if err != 0 { return Err(format!("hipStreamCreate: error {err}")); } |
| 194 | |
| 195 | // Bind stream to rocBLAS for async GEMM |
| 196 | let err = unsafe { (ffi.rocblas_set_stream)(handle, stream) }; |
| 197 | if err != 0 { return Err(format!("rocblas_set_stream: error {err}")); } |
| 198 | |
| 199 | Ok(Self { |
| 200 | device: Device::Cpu, |
| 201 | ffi, |
| 202 | blas_handle: handle, |
| 203 | stream, |
| 204 | cache: RwLock::new(HashMap::with_capacity(64)), |
| 205 | }) |
| 206 | } |
nothing calls this directly
no test coverage detected