From 11dabc03d8624557c146e0796dc4bc9c9c1050ee Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 2 Nov 2026 10:53:47 +0100 Subject: add remake benchmarks --- src/remake/bench.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/remake/bench.rs (limited to 'src/remake/bench.rs') diff --git a/src/remake/bench.rs b/src/remake/bench.rs new file mode 100644 index 0000000..213ed4b --- /dev/null +++ b/src/remake/bench.rs @@ -0,0 +1,89 @@ +//! Benchmarks, as ignored tests (`cargo benchmarks`, `docs/development.md`). +//! +//! `replay`: carrying writes over into a new epoch's document, last writer wins +//! (`delta::replay_newest`): what a rejoin does with the writes made during it, and a +//! switch with those made after the remake's base. It finds the paths of every write +//! carried, and of every newer change in the new document, by a diff each. + +use std::time::Instant; + +use automerge::transaction::Transactable; +use automerge::{ObjType, ROOT, ReadDoc, ScalarValue}; + +use super::delta::{Superseded, replay_newest}; +use super::kind::Translator; +use crate::document::Document; +use crate::document::bench::{document, median}; +use crate::document::store; + +/// `count` changes to `doc`, each writing one key under `data` (from `first` on), made +/// at `at` and after. +fn writes(doc: &mut Document, first: usize, count: usize, at: i64) { + for i in 0..count { + let mut transaction = doc.transaction(); + let data = transaction + .get(ROOT, "data") + .expect("read") + .map(|(_, id)| id) + .unwrap_or_else(|| { + transaction + .put_object(ROOT, "data", ObjType::Map) + .expect("map") + }); + transaction + .put( + &data, + format!("late{}", first + i), + ScalarValue::Int(i as i64), + ) + .expect("write"); + transaction + .commit_with(automerge::transaction::CommitOptions::default().with_time(at + i as i64)); + } +} + +/// `late` writes made to the old document after `keys` keys, carried into a new one +/// holding those keys (as a snapshot, at time 0) and `newer` writes of its own made +/// after them. +fn replay(keys: usize, late: usize, newer: usize) { + let old_base = document(keys); + let base = old_base.get_heads(); + let mut old = old_base.clone(); + writes(&mut old, 0, late, 1_000); + let after = old.get_heads(); + + let mut new = Document::new(); + { + let mut transaction = new.transaction(); + store::materialize_into(&old_base, &mut transaction, &|_| false).expect("snapshot"); + transaction.commit_with(automerge::transaction::CommitOptions::default().with_time(0)); + } + writes(&mut new, late, newer, 2_000); + + let took = median(5, || { + let mut target = new.clone(); + let started = Instant::now(); + std::hint::black_box(replay_newest( + &old, + &base, + &after, + &mut target, + &Translator::default(), + Superseded::Drop, + )); + started.elapsed() + }); + println!( + "{:<60} {:>10.3} ms", + format!("replay of {late} writes, {keys} keys, {newer} newer changes"), + took.as_secs_f64() * 1e3 + ); +} + +#[test] +#[ignore = "a benchmark: cargo benchmarks"] +fn bench_replay() { + replay(1_000, 100, 100); + replay(100_000, 100, 100); + replay(100_000, 1_000, 1_000); +} -- cgit v1.3.1