perf: fast-path identical snapshots in diff_snapshots (#922)
* Update agent-browser optimization plan: PR #916 submitted, Phase 2 complete Co-authored-by: Hermes <agent@hermes.ai> * perf(snapshot-diff): fast-path identical snapshots Co-authored-by: Hermes <agent@hermes.ai> * chore(pr): remove unrelated docs from snapshot-diff fast-path --------- Co-authored-by: Merlin <merlin@rbeckner.com> Co-authored-by: Hermes <agent@hermes.ai>
This commit is contained in:
@@ -101,6 +101,21 @@ pub fn diff_screenshot(
|
|||||||
|
|
||||||
/// Compute a snapshot diff using the Myers algorithm via the `similar` crate.
|
/// Compute a snapshot diff using the Myers algorithm via the `similar` crate.
|
||||||
pub fn diff_snapshots(before: &str, after: &str) -> SnapshotDiffResult {
|
pub fn diff_snapshots(before: &str, after: &str) -> SnapshotDiffResult {
|
||||||
|
// Fast path: identical inputs.
|
||||||
|
// This avoids constructing the `similar` TextDiff object and running the diff
|
||||||
|
// iteration when agents compare a snapshot to itself (common in retry/loop
|
||||||
|
// workloads).
|
||||||
|
if before == after {
|
||||||
|
let unchanged = before.lines().count();
|
||||||
|
return SnapshotDiffResult {
|
||||||
|
diff: String::new(),
|
||||||
|
additions: 0,
|
||||||
|
removals: 0,
|
||||||
|
unchanged,
|
||||||
|
changed: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let text_diff = TextDiff::from_lines(before, after);
|
let text_diff = TextDiff::from_lines(before, after);
|
||||||
|
|
||||||
let mut additions = 0usize;
|
let mut additions = 0usize;
|
||||||
@@ -192,4 +207,68 @@ mod tests {
|
|||||||
assert_eq!(result.unchanged, 1);
|
assert_eq!(result.unchanged, 1);
|
||||||
assert!(!result.diff.is_empty());
|
assert!(!result.diff.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_diff_snapshots_identical_fast_path() {
|
||||||
|
let input = "hello\nworld\n";
|
||||||
|
let result = diff_snapshots(input, input);
|
||||||
|
assert!(!result.changed);
|
||||||
|
assert_eq!(result.additions, 0);
|
||||||
|
assert_eq!(result.removals, 0);
|
||||||
|
assert_eq!(result.unchanged, input.lines().count());
|
||||||
|
assert!(result.diff.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn bench_diff_snapshots_identical_and_changed() {
|
||||||
|
use std::hint::black_box;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
let identical_a = (0..200)
|
||||||
|
.map(|i| format!("line {i}"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
let identical_b = identical_a.clone();
|
||||||
|
|
||||||
|
let changed_a = identical_a.clone();
|
||||||
|
let changed_b = (0..200)
|
||||||
|
.map(|i| {
|
||||||
|
if i == 123 {
|
||||||
|
format!("line {i} changed")
|
||||||
|
} else {
|
||||||
|
format!("line {i}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
// Keep the iteration count high enough to measure, but low enough
|
||||||
|
// to avoid long CI times when someone runs `--ignored`.
|
||||||
|
let iters = 50_000usize;
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut acc_changed = 0usize;
|
||||||
|
for _ in 0..iters {
|
||||||
|
let r = diff_snapshots(black_box(&identical_a), black_box(&identical_b));
|
||||||
|
acc_changed ^= r.unchanged;
|
||||||
|
}
|
||||||
|
let identical_ms = start.elapsed().as_secs_f64() * 1000.0;
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut acc_changed2 = 0usize;
|
||||||
|
for _ in 0..iters {
|
||||||
|
let r = diff_snapshots(black_box(&changed_a), black_box(&changed_b));
|
||||||
|
acc_changed2 ^= r.additions;
|
||||||
|
}
|
||||||
|
let changed_ms = start.elapsed().as_secs_f64() * 1000.0;
|
||||||
|
|
||||||
|
// Prevent the compiler from optimizing everything away.
|
||||||
|
black_box(acc_changed);
|
||||||
|
black_box(acc_changed2);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"bench_diff_snapshots_identical_and_changed: iters={iters} identical_ms={identical_ms:.2} changed_ms={changed_ms:.2}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user