test: failing regression test for #261: Rectangular pattern of a hole cut scales super-linearly (#276)
* test: reproduce #261 (Rectangular pattern of a hole cut scales super-linearly) * Patterns of many hole cuts scale near-linearly (#261) Two quadratic costs: - Meshing a face tested every point against every segment of every boundary loop, so a plate face with hundreds of holes meshed in quadratic time. The vendored truck-meshalgo inside test now skips loops whose parameter box is clear of the point (they wind zero times around it). - A pattern cut each copy in turn, rebuilding and re-checking an ever more complex target per copy. Copies whose boxes are clear of each other are now one tool of many pieces (kernel::union_apart, no intersection work), cut once. 512 holes now take ~7 s instead of not finishing. The test's volume tolerance is widened from 1e-6 relative to 0.1 % of each hole: the measure meshes the bores and reads each hole ~0.06 % small, on main too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Hole-pattern test: a budget CI can meet; coarser apart-box meshes (#261) CI runs every test binary at once and is about ten times slower than a machine running this test alone (15 tests passed 60 s in the last run), so the 512-hole pattern (about 6 s alone) hit the 60 s timeout there. The budget now only has to tell linear from the quadratic hang: 300 s timeout, 120 s budget. union_apart meshes each copy coarsely (2 % of its size, box grown by twice that). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Hole-pattern test checks the scaling, not a wall-clock time (#261) CI runs every test binary at once: the 512-hole pattern (about 6 s alone, 10 s CPU single-threaded) took 177 s there, so no fixed time is reliable. The test now patterns 128 and then 512 holes and requires the second to take under 8x the first (linear is 4x, measured 3.5-4.2x here; the old quadratic cost was 16x or more), each with the volume check and a 900 s hang guard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: bherbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
6 files changed
+109
-4
No files matched your search
@@ -207,3 +207,48 @@ fn patterns_of_a_blind_hole_drill_every_copy() {
|
||||
));
|
||||
assert!((c - 2.0 * one).abs() < 1e-3 * one, "{c} vs 2 × {one}");
|
||||
}
|
||||
|
||||
/// A plate with a `count1` × `count2` feature pattern of one through-hole cut: its volume and how
|
||||
/// long the pattern took. It runs on its own thread so a hang fails the test instead of CI.
|
||||
fn hole_pattern(count1: usize, count2: usize) -> (f64, std::time::Duration) {
|
||||
use std::time::{Duration, Instant};
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "solid.box", json!({"length": 200, "width": 100, "height": 1, "operation": "new_body", "body_name": "Plate"}));
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "offset": "2", "name": "H"}));
|
||||
run(&mut s, "sketch.circle.center", json!({"center": [4, 4], "diameter": 2}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(
|
||||
&mut s,
|
||||
"solid.extrude",
|
||||
json!({"sketch": "H", "distance": "4", "direction": "negative", "operation": "cut", "targets": ["Plate"], "name": "Hole"}),
|
||||
);
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
std::thread::spawn(move || {
|
||||
let t = Instant::now();
|
||||
let r = s.execute(
|
||||
"solid.pattern.rectangular",
|
||||
&json!({"features": ["Hole"], "dir1": [1, 0, 0], "count1": count1, "spacing1": 6, "dir2": [0, 1, 0], "count2": count2, "spacing2": 6}),
|
||||
);
|
||||
let took = t.elapsed();
|
||||
let v = r.map(|_| volume(&mut s)).map_err(|e| e.to_string());
|
||||
let _ = tx.send((v, took));
|
||||
});
|
||||
let (v, took) = rx.recv_timeout(Duration::from_secs(900)).expect("the hole pattern did not finish within 900 s");
|
||||
let n = (count1 * count2) as f64;
|
||||
let v = v.expect("pattern");
|
||||
// The measure meshes the bores: each hole reads about 0.06 % small, so allow 0.1 % a hole.
|
||||
assert!((v - (200.0 * 100.0 - n * PI)).abs() < n * PI * 1e-3, "{n} holes: {v}");
|
||||
(v, took)
|
||||
}
|
||||
|
||||
/// 512 identical through-holes from a feature pattern of one cut (#261). 128 took 30 s and 512 did
|
||||
/// not finish in 150 s: each copy was cut into an ever more complex plate. The time must grow about
|
||||
/// linearly with the count. A ratio, not a time: CI runs every test binary at once and is many
|
||||
/// times slower than a machine running this alone (about 6 s for 512 holes there).
|
||||
#[test]
|
||||
fn pattern_of_512_hole_cuts_finishes_in_reasonable_time() {
|
||||
let (_, t128) = hole_pattern(16, 8);
|
||||
let (_, t512) = hole_pattern(32, 16);
|
||||
// Linear is 4×, the old quadratic cost 16× or more.
|
||||
assert!(t512.as_secs_f64() < 8.0 * t128.as_secs_f64() + 2.0, "128 holes took {t128:?}, 512 took {t512:?}");
|
||||
}
|
||||
Reference in new issue
Block a user