All three SDD plans fully wired and committed to main: Filter Codecs (FC): - FC-1: Implement float E-scale in scaleoffset_decompress (value = minval + code * 2^E, negative exponents via cast to i32); add two round-trip tests. - FC-2: filters_szip.rs — feature-gated SZIP decode via libaec FFI; SZIP dispatch arm added to decompress_chunk. - FC-3: libaec-sys workspace crate with pkg-config probe and aec_buffer_decode FFI binding; added to workspace members. Format Write Extensions (FWE): - FWE-1: GroupBuilder::add_external_link() API; wired through FinishedGroup → GrpFlat → file_writer pass 1/2/3 (OH size, layout cursor, final write); external_link_write_roundtrip test. - FWE-2: data_layout_write.rs — serialize_vds_mappings with length_size param and version 0/1 (external vs same-file) selection; declared as pub mod. - FWE-3: with_virtual_sources empty-mapping guard (Important #9) — empty vec is silently ignored; vds_empty_mapping_list test updated to assert non-VDS layout results. MPI-IO VOL Backend (MPI): - MPI-1/2/3: mpi_vol.rs — MpiVol implementing VirtualObjectLayer; root-read + broadcast collective read; gather + root-write collective write; feature- gated mpi-io feature; wired into clawhdf5-io lib.rs. - MPI-4: mpi_io_bench binary (h5bench-equivalent MPI-IO throughput bench). mpi_vol.rs reviewer fixes: - Doc-comment updated to accurately describe root-read+broadcast pattern (not MPI_File_read_at); MpiVol::expected_capabilities() associated fn added so tests can verify capabilities without a live MPI universe; rank_and_size_stub_values renamed to no_feature_error_contains_feature_name. Workspace check: zero warnings, 20 test suites pass. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
68 lines
2.2 KiB
Rust
68 lines
2.2 KiB
Rust
//! h5bench-equivalent MPI-IO performance benchmark.
|
|
//!
|
|
//! Usage: mpirun -np N cargo run -p clawhdf5-bench --features mpi-io --bin mpi_io_bench -- --size <N>
|
|
//!
|
|
//! Measures collective write and read throughput in MB/s for f64 arrays.
|
|
|
|
#[cfg(feature = "mpi-io")]
|
|
fn main() {
|
|
use clawhdf5_io::mpi_vol::MpiVol;
|
|
use clawhdf5_io::vol::VirtualObjectLayer;
|
|
use mpi::traits::*;
|
|
use std::time::Instant;
|
|
|
|
let args: Vec<String> = std::env::args().collect();
|
|
let n_elements: usize = args
|
|
.iter()
|
|
.position(|a| a == "--size")
|
|
.and_then(|i| args.get(i + 1))
|
|
.and_then(|s| s.parse().ok())
|
|
.unwrap_or(100_000);
|
|
|
|
let mut vol = MpiVol::new_world().expect("MPI init failed");
|
|
let world = vol.universe.world();
|
|
let rank = world.rank() as usize;
|
|
let size = world.size() as usize;
|
|
|
|
let path = format!("/tmp/clawhdf5_mpiio_bench_{n_elements}.h5");
|
|
vol.open(&path).unwrap();
|
|
|
|
// Each rank contributes n_elements/size f64 values
|
|
let per_rank = n_elements / size;
|
|
let shard: Vec<f64> = (0..per_rank)
|
|
.map(|i| (rank * per_rank + i) as f64)
|
|
.collect();
|
|
let shard_bytes: Vec<u8> = shard.iter().flat_map(|v| v.to_le_bytes()).collect();
|
|
|
|
// Collective write
|
|
world.barrier();
|
|
let t0 = Instant::now();
|
|
vol.write_dataset("data", &shard_bytes, &[n_elements as u64], "f64")
|
|
.unwrap();
|
|
world.barrier();
|
|
let write_elapsed = t0.elapsed().as_secs_f64();
|
|
|
|
// Collective read
|
|
let t1 = Instant::now();
|
|
let _data = vol.read_dataset("data").unwrap();
|
|
world.barrier();
|
|
let read_elapsed = t1.elapsed().as_secs_f64();
|
|
|
|
if rank == 0 {
|
|
let total_mb = (n_elements * 8) as f64 / 1e6;
|
|
println!("=== clawhdf5 MPI-IO Benchmark ===");
|
|
println!("Elements : {n_elements}");
|
|
println!("Ranks : {size}");
|
|
println!("Total : {total_mb:.1} MB");
|
|
println!("Write : {:.1} MB/s", total_mb / write_elapsed);
|
|
println!("Read : {:.1} MB/s", total_mb / read_elapsed);
|
|
}
|
|
}
|
|
|
|
#[cfg(not(feature = "mpi-io"))]
|
|
fn main() {
|
|
eprintln!("mpi_io_bench requires the `mpi-io` feature.");
|
|
eprintln!("Run: mpirun -np N cargo run -p clawhdf5-bench --features mpi-io --bin mpi_io_bench");
|
|
std::process::exit(1);
|
|
}
|