109 lines
3.9 KiB
Rust
109 lines
3.9 KiB
Rust
|
|
//! Phase 0 — Task 0.2: thumbnail render latency + output-size baseline.
|
|||
|
|
//!
|
|||
|
|
//! Measures the CPU-bound render path (decode → EXIF orientation → resize →
|
|||
|
|
//! JPEG encode) per size and for the all-sizes upload path, across the size/
|
|||
|
|
//! format corpus. `Throughput::Elements(1)` makes criterion report images/sec
|
|||
|
|
//! alongside ms/image. Output byte sizes (bandwidth/disk proxy) are printed once
|
|||
|
|
//! as a table before the timed runs.
|
|||
|
|
//!
|
|||
|
|
//! Run: `cargo bench --features bench`
|
|||
|
|
//! HTML report: `target/criterion/report/index.html`
|
|||
|
|
|
|||
|
|
use std::time::Duration;
|
|||
|
|
|
|||
|
|
use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main};
|
|||
|
|
use oxicloud::bench_support::{self, CorpusCase};
|
|||
|
|
use oxicloud::infrastructure::services::thumbnail_service::{ThumbnailService, ThumbnailSize};
|
|||
|
|
|
|||
|
|
const SIZES: [ThumbnailSize; 3] = [
|
|||
|
|
ThumbnailSize::Icon,
|
|||
|
|
ThumbnailSize::Preview,
|
|||
|
|
ThumbnailSize::Large,
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
/// Print the output-size table (per-size encoded JPEG bytes) once. This is the
|
|||
|
|
/// bandwidth/disk half of the Task 0.2 deliverable.
|
|||
|
|
fn print_output_sizes(corpus: &[CorpusCase]) {
|
|||
|
|
println!("\n=== Output size baseline (encoded JPEG bytes per thumbnail) ===");
|
|||
|
|
println!(
|
|||
|
|
"| {:<17} | {:<5} | {:>11} | {:>8} | {:>7} | {:>8} | {:>8} |",
|
|||
|
|
"case", "fmt", "source", "input KB", "icon B", "preview B", "large B"
|
|||
|
|
);
|
|||
|
|
println!(
|
|||
|
|
"|{:-<19}|{:-<7}|{:-<13}|{:-<10}|{:-<9}|{:-<10}|{:-<10}|",
|
|||
|
|
"", "", "", "", "", "", ""
|
|||
|
|
);
|
|||
|
|
for case in corpus {
|
|||
|
|
let sizes = ThumbnailService::bench_render_all(&case.bytes).unwrap_or_default();
|
|||
|
|
let get = |want: ThumbnailSize| {
|
|||
|
|
sizes
|
|||
|
|
.iter()
|
|||
|
|
.find(|(s, _)| *s == want)
|
|||
|
|
.map(|(_, n)| *n)
|
|||
|
|
.unwrap_or(0)
|
|||
|
|
};
|
|||
|
|
println!(
|
|||
|
|
"| {:<17} | {:<5} | {:>5}×{:<5} | {:>8} | {:>6} | {:>8} | {:>8} |",
|
|||
|
|
case.name,
|
|||
|
|
case.format,
|
|||
|
|
case.width,
|
|||
|
|
case.height,
|
|||
|
|
case.bytes.len() / 1024,
|
|||
|
|
get(ThumbnailSize::Icon),
|
|||
|
|
get(ThumbnailSize::Preview),
|
|||
|
|
get(ThumbnailSize::Large),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
println!();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn configure(group: &mut criterion::BenchmarkGroup<'_, criterion::measurement::WallTime>) {
|
|||
|
|
// Big images (48 MP) are slow per-iter; keep the suite bounded but stable.
|
|||
|
|
group
|
|||
|
|
.sample_size(10)
|
|||
|
|
.warm_up_time(Duration::from_secs(1))
|
|||
|
|
.measurement_time(Duration::from_secs(6));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fn bench_thumbnails(c: &mut Criterion) {
|
|||
|
|
let corpus = bench_support::load_or_generate();
|
|||
|
|
assert!(!corpus.is_empty(), "corpus is empty — generation failed");
|
|||
|
|
print_output_sizes(&corpus);
|
|||
|
|
|
|||
|
|
// Per-size single-thumbnail latency (the lazy request path).
|
|||
|
|
for size in SIZES {
|
|||
|
|
let mut group = c.benchmark_group(format!("render_thumbnail/{size:?}"));
|
|||
|
|
configure(&mut group);
|
|||
|
|
for case in &corpus {
|
|||
|
|
group.throughput(Throughput::Elements(1));
|
|||
|
|
group.bench_with_input(BenchmarkId::from_parameter(case.name), case, |b, case| {
|
|||
|
|
b.iter(|| {
|
|||
|
|
let out =
|
|||
|
|
ThumbnailService::bench_render_thumbnail(black_box(&case.bytes), size)
|
|||
|
|
.expect("render_thumbnail");
|
|||
|
|
black_box(out.len())
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
group.finish();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// All-sizes-in-one-decode latency (the eager upload path).
|
|||
|
|
let mut group = c.benchmark_group("render_all");
|
|||
|
|
configure(&mut group);
|
|||
|
|
for case in &corpus {
|
|||
|
|
group.throughput(Throughput::Elements(1));
|
|||
|
|
group.bench_with_input(BenchmarkId::from_parameter(case.name), case, |b, case| {
|
|||
|
|
b.iter(|| {
|
|||
|
|
let out =
|
|||
|
|
ThumbnailService::bench_render_all(black_box(&case.bytes)).expect("render_all");
|
|||
|
|
black_box(out.len())
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
group.finish();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
criterion_group!(benches, bench_thumbnails);
|
|||
|
|
criterion_main!(benches);
|