diff options
Diffstat (limited to 'src/document/bench.rs')
| -rw-r--r-- | src/document/bench.rs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/document/bench.rs b/src/document/bench.rs index bc1f6fa..467dc2f 100644 --- a/src/document/bench.rs +++ b/src/document/bench.rs @@ -29,6 +29,13 @@ //! rebuilds them, and from the bytes they came as; and inspected before they are //! applied (`inspect::Inspector`), their objects made among them or looked up in the //! document, each once. +//! +//! `screening`: what judging every change received costs while catching up +//! (`access::screen`), against applying them unjudged, as a node whose document has no +//! policy does now: many changes into an empty document, as one delta brings them; +//! judged with no policy in them (each passes, read at its dependencies, after its +//! paths were found), and with the policy their first change wrote (each judged by the +//! rules). use std::time::{Duration, Instant}; @@ -607,3 +614,104 @@ fn bench_change_paths() { ); } } + +/// `changes` changes on `doc`, each writing `servers/<region>/<n>/cpu`, by `actors` +/// actors in turn, as `nested` does. +fn nested_on(mut doc: Document, changes: usize, actors: usize) -> Document { + let per = changes.div_ceil(actors.max(1)); + for i in 0..changes { + if i % per == 0 { + doc.set_actor(automerge::ActorId::random()); + } + let path = [ + "servers".to_owned(), + format!("region{}", i % 4), + format!("{}", (i / 4) % 50), + "cpu".to_owned(), + ]; + transact(&mut doc, UnixMillis(1), &WRITER, |doc| { + store::write_path(doc, &path, &serde_json::json!(i)) + }) + .expect("write"); + } + doc +} + +/// The time to take `doc`'s changes into an empty document: unjudged, as Automerge +/// applies them; and screened (`access::screen::apply`). +fn screening_costs(workload: &str, doc: &Document) { + let raw: Vec<Vec<u8>> = doc + .get_changes(&[]) + .iter() + .map(|change| change.raw_bytes().to_vec()) + .collect(); + let changes = || -> Vec<automerge::Change> { + raw.iter() + .map(|bytes| automerge::Change::from_bytes(bytes.clone()).expect("change")) + .collect() + }; + let unjudged = median(3, || { + let changes = changes(); + let mut empty = Document::new(); + let started = Instant::now(); + empty.apply_changes(changes).expect("apply"); + started.elapsed() + }); + let screened = median(3, || { + let changes = changes(); + let mut empty = Document::new(); + let started = Instant::now(); + let screened = crate::access::screen::apply( + &mut empty, + Epoch::GENESIS, + changes, + &mut crate::access::screen::Waiting::default(), + &mut crate::access::screen::Refusals::default(), + None, + &mut crate::document::PatchLog::inactive(), + ) + .expect("screen"); + let elapsed = started.elapsed(); + assert_eq!(screened.applied, raw.len(), "every change taken"); + elapsed + }); + report_signatures( + workload, + unjudged, + &[("screened", screened.saturating_sub(unjudged))], + ); +} + +#[test] +#[ignore = "a benchmark: cargo benchmarks"] +fn bench_screening() { + println!(); + for changes in [1_000, 10_000, 100_000] { + screening_costs( + &format!("{changes} changes, no policy"), + &nested(changes, changes / 100), + ); + // The swarm, its policy and the writer's member entry first: every change after + // is judged by the rules (no registry: the writer's node, a member, may). + let mut start = Document::new(); + transact(&mut start, UnixMillis(1), &WRITER, |doc| { + let path = |text: &str| -> Vec<String> { text.split('/').map(str::to_owned).collect() }; + store::write_path(doc, &path("_continuum/swarm"), &serde_json::json!("bench"))?; + store::write_path( + doc, + &path("_continuum/access/policy"), + &serde_json::json!({"version": 1}), + )?; + store::write_path( + doc, + &crate::swarm::members::member_path(WRITER.node), + &serde_json::json!({}), + ) + }) + .expect("start"); + screening_costs( + &format!("{changes} changes, the policy first"), + &nested_on(start, changes, changes / 100), + ); + } +} |
