use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use cloudini::{
CompressionOption, EncodingInfo, EncodingOptions, FieldType, PointField, PointcloudDecoder,
PointcloudEncoder,
};
fn make_xyzi_info(n_points: u32, comp: CompressionOption) -> EncodingInfo {
EncodingInfo {
fields: vec![
PointField {
name: "x".into(),
offset: 0,
field_type: FieldType::Float32,
resolution: Some(0.001),
},
PointField {
name: "y".into(),
offset: 4,
field_type: FieldType::Float32,
resolution: Some(0.001),
},
PointField {
name: "z".into(),
offset: 8,
field_type: FieldType::Float32,
resolution: Some(0.001),
},
PointField {
name: "intensity".into(),
offset: 12,
field_type: FieldType::Uint8,
resolution: None,
},
],
width: n_points,
height: 1,
point_step: 13,
encoding_opt: EncodingOptions::Lossy,
compression_opt: comp,
..EncodingInfo::default()
}
}
fn gen_cloud(n: usize) -> Vec<u8> {
let mut data = vec![0u8; n * 13];
for i in 0..n {
let t = i as f32 * 0.005;
let x = t.sin() * 20.0 + (t * 0.3).cos() * 5.0;
let y = t.cos() * 15.0 + (t * 0.7).sin() * 3.0;
let z = (t * 0.2).sin() * 8.0 + 1.0;
let intensity = (i % 256) as u8;
let base = i * 13;
data[base..base + 4].copy_from_slice(&x.to_le_bytes());
data[base + 4..base + 8].copy_from_slice(&y.to_le_bytes());
data[base + 8..base + 12].copy_from_slice(&z.to_le_bytes());
data[base + 12] = intensity;
}
data
}
fn bench_encode_lz4(c: &mut Criterion) {
let mut group = c.benchmark_group("encode/lz4-lossy");
for &n in &[1_000usize, 10_000, 100_000] {
let cloud = gen_cloud(n);
let info = make_xyzi_info(n as u32, CompressionOption::Lz4);
group.throughput(Throughput::Bytes(cloud.len() as u64));
group.bench_with_input(BenchmarkId::new("rust", n), &cloud, |b, cloud| {
let enc = PointcloudEncoder::new(info.clone());
b.iter(|| enc.encode(cloud).unwrap())
});
#[cfg(feature = "parallel")]
group.bench_with_input(BenchmarkId::new("rust-mt", n), &cloud, |b, cloud| {
let enc = PointcloudEncoder::new(info.clone()).with_threads(true);
b.iter(|| enc.encode(cloud).unwrap())
});
#[cfg(feature = "use_cpp")]
group.bench_with_input(BenchmarkId::new("cpp-st", n), &cloud, |b, cloud| {
let enc = cloudini::CppPointcloudEncoder::new(info.clone()).with_threads(false);
b.iter(|| enc.encode(cloud).unwrap())
});
#[cfg(feature = "use_cpp")]
group.bench_with_input(BenchmarkId::new("cpp-mt", n), &cloud, |b, cloud| {
let enc = cloudini::CppPointcloudEncoder::new(info.clone()).with_threads(true);
b.iter(|| enc.encode(cloud).unwrap())
});
}
group.finish();
}
fn bench_encode_zstd(c: &mut Criterion) {
let mut group = c.benchmark_group("encode/zstd-lossy");
for &n in &[1_000usize, 10_000, 100_000] {
let cloud = gen_cloud(n);
let info = make_xyzi_info(n as u32, CompressionOption::Zstd);
group.throughput(Throughput::Bytes(cloud.len() as u64));
group.bench_with_input(BenchmarkId::new("rust", n), &cloud, |b, cloud| {
let enc = PointcloudEncoder::new(info.clone());
b.iter(|| enc.encode(cloud).unwrap())
});
#[cfg(feature = "parallel")]
group.bench_with_input(BenchmarkId::new("rust-mt", n), &cloud, |b, cloud| {
let enc = PointcloudEncoder::new(info.clone()).with_threads(true);
b.iter(|| enc.encode(cloud).unwrap())
});
#[cfg(feature = "use_cpp")]
group.bench_with_input(BenchmarkId::new("cpp-st", n), &cloud, |b, cloud| {
let enc = cloudini::CppPointcloudEncoder::new(info.clone()).with_threads(false);
b.iter(|| enc.encode(cloud).unwrap())
});
#[cfg(feature = "use_cpp")]
group.bench_with_input(BenchmarkId::new("cpp-mt", n), &cloud, |b, cloud| {
let enc = cloudini::CppPointcloudEncoder::new(info.clone()).with_threads(true);
b.iter(|| enc.encode(cloud).unwrap())
});
}
group.finish();
}
fn bench_decode_lz4(c: &mut Criterion) {
let mut group = c.benchmark_group("decode/lz4-lossy");
for &n in &[1_000usize, 10_000, 100_000] {
let cloud = gen_cloud(n);
let info = make_xyzi_info(n as u32, CompressionOption::Lz4);
let compressed = PointcloudEncoder::new(info.clone()).encode(&cloud).unwrap();
group.throughput(Throughput::Bytes(cloud.len() as u64));
group.bench_with_input(BenchmarkId::new("rust", n), &compressed, |b, compressed| {
let dec = PointcloudDecoder::new();
b.iter(|| dec.decode(compressed).unwrap())
});
#[cfg(feature = "parallel")]
group.bench_with_input(
BenchmarkId::new("rust-mt", n),
&compressed,
|b, compressed| {
let dec = PointcloudDecoder::new().with_threads(true);
b.iter(|| dec.decode(compressed).unwrap())
},
);
#[cfg(feature = "use_cpp")]
group.bench_with_input(BenchmarkId::new("cpp", n), &compressed, |b, compressed| {
let dec = cloudini::CppPointcloudDecoder::new();
b.iter(|| dec.decode(compressed).unwrap())
});
}
group.finish();
}
fn bench_decode_zstd(c: &mut Criterion) {
let mut group = c.benchmark_group("decode/zstd-lossy");
for &n in &[1_000usize, 10_000, 100_000] {
let cloud = gen_cloud(n);
let info = make_xyzi_info(n as u32, CompressionOption::Zstd);
let compressed = PointcloudEncoder::new(info.clone()).encode(&cloud).unwrap();
group.throughput(Throughput::Bytes(cloud.len() as u64));
group.bench_with_input(BenchmarkId::new("rust", n), &compressed, |b, compressed| {
let dec = PointcloudDecoder::new();
b.iter(|| dec.decode(compressed).unwrap())
});
#[cfg(feature = "parallel")]
group.bench_with_input(
BenchmarkId::new("rust-mt", n),
&compressed,
|b, compressed| {
let dec = PointcloudDecoder::new().with_threads(true);
b.iter(|| dec.decode(compressed).unwrap())
},
);
#[cfg(feature = "use_cpp")]
group.bench_with_input(BenchmarkId::new("cpp", n), &compressed, |b, compressed| {
let dec = cloudini::CppPointcloudDecoder::new();
b.iter(|| dec.decode(compressed).unwrap())
});
}
group.finish();
}
criterion_group!(
benches,
bench_encode_lz4,
bench_encode_zstd,
bench_decode_lz4,
bench_decode_zstd,
);
criterion_main!(benches);