From 94db116f03af489471f48a8ea432d7654a1cb39b Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 12 Nov 2026 00:35:29 +0000 Subject: [PATCH] craft-metadata: interleave the linear-time scan test's runs The best-of-three ratio still failed once under load. The test now alternates five runs of 50 000 and 200 000 attributes and compares the fastest of each, so a burst of load slows both sizes. Six runs at load average 55 gave ratios of 3.9 to 5.4 against the bound of 10. --- crates/metadata/src/xmp_merge.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/metadata/src/xmp_merge.rs b/crates/metadata/src/xmp_merge.rs index 2a3be72af..3056225b0 100644 --- a/crates/metadata/src/xmp_merge.rs +++ b/crates/metadata/src/xmp_merge.rs @@ -466,7 +466,7 @@ mod tests { fn many_attributes_scan_in_linear_time() { // quick-xml's duplicate-name check compares each attribute with all earlier ones: 200 000 attributes on // one description took over 20 s to scan, about 30 ms with the set. Four times the attributes must take - // about four times as long, not sixteen. A ratio of best-of-three times holds on a loaded machine, where + // about four times as long, not sixteen. A ratio of the fastest runs holds on a loaded machine, where // a fixed bound does not. let packet = |n: usize| { let mut s = String::from( @@ -479,20 +479,20 @@ mod tests { s.push_str("/>"); s }; - let best = |n: usize| { - let s = packet(n); - (0..3) - .map(|_| { - let t = std::time::Instant::now(); - let found = scan(&s, &[]).unwrap(); - let took = t.elapsed(); - assert_eq!(found.descs[0].attrs.len(), n + 2, "every attribute is read"); - took - }) - .min() - .unwrap_or_default() + let run = |s: &str, n: usize| { + let t = std::time::Instant::now(); + let found = scan(s, &[]).unwrap(); + let took = t.elapsed(); + assert_eq!(found.descs[0].attrs.len(), n + 2, "every attribute is read"); + took }; - let (small, large) = (best(25_000), best(100_000)); + let (n, small_packet, large_packet) = (50_000, packet(50_000), packet(200_000)); + // interleaved, so a burst of load slows both sizes rather than one; the fastest run of each counts + let (mut small, mut large) = (std::time::Duration::MAX, std::time::Duration::MAX); + for _ in 0..5 { + small = small.min(run(&small_packet, n)); + large = large.min(run(&large_packet, 4 * n)); + } let ratio = large.as_secs_f64() / small.as_secs_f64().max(1e-6); assert!(ratio < 10.0, "4x the attributes took {ratio:.1}x as long ({small:?}, then {large:?})"); }