perf: copy contiguous hyperslab and point reads run by run
A 256 x 256 hyperslab of a contiguous f32 dataset read at an eighth of h5py's speed: partial_read copied the bounding box out of the file, the extractor then walked it element by element (a recursive call and two bounds checks per element) into a second buffer, and read_f32_selection converted that into a third. Selections of contiguous data are now copied straight from the file, one memcpy per run of elements contiguous in the file (gather.rs: a block along the last dimension, touching blocks as one range, whole rows merged), with no zero-filled intermediate and no full copy for large selections. The typed selection readers copy into their Vec<T> directly when the dataset stores T natively (new data_read::read_selection_native and sealed NativeElement trait, which the read_as_* fast paths now share; read_as_u64 gains one) and convert as before otherwise. The general extractor used by the chunked paths runs on the same run walker, keeping its old handling of unvalidated selections. Checked against h5py (contiguous_read_interop.rs) for strided, blocked, adjacent-block and whole-row hyperslabs, points and empty selections of every 1-8-byte type in both byte orders, ranks 1-4. Also keeps the huge-page threshold constant out of no_std builds, where it was unused. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -569,9 +569,7 @@ impl<'f> Dataset<'f> {
|
||||
&self,
|
||||
selection: &clawhdf5_format::selection::Selection,
|
||||
) -> Result<Vec<f64>, Error> {
|
||||
let raw = self.read_selection(selection)?;
|
||||
let dt = self.datatype()?;
|
||||
Ok(data_read::read_as_f64(&raw, &dt)?)
|
||||
self.read_typed_selection(selection, data_read::read_as_f64, || self.read_f64())
|
||||
}
|
||||
|
||||
/// Read selected elements as `f32` values.
|
||||
@@ -579,9 +577,7 @@ impl<'f> Dataset<'f> {
|
||||
&self,
|
||||
selection: &clawhdf5_format::selection::Selection,
|
||||
) -> Result<Vec<f32>, Error> {
|
||||
let raw = self.read_selection(selection)?;
|
||||
let dt = self.datatype()?;
|
||||
Ok(data_read::read_as_f32(&raw, &dt)?)
|
||||
self.read_typed_selection(selection, data_read::read_as_f32, || self.read_f32())
|
||||
}
|
||||
|
||||
/// Read selected elements as `i32` values.
|
||||
@@ -589,9 +585,7 @@ impl<'f> Dataset<'f> {
|
||||
&self,
|
||||
selection: &clawhdf5_format::selection::Selection,
|
||||
) -> Result<Vec<i32>, Error> {
|
||||
let raw = self.read_selection(selection)?;
|
||||
let dt = self.datatype()?;
|
||||
Ok(data_read::read_as_i32(&raw, &dt)?)
|
||||
self.read_typed_selection(selection, data_read::read_as_i32, || self.read_i32())
|
||||
}
|
||||
|
||||
/// Read selected elements as `i64` values.
|
||||
@@ -599,9 +593,34 @@ impl<'f> Dataset<'f> {
|
||||
&self,
|
||||
selection: &clawhdf5_format::selection::Selection,
|
||||
) -> Result<Vec<i64>, Error> {
|
||||
let raw = self.read_selection(selection)?;
|
||||
self.read_typed_selection(selection, data_read::read_as_i64, || self.read_i64())
|
||||
}
|
||||
|
||||
/// The typed selection readers. `All` is a full read. A contiguous dataset
|
||||
/// that stores `T` natively is copied from the file straight into the
|
||||
/// `Vec<T>`, one copy per contiguous run of selected elements; anything
|
||||
/// else reads the selection's bytes and converts them with `convert`.
|
||||
fn read_typed_selection<T: data_read::NativeElement>(
|
||||
&self,
|
||||
selection: &clawhdf5_format::selection::Selection,
|
||||
convert: fn(&[u8], &Datatype) -> Result<Vec<T>, FormatError>,
|
||||
full: impl FnOnce() -> Result<Vec<T>, Error>,
|
||||
) -> Result<Vec<T>, Error> {
|
||||
if matches!(selection, clawhdf5_format::selection::Selection::All) {
|
||||
return full();
|
||||
}
|
||||
let dt = self.datatype()?;
|
||||
Ok(data_read::read_as_i64(&raw, &dt)?)
|
||||
if T::is_native(&dt)
|
||||
&& let Ok(Some(raw)) = self.read_raw_ref()
|
||||
{
|
||||
let dims = self.dataspace()?.dimensions;
|
||||
if let Some(values) = data_read::read_selection_native::<T>(raw, &dims, &dt, selection)?
|
||||
{
|
||||
return Ok(values);
|
||||
}
|
||||
}
|
||||
let raw = self.read_selection(selection)?;
|
||||
Ok(convert(&raw, &dt)?)
|
||||
}
|
||||
|
||||
/// Zero-copy read of contiguous raw data.
|
||||
|
||||
Reference in New Issue
Block a user