aboutsummaryrefslogtreecommitdiffstats
path: root/src/document/bench.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/document/bench.rs')
-rw-r--r--src/document/bench.rs108
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),
+ );
+ }
+}