Files
clawhdf5/benchmarks/bench_h5py.py
T

102 lines
3.4 KiB
Python

#!/usr/bin/env python3
"""h5py benchmarks matching rustyhdf5 Criterion benches (1M f64)."""
import time, os, tempfile, numpy as np, h5py
N = 1_000_000
ITERS = 50
data = np.arange(N, dtype=np.float64)
def bench(name, fn, iters=ITERS):
# warmup
for _ in range(3):
fn()
times = []
for _ in range(iters):
t0 = time.perf_counter()
fn()
times.append(time.perf_counter() - t0)
times.sort()
median = times[len(times)//2]
print(f"{name}: {median*1000:.3f} ms (median of {iters})")
# --- Write benchmarks ---
def write_contiguous():
with tempfile.NamedTemporaryFile(suffix='.h5', delete=True) as f:
with h5py.File(f.name, 'w') as hf:
hf.create_dataset('data', data=data)
def write_chunked():
with tempfile.NamedTemporaryFile(suffix='.h5', delete=True) as f:
with h5py.File(f.name, 'w') as hf:
hf.create_dataset('data', data=data, chunks=(10000,))
def write_chunked_deflate():
with tempfile.NamedTemporaryFile(suffix='.h5', delete=True) as f:
with h5py.File(f.name, 'w') as hf:
hf.create_dataset('data', data=data, chunks=(10000,), compression='gzip', compression_opts=6)
# --- Read benchmarks (pre-create files) ---
tmp_contig = tempfile.NamedTemporaryFile(suffix='.h5', delete=False)
with h5py.File(tmp_contig.name, 'w') as hf:
hf.create_dataset('data', data=data)
tmp_chunked = tempfile.NamedTemporaryFile(suffix='.h5', delete=False)
with h5py.File(tmp_chunked.name, 'w') as hf:
hf.create_dataset('data', data=data, chunks=(10000,))
tmp_deflate = tempfile.NamedTemporaryFile(suffix='.h5', delete=False)
with h5py.File(tmp_deflate.name, 'w') as hf:
hf.create_dataset('data', data=data, chunks=(10000,), compression='gzip', compression_opts=6)
def read_contiguous():
with h5py.File(tmp_contig.name, 'r') as hf:
_ = hf['data'][:]
def read_chunked():
with h5py.File(tmp_chunked.name, 'r') as hf:
_ = hf['data'][:]
def read_chunked_deflate():
with h5py.File(tmp_deflate.name, 'r') as hf:
_ = hf['data'][:]
# --- Metadata: parse superblock + read attrs ---
tmp_attrs = tempfile.NamedTemporaryFile(suffix='.h5', delete=False)
with h5py.File(tmp_attrs.name, 'w') as hf:
for i in range(50):
hf.attrs[f'attr_{i}'] = f'value_{i}'
def read_50_attrs():
with h5py.File(tmp_attrs.name, 'r') as hf:
for i in range(50):
_ = hf.attrs[f'attr_{i}']
# --- Group navigation (100 groups) ---
tmp_groups = tempfile.NamedTemporaryFile(suffix='.h5', delete=False)
with h5py.File(tmp_groups.name, 'w') as hf:
g = hf
for i in range(100):
g = g.create_group(f'g{i}')
g.create_dataset('leaf', data=[1.0])
def group_nav_100():
with h5py.File(tmp_groups.name, 'r') as hf:
path = '/'.join(f'g{i}' for i in range(100)) + '/leaf'
_ = hf[path][:]
print(f"=== h5py {h5py.version.version} / HDF5 {h5py.version.hdf5_version} / numpy {np.__version__} ===")
print(f"=== {N:,} float64 elements ({N*8/1e6:.1f} MB) ===\n")
bench("write_contiguous", write_contiguous)
bench("write_chunked", write_chunked)
bench("write_chunked_deflate", write_chunked_deflate, iters=20)
bench("read_contiguous", read_contiguous)
bench("read_chunked", read_chunked)
bench("read_chunked_deflate", read_chunked_deflate)
bench("read_50_attrs", read_50_attrs)
bench("group_nav_100", group_nav_100)
# cleanup
for f in [tmp_contig, tmp_chunked, tmp_deflate, tmp_attrs, tmp_groups]:
os.unlink(f.name)