Skip to main content

bench_sessions/
bench_sessions.rs

1//! Session lifecycle benchmark with two data graphs sharing one compilation.
2//!
3//! Run from the repository root, for example:
4//! `cargo run --release -p shifty-engine --example bench_sessions -- \
5//!   benchmark/brick/Brick-closure.ttl benchmark/brick/models/bldg1.ttl \
6//!   benchmark/brick/models/bldg2.ttl`
7//!
8//! Each invocation is a fresh process. Use `/usr/bin/time -l` on macOS or
9//! `/usr/bin/time -v` on Linux around the binary to record peak resident memory.
10
11use shifty_engine::{CompiledShapes, FindingOptions, SessionData, SessionOptions};
12use shifty_parse::{Loaded, RdfFormat};
13use shifty_repair::GraphDelta;
14use std::env;
15use std::hint::black_box;
16use std::path::Path;
17use std::process::Command;
18use std::time::Instant;
19
20fn load(path: &str) -> Loaded {
21    Loaded::from_path(Path::new(path), RdfFormat::Turtle, None).expect("valid Turtle input")
22}
23
24fn rss_kib() -> Option<usize> {
25    let pid = std::process::id().to_string();
26    let output = Command::new("ps")
27        .args(["-o", "rss=", "-p", &pid])
28        .output()
29        .ok()?;
30    String::from_utf8(output.stdout).ok()?.trim().parse().ok()
31}
32
33fn main() {
34    let args: Vec<_> = env::args().skip(1).collect();
35    assert!(
36        args.len() == 3 || (args.len() == 4 && args[3] == "--infer"),
37        "usage: bench_sessions SHAPES DATA_A DATA_B [--infer]"
38    );
39    let options = SessionOptions {
40        inference: args.len() == 4,
41        ..SessionOptions::default()
42    };
43    let findings = FindingOptions::default();
44
45    let start = Instant::now();
46    let shapes = load(&args[0]);
47    let load_shapes_ms = start.elapsed().as_secs_f64() * 1000.0;
48    let start = Instant::now();
49    let compiled = CompiledShapes::compile(shapes).expect("compilable shapes");
50    let compile_ms = start.elapsed().as_secs_f64() * 1000.0;
51    let compiled_rss_kib = rss_kib();
52
53    let data_a = load(&args[1]).graph;
54    let data_b = load(&args[2]).graph;
55    let delta = GraphDelta {
56        delete: data_a
57            .iter()
58            .next()
59            .map(|triple| triple.into_owned())
60            .into_iter()
61            .collect(),
62        ..GraphDelta::default()
63    };
64
65    let start = Instant::now();
66    let first = compiled
67        .session(SessionData::Separate(data_a), options)
68        .expect("first session");
69    let first_session_ms = start.elapsed().as_secs_f64() * 1000.0;
70    let start = Instant::now();
71    black_box(first.validate(&findings));
72    let first_validate_ms = start.elapsed().as_secs_f64() * 1000.0;
73    let first_rss_kib = rss_kib();
74
75    let start = Instant::now();
76    for _ in 0..3 {
77        black_box(first.validate(&findings));
78    }
79    let repeated_validate_ms = start.elapsed().as_secs_f64() * 1000.0 / 3.0;
80
81    let start = Instant::now();
82    let second = compiled
83        .session(SessionData::Separate(data_b), options)
84        .expect("second session");
85    let second_session_ms = start.elapsed().as_secs_f64() * 1000.0;
86    let start = Instant::now();
87    black_box(second.validate(&findings));
88    let second_validate_ms = start.elapsed().as_secs_f64() * 1000.0;
89    let second_rss_kib = rss_kib();
90
91    let start = Instant::now();
92    let edited = first.with_delta(&delta).expect("edited session");
93    let edit_session_ms = start.elapsed().as_secs_f64() * 1000.0;
94    let start = Instant::now();
95    black_box(edited.validate(&findings));
96    let edit_validate_ms = start.elapsed().as_secs_f64() * 1000.0;
97    let edited_rss_kib = rss_kib();
98
99    println!(
100        "shapes={},data_a={},data_b={},infer={},load_shapes_ms={load_shapes_ms:.2},compile_ms={compile_ms:.2},first_session_ms={first_session_ms:.2},first_validate_ms={first_validate_ms:.2},repeated_validate_ms={repeated_validate_ms:.2},second_session_ms={second_session_ms:.2},second_validate_ms={second_validate_ms:.2},edit_session_ms={edit_session_ms:.2},edit_validate_ms={edit_validate_ms:.2},compiled_rss_kib={compiled_rss_kib:?},first_rss_kib={first_rss_kib:?},second_rss_kib={second_rss_kib:?},edited_rss_kib={edited_rss_kib:?}",
101        args[0], args[1], args[2], options.inference,
102    );
103}