102 lines
3.4 KiB
Python
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)
|