154 lines
4.6 KiB
Rust
154 lines
4.6 KiB
Rust
#![allow(
|
|
clippy::unwrap_used,
|
|
clippy::cast_precision_loss,
|
|
clippy::cast_possible_truncation
|
|
)]
|
|
|
|
//! Criterion benchmarks for metadata-based sort modes (m6p3).
|
|
//!
|
|
//! Validates the m6p3 performance acceptance criterion:
|
|
//! - Metadata-based sorts (alphabetical, duration) complete in < 50ms at 500 items.
|
|
//!
|
|
//! Sort modes exercised:
|
|
//! - `alphabetical_asc`: packs 8-byte title prefix into u64 for ordering
|
|
//! - `alphabetical_desc`: inverse of alphabetical_asc
|
|
//! - `shortest`: reads "duration" metadata, orders ascending
|
|
//! - `longest`: reads "duration" metadata, orders descending
|
|
//!
|
|
//! Dataset: 500 items, each with a unique title and duration. No signals.
|
|
//! The benchmark uses a shared `LazyLock<TidalDb>` to amortize setup.
|
|
|
|
use std::sync::LazyLock;
|
|
use std::time::Duration;
|
|
|
|
use criterion::{Criterion, black_box, criterion_group, criterion_main};
|
|
use tidaldb::TidalDb;
|
|
use tidaldb::query::retrieve::Retrieve;
|
|
use tidaldb::schema::{DecaySpec, EntityId, EntityKind, SchemaBuilder, Window};
|
|
|
|
const N_ITEMS: u64 = 500;
|
|
|
|
/// Minimal schema: no text fields needed; metadata-only sorts don't use Tantivy.
|
|
fn sort_schema() -> tidaldb::schema::Schema {
|
|
let mut builder = SchemaBuilder::new();
|
|
let _ = builder
|
|
.signal(
|
|
"view",
|
|
EntityKind::Item,
|
|
DecaySpec::Exponential {
|
|
half_life: Duration::from_secs(7 * 24 * 3600),
|
|
},
|
|
)
|
|
.windows(&[Window::SevenDays])
|
|
.velocity(false)
|
|
.add();
|
|
builder.build().unwrap()
|
|
}
|
|
|
|
/// Build the shared 500-item database. Called exactly once per benchmark run.
|
|
///
|
|
/// Items are written with:
|
|
/// - `"title"`: alphabetically varied titles ("Item 000" through "Item 499")
|
|
/// - `"duration"`: varied integer seconds (1..=500)
|
|
fn build_sort_db() -> TidalDb {
|
|
let db = TidalDb::builder()
|
|
.ephemeral()
|
|
.with_schema(sort_schema())
|
|
.open()
|
|
.unwrap();
|
|
|
|
for i in 0..N_ITEMS {
|
|
let item_id = EntityId::new(i + 1);
|
|
let mut meta = std::collections::HashMap::new();
|
|
// Vary the title so alphabetical sort has real ordering work to do.
|
|
meta.insert("title".to_string(), format!("Item {:03}", i));
|
|
// Duration cycles 1..=500 seconds.
|
|
meta.insert("duration".to_string(), (i + 1).to_string());
|
|
db.write_item_with_metadata(item_id, &meta).unwrap();
|
|
}
|
|
|
|
db
|
|
}
|
|
|
|
/// Shared 500-item DB: built once, reused by all sort benchmarks.
|
|
static SORT_DB: LazyLock<TidalDb> = LazyLock::new(build_sort_db);
|
|
|
|
// ── Benchmarks ────────────────────────────────────────────────────────────────
|
|
|
|
/// Alphabetical A-Z sort over 500 items (< 50ms AC).
|
|
fn bench_alphabetical_asc(c: &mut Criterion) {
|
|
let db: &TidalDb = &SORT_DB;
|
|
|
|
let query = Retrieve::builder()
|
|
.profile("alphabetical_asc")
|
|
.limit(N_ITEMS as usize)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut group = c.benchmark_group("sort_500");
|
|
group.bench_function("alphabetical_asc", |b| {
|
|
b.iter(|| db.retrieve(black_box(&query)).unwrap());
|
|
});
|
|
group.finish();
|
|
}
|
|
|
|
/// Alphabetical Z-A sort over 500 items (< 50ms AC).
|
|
fn bench_alphabetical_desc(c: &mut Criterion) {
|
|
let db: &TidalDb = &SORT_DB;
|
|
|
|
let query = Retrieve::builder()
|
|
.profile("alphabetical_desc")
|
|
.limit(N_ITEMS as usize)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut group = c.benchmark_group("sort_500");
|
|
group.bench_function("alphabetical_desc", |b| {
|
|
b.iter(|| db.retrieve(black_box(&query)).unwrap());
|
|
});
|
|
group.finish();
|
|
}
|
|
|
|
/// Shortest-first sort over 500 items (< 50ms AC).
|
|
fn bench_shortest(c: &mut Criterion) {
|
|
let db: &TidalDb = &SORT_DB;
|
|
|
|
let query = Retrieve::builder()
|
|
.profile("shortest")
|
|
.limit(N_ITEMS as usize)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut group = c.benchmark_group("sort_500");
|
|
group.bench_function("shortest", |b| {
|
|
b.iter(|| db.retrieve(black_box(&query)).unwrap());
|
|
});
|
|
group.finish();
|
|
}
|
|
|
|
/// Longest-first sort over 500 items (< 50ms AC).
|
|
fn bench_longest(c: &mut Criterion) {
|
|
let db: &TidalDb = &SORT_DB;
|
|
|
|
let query = Retrieve::builder()
|
|
.profile("longest")
|
|
.limit(N_ITEMS as usize)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut group = c.benchmark_group("sort_500");
|
|
group.bench_function("longest", |b| {
|
|
b.iter(|| db.retrieve(black_box(&query)).unwrap());
|
|
});
|
|
group.finish();
|
|
}
|
|
|
|
criterion_group!(
|
|
benches,
|
|
bench_alphabetical_asc,
|
|
bench_alphabetical_desc,
|
|
bench_shortest,
|
|
bench_longest,
|
|
);
|
|
criterion_main!(benches);
|