Merge branch 'feat/p3-storage-trait' into feat/p3-range-zfp-edit
# Conflicts: # CHANGELOG.md # crates/clawhdf5-format/src/attribute.rs # crates/clawhdf5-format/src/btree_v1.rs # crates/clawhdf5-format/src/data_layout.rs # crates/clawhdf5-format/src/extensible_array.rs # crates/clawhdf5-format/src/fixed_array.rs # crates/clawhdf5-format/src/fractal_heap.rs # crates/clawhdf5-format/src/local_heap.rs # crates/clawhdf5-format/src/shared_message.rs
This commit is contained in:
@@ -31,6 +31,10 @@ harness = false
|
||||
name = "parallel_bench"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "local_metadata_bench"
|
||||
harness = false
|
||||
|
||||
[features]
|
||||
default = ["mmap", "provenance", "lzf"]
|
||||
mmap = ["clawhdf5-io/mmap"]
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
//! Metadata parsing over an in-memory file: the local fast path that the
|
||||
//! range-read `Storage` migration must not slow down
|
||||
//! (`docs/design/range-reads.md`, "Keeping the local fast path").
|
||||
//!
|
||||
//! Only the `&[u8]` APIs are used, so the same file builds against older
|
||||
//! revisions for an A/B comparison. The input is a version-1 (symbol table)
|
||||
//! file with 400 groups, written by h5py with `libver='earliest'` and a
|
||||
//! 512-byte user block (`clawhdf5-format/tests/fixtures/v1_groups_400.h5`).
|
||||
|
||||
use clawhdf5::{File, Group};
|
||||
use clawhdf5_format::btree_v1::collect_symbol_table_nodes;
|
||||
use clawhdf5_format::message_type::MessageType;
|
||||
use clawhdf5_format::object_header::ObjectHeader;
|
||||
use clawhdf5_format::superblock::Superblock;
|
||||
use clawhdf5_format::symbol_table::{SymbolTableMessage, SymbolTableNode};
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use std::hint::black_box;
|
||||
|
||||
const FIXTURE: &str = concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/../clawhdf5-format/tests/fixtures/v1_groups_400.h5"
|
||||
);
|
||||
|
||||
fn walk(g: &Group<'_>, objs: &mut usize) {
|
||||
for name in g.datasets().unwrap_or_default() {
|
||||
*objs += 1;
|
||||
if let Ok(ds) = g.dataset(&name) {
|
||||
let _ = black_box(ds.shape());
|
||||
let _ = black_box(ds.dtype());
|
||||
let _ = black_box(ds.attrs());
|
||||
}
|
||||
}
|
||||
for name in g.groups().unwrap_or_default() {
|
||||
*objs += 1;
|
||||
if let Ok(sub) = g.group(&name) {
|
||||
walk(&sub, objs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bench_local_metadata(c: &mut Criterion) {
|
||||
let bytes = std::fs::read(FIXTURE).unwrap();
|
||||
let (_, f) = clawhdf5_format::signature::split_user_block(&bytes).unwrap();
|
||||
let sb = Superblock::parse(f, 0).unwrap();
|
||||
let (os, ls) = (sb.offset_size, sb.length_size);
|
||||
let root = ObjectHeader::parse(f, sb.root_group_address as usize, os, ls).unwrap();
|
||||
let stm = root
|
||||
.messages
|
||||
.iter()
|
||||
.find(|m| m.msg_type == MessageType::SymbolTable)
|
||||
.map(|m| SymbolTableMessage::parse(&m.data, os).unwrap())
|
||||
.unwrap();
|
||||
let nodes = collect_symbol_table_nodes(f, stm.btree_address, os, ls).unwrap();
|
||||
let headers: Vec<u64> = nodes
|
||||
.iter()
|
||||
.flat_map(|&a| SymbolTableNode::parse(f, a as usize, os).unwrap().entries)
|
||||
.map(|e| e.object_header_address)
|
||||
.collect();
|
||||
assert_eq!(headers.len(), 401);
|
||||
|
||||
let mut g = c.benchmark_group("local_metadata");
|
||||
g.bench_function("object_header_parse_x401", |b| {
|
||||
b.iter(|| {
|
||||
for &a in &headers {
|
||||
black_box(ObjectHeader::parse(f, a as usize, os, ls).unwrap());
|
||||
}
|
||||
})
|
||||
});
|
||||
g.bench_function("snod_parse_all", |b| {
|
||||
b.iter(|| {
|
||||
for &a in &nodes {
|
||||
black_box(SymbolTableNode::parse(f, a as usize, os).unwrap());
|
||||
}
|
||||
})
|
||||
});
|
||||
g.bench_function("btree_v1_walk", |b| {
|
||||
b.iter(|| black_box(collect_symbol_table_nodes(f, stm.btree_address, os, ls).unwrap()))
|
||||
});
|
||||
let file = File::open(FIXTURE).unwrap();
|
||||
g.bench_function("facade_list_400_groups", |b| {
|
||||
b.iter(|| {
|
||||
let mut n = 0;
|
||||
walk(&file.root(), &mut n);
|
||||
assert_eq!(n, 401);
|
||||
})
|
||||
});
|
||||
g.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_local_metadata);
|
||||
criterion_main!(benches);
|
||||
@@ -6,7 +6,12 @@ use clawhdf5_format::error::FormatError;
|
||||
use clawhdf5_format::message_type::MessageType;
|
||||
|
||||
/// Errors that can occur when using the high-level API.
|
||||
///
|
||||
/// Non-exhaustive: new failure modes add variants, so a `match` needs a
|
||||
/// wildcard arm. Failures of a [`Storage`](clawhdf5_format::storage::Storage)
|
||||
/// backend arrive as `Error::Format(FormatError::Storage(..))`.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// I/O error from the filesystem.
|
||||
Io(std::io::Error),
|
||||
|
||||
Reference in New Issue
Block a user