PERF-2 P0-b: CG iterations per Poisson solve in the profile (ms per V-cycle) and sub-timers inside the patch regeneration (outline, hull + offset, ring projection, Winslow sweeps, respace, warm bookkeeping, mesh finalisation)
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (macos-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (ubuntu-latest) (push) Blocked by required conditions
CI / WASM Build + Size Check (push) Blocked by required conditions
CI / Distributed Training Tests (push) Blocked by required conditions
CI / CI Success (push) Blocked by required conditions
CI / Build (macos-latest) (push) Waiting to run
CI / Test (macos-latest) (push) Blocked by required conditions
Documentation / Build API Documentation (push) Failing after 5s
CI / Build (ubuntu-latest) (push) Failing after 6s
Documentation / Build User Guide (push) Successful in 6s
CI / Format Check (push) Failing after 14s
CI / Clippy Check (push) Failing after 48s
CI / Build CPU-Only (Explicit) (push) Failing after 2m21s
Performance Benchmarks / Run Benchmarks (push) Successful in 4m4s

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YJPeT6WA2e7YvAnS875AHL
This commit is contained in:
Omar Sobh
2026-09-15 22:53:26 -05:00
co-authored by Claude Fable 5.1
parent 172a26dee4
commit 1547d14ff1
4 changed files with 100 additions and 43 deletions
@@ -721,6 +721,23 @@ pub fn cylinder_flag_patch_deformed_tip(
/// [`cylinder_flag_patch_deformed_from`] with the flat tip.
#[allow(clippy::too_many_arguments)]
thread_local! {
/// PERF-2 P0 (`docs/perf2_campaign.md`): wall time [ns] of the
/// regeneration's stages on this thread — outline, hull + offset, ring
/// projection, Winslow sweeps, respace, warm bookkeeping, mesh
/// finalisation — and the number of builds (slot 7).
static REGEN_NS: std::cell::RefCell<[u64; 8]> = const { std::cell::RefCell::new([0; 8]) };
}
fn regen_charge(slot: usize, start: std::time::Instant) {
REGEN_NS.with(|r| r.borrow_mut()[slot] += start.elapsed().as_nanos() as u64);
}
/// The regeneration's stage times so far on this thread (see `REGEN_NS`).
pub fn regen_profile() -> [u64; 8] {
REGEN_NS.with(|r| *r.borrow())
}
pub fn cylinder_flag_patch_deformed_from_tip(
prev: Option<&PatchMesh>,
centre: [f64; 2],
@@ -736,9 +753,11 @@ pub fn cylinder_flag_patch_deformed_from_tip(
winslow_sweeps: usize,
tip_corner: f64,
) -> CfdResult<(PatchMesh, (usize, f64))> {
let t0 = std::time::Instant::now();
let (inner, tip) = cylinder_flag_outline_deformed_tip(
centre, r, t, edges, x_tip_ref, fillet, 3, 16, h, 1.15, tip_corner,
);
regen_charge(0, t0);
// With a flat tip the outline's corners would put 90° corners on the
// hull, whose normal offset folds the rays at the tip; the tip disc
// (already a hull source) covers the tip, so the inner points ahead of
@@ -1087,8 +1106,11 @@ fn o_grid_from_outline(
) -> CfdResult<(PatchMesh, (usize, f64))> {
inner.reverse(); // clockwise
let ns = inner.len();
let t0 = std::time::Instant::now();
let hull = convex_hull(hull_src);
let outer_poly = offset_convex_polygon(&hull, offset, 24);
regen_charge(1, t0);
let t0 = std::time::Instant::now();
// Initial outer ring: the inner point pushed along its outward normal
// (the ring is clockwise, so the outward normal is the LEFT-hand normal
// of the direction of travel) and projected onto the hull offset —
@@ -1109,6 +1131,7 @@ fn o_grid_from_outline(
)
})
.collect();
regen_charge(2, t0);
let mut inner_closed = inner.clone();
inner_closed.push(inner[0]);
// Transfinite start, or the previous mesh's interior with the new
@@ -1153,15 +1176,23 @@ fn o_grid_from_outline(
let mut last = f64::INFINITY;
let mut done = 0;
for k in 0..winslow_sweeps {
let t0 = std::time::Instant::now();
let before = x.clone();
regen_charge(5, t0);
let t0 = std::time::Instant::now();
winslow_smooth(&mut x, ns, 0.0, 1, Some(&outer_poly));
regen_charge(3, t0);
let t0 = std::time::Instant::now();
respace_rays(&mut x, ns, &eta);
regen_charge(4, t0);
let t0 = std::time::Instant::now();
last = x
.iter()
.zip(&before)
.flat_map(|(r, b)| r.iter().zip(b))
.map(|(p, q)| ((p[0] - q[0]).powi(2) + (p[1] - q[1]).powi(2)).sqrt())
.fold(0.0, f64::max);
regen_charge(5, t0);
done = k + 1;
if last < 1e-10 * h {
break;
@@ -1169,10 +1200,15 @@ fn o_grid_from_outline(
}
(done, last)
} else {
let t0 = std::time::Instant::now();
let report = winslow_smooth(&mut x, ns, 1e-10 * h, winslow_sweeps, Some(&outer_poly));
regen_charge(3, t0);
let t0 = std::time::Instant::now();
respace_rays(&mut x, ns, &eta);
regen_charge(4, t0);
report
};
let t0 = std::time::Instant::now();
let mut xs = Vec::with_capacity((nn + 1) * (ns + 1));
let mut ys = Vec::with_capacity(xs.capacity());
for row in &x {
@@ -1182,5 +1218,7 @@ fn o_grid_from_outline(
}
}
let mesh = PatchMesh::from_nodes(ns, nn, xs, ys, Some([0.0, 0.0]))?;
regen_charge(6, t0);
REGEN_NS.with(|r| r.borrow_mut()[7] += 1);
Ok((mesh, report))
}