use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, OnceLock};
use memmap2::Mmap;
use onnx_runtime_ir::WeightRef;
use super::host::{HostOrtValue, HostOrtValueStorage, HostTensorTypeAndShapeInfo, dtype_to_ort};
static MAPPED_WEIGHTS: OnceLock<Mutex<HashMap<PathBuf, MappedWeightFile>>> = OnceLock::new();
struct MappedWeightFile {
map: Arc<Mmap>,
identity: (Option<std::time::SystemTime>, u64),
}
fn weight_file_identity(path: &Path) -> (Option<std::time::SystemTime>, u64) {
match std::fs::metadata(path) {
Ok(meta) => (meta.modified().ok(), meta.len()),
Err(_) => (None, 0),
}
}
fn mapped_weight_file(path: &Path) -> Option<Arc<Mmap>> {
let identity = weight_file_identity(path);
let cache = MAPPED_WEIGHTS.get_or_init(|| Mutex::new(HashMap::new()));
let mut cache = cache
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
if let Some(entry) = cache.get(path)
&& entry.identity == identity
{
return Some(Arc::clone(&entry.map));
}
let file = std::fs::File::open(path).ok()?;
let map = Arc::new(unsafe { Mmap::map(&file) }.ok()?);
cache.insert(
path.to_path_buf(),
MappedWeightFile {
map: Arc::clone(&map),
identity,
},
);
Some(map)
}
pub(super) fn host_ort_value_for_weight(weight: &WeightRef) -> Option<Box<HostOrtValue>> {
let (dtype, dims, data) = match weight {
WeightRef::Inline(tensor) => (tensor.dtype, tensor.dims.clone(), tensor.data.clone()),
WeightRef::External {
path,
offset,
length,
dtype,
dims,
} => {
let map = mapped_weight_file(path)?;
let end = offset.checked_add(*length)?;
map.get(*offset..end)?;
return Some(Box::new(HostOrtValue {
tensor: HostTensorTypeAndShapeInfo {
dtype: dtype_to_ort(*dtype),
dims: dims.iter().map(|d| *d as i64).collect(),
},
storage: HostOrtValueStorage::Mapped {
map,
offset: *offset,
len: *length,
},
}));
}
};
Some(Box::new(HostOrtValue {
tensor: HostTensorTypeAndShapeInfo {
dtype: dtype_to_ort(dtype),
dims: dims.into_iter().map(|d| d as i64).collect(),
},
storage: HostOrtValueStorage::Owned(data),
}))
}