aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/document/bench.rs4
-rw-r--r--src/document/mod.rs2
-rw-r--r--src/remake/bench.rs89
-rw-r--r--src/remake/mod.rs2
4 files changed, 94 insertions, 3 deletions
diff --git a/src/document/bench.rs b/src/document/bench.rs
index 78f87d8..02b530d 100644
--- a/src/document/bench.rs
+++ b/src/document/bench.rs
@@ -30,7 +30,7 @@ fn sorted(mut heads: Vec<ChangeHash>) -> Vec<ChangeHash> {
}
/// A document with `keys` keys under `data`, each written by a change of its own.
-fn document(keys: usize) -> Document {
+pub(crate) fn document(keys: usize) -> Document {
let mut doc = Document::new();
let mut map = None;
for key in 0..keys {
@@ -47,7 +47,7 @@ fn document(keys: usize) -> Document {
}
/// The median of `runs` timings of `f`.
-fn median(runs: usize, mut f: impl FnMut() -> Duration) -> Duration {
+pub(crate) fn median(runs: usize, mut f: impl FnMut() -> Duration) -> Duration {
let mut times: Vec<Duration> = (0..runs).map(|_| f()).collect();
times.sort_unstable();
times[runs / 2]
diff --git a/src/document/mod.rs b/src/document/mod.rs
index 4d7fbfe..21050ea 100644
--- a/src/document/mod.rs
+++ b/src/document/mod.rs
@@ -36,7 +36,7 @@ pub(crate) fn actor(doc: &Document) -> ActorId {
pub(crate) mod at;
#[cfg(test)]
-mod bench;
+pub(crate) mod bench;
pub(crate) mod changes;
pub(crate) mod file;
pub(crate) mod lock;
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);
+}
diff --git a/src/remake/mod.rs b/src/remake/mod.rs
index 25ca7ab..9351cc5 100644
--- a/src/remake/mod.rs
+++ b/src/remake/mod.rs
@@ -22,6 +22,8 @@
//! depends on `AppState`, peers or sync internals.
mod api;
+#[cfg(test)]
+mod bench;
mod catchup;
mod content;
mod coordinator;