embedded3 PERF-3 P1-3 (a): the operator refresh moves the operator into the level (no eight-array clone) and takes its components/links from the level's problem; Components::find_parallel (hook-and-shortcut union-find, same numbering) on the refresh and the hierarchy rebuild; the S2-7b device carry's shift-table clone (830 MB per build at ny 124) replaced by a borrow — slab flag ny 62 CSV byte-identical, device moving/cg tests green; ny 124 rebuild block 4,570 → 3,353 ms per step
CI / Build (macos-latest) (push) Waiting to run
CI / Test (macos-latest) (push) Blocked by required conditions
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
Documentation / Build API Documentation (push) Failing after 6s
CI / Build CPU-Only (Explicit) (push) Failing after 5s
CI / Format Check (push) Failing after 12s
Documentation / Build User Guide (push) Successful in 13s
CI / Build (ubuntu-latest) (push) Failing after 1m33s
CI / Clippy Check (push) Failing after 1m52s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m13s
CI / Build (macos-latest) (push) Waiting to run
CI / Test (macos-latest) (push) Blocked by required conditions
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
Documentation / Build API Documentation (push) Failing after 6s
CI / Build CPU-Only (Explicit) (push) Failing after 5s
CI / Format Check (push) Failing after 12s
Documentation / Build User Guide (push) Successful in 13s
CI / Build (ubuntu-latest) (push) Failing after 1m33s
CI / Clippy Check (push) Failing after 1m52s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m13s
Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
f6b34f924d
commit
651f75d96a
+8
-4
@@ -104,7 +104,7 @@ impl DeviceCg {
|
|||||||
let lap = std::time::Instant::now();
|
let lap = std::time::Instant::now();
|
||||||
let fine = Level::<f64>::new(problem.clone());
|
let fine = Level::<f64>::new(problem.clone());
|
||||||
let l_level = lap.elapsed();
|
let l_level = lap.elapsed();
|
||||||
let components = Components::find(problem, &fine.cells);
|
let components = Components::find_parallel(problem, &fine.cells);
|
||||||
let l_components = lap.elapsed();
|
let l_components = lap.elapsed();
|
||||||
let singular_count = components.singular.iter().filter(|&&s| s).count();
|
let singular_count = components.singular.iter().filter(|&&s| s).count();
|
||||||
assert!(
|
assert!(
|
||||||
@@ -193,13 +193,17 @@ impl DeviceCg {
|
|||||||
/// operator changes little per step; the hierarchy's rebuild is the
|
/// operator changes little per step; the hierarchy's rebuild is the
|
||||||
/// cost). `z` is zeroed before every V-cycle scatter, so cells absent
|
/// cost). `z` is zeroed before every V-cycle scatter, so cells absent
|
||||||
/// from the stale hierarchy get no correction rather than a stale one.
|
/// from the stale hierarchy get no correction rather than a stale one.
|
||||||
pub fn refresh(&mut self, problem: &Problem, params: &MultigridParameters) {
|
pub fn refresh(&mut self, problem: Problem, params: &MultigridParameters) {
|
||||||
let rt = runtime();
|
let rt = runtime();
|
||||||
let profile = std::env::var("RTX_E3_MOVING_PROFILE").is_ok();
|
let profile = std::env::var("RTX_E3_MOVING_PROFILE").is_ok();
|
||||||
let lap = std::time::Instant::now();
|
let lap = std::time::Instant::now();
|
||||||
let fine = Level::<f64>::new(problem.clone());
|
// PERF-3 P1-3: the operator moves into the level (no 8-array clone);
|
||||||
|
// the level's masked problem gives the same components (couplings
|
||||||
|
// toward inactive cells are zero either way) and the same links.
|
||||||
|
let fine = Level::<f64>::new(problem);
|
||||||
|
let problem = &fine.problem;
|
||||||
let l_level = lap.elapsed();
|
let l_level = lap.elapsed();
|
||||||
let components = Components::find(problem, &fine.cells);
|
let components = Components::find_parallel(problem, &fine.cells);
|
||||||
let l_components = lap.elapsed();
|
let l_components = lap.elapsed();
|
||||||
let singular_count = components.singular.iter().filter(|&&s| s).count();
|
let singular_count = components.singular.iter().filter(|&&s| s).count();
|
||||||
assert!(
|
assert!(
|
||||||
|
|||||||
@@ -437,4 +437,106 @@ impl Components {
|
|||||||
singular,
|
singular,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same components by a parallel hook-and-shortcut union-find
|
||||||
|
/// (PERF-3 P1-3): every component's root is its smallest cell index, so
|
||||||
|
/// the numbering (by root, ascending) equals the serial search's (whose
|
||||||
|
/// seed is the first unlabelled cell in ascending order = the smallest
|
||||||
|
/// of its component); the member lists are ascending (the serial ones
|
||||||
|
/// are in visit order — only their sets are used by the device path).
|
||||||
|
pub(crate) fn find_parallel(problem: &Problem, cells: &[usize]) -> Self {
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
|
let (nx, ny, nz) = (problem.nx, problem.ny, problem.nz);
|
||||||
|
let n = nx * ny * nz;
|
||||||
|
let nxy = nx * ny;
|
||||||
|
let parent: Vec<AtomicUsize> = (0..n).map(AtomicUsize::new).collect();
|
||||||
|
let links = problem.link_lists();
|
||||||
|
let is_active = |idx: usize| problem.active[idx];
|
||||||
|
// The positive-direction edges of a cell (each edge once) plus its links.
|
||||||
|
let edges = |idx: usize, mut f: &mut dyn FnMut(usize)| {
|
||||||
|
let (k, j, i) = (idx / nxy, (idx % nxy) / nx, idx % nx);
|
||||||
|
if i + 1 < nx && problem.ae[idx] > 0.0 && is_active(idx + 1) {
|
||||||
|
f(idx + 1);
|
||||||
|
}
|
||||||
|
if j + 1 < ny && problem.an[idx] > 0.0 && is_active(idx + nx) {
|
||||||
|
f(idx + nx);
|
||||||
|
}
|
||||||
|
if let Some(t) = problem.top(idx, k) {
|
||||||
|
if problem.at[idx] > 0.0 && is_active(t) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for &(other, c) in &links[idx] {
|
||||||
|
if c > 0.0 && is_active(other) {
|
||||||
|
f(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = &mut f;
|
||||||
|
};
|
||||||
|
let root_of = |idx: usize| {
|
||||||
|
let mut r = idx;
|
||||||
|
loop {
|
||||||
|
let p = parent[r].load(Ordering::Relaxed);
|
||||||
|
if p == r {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let changed = AtomicBool::new(false);
|
||||||
|
cells.par_iter().for_each(|&idx| {
|
||||||
|
edges(idx, &mut |nb: usize| {
|
||||||
|
let (ru, rv) = (root_of(idx), root_of(nb));
|
||||||
|
if ru != rv {
|
||||||
|
let (lo, hi) = if ru < rv { (ru, rv) } else { (rv, ru) };
|
||||||
|
// Hook the larger root under the smaller (atomic min).
|
||||||
|
let mut cur = parent[hi].load(Ordering::Relaxed);
|
||||||
|
while lo < cur {
|
||||||
|
match parent[hi].compare_exchange_weak(cur, lo, Ordering::Relaxed, Ordering::Relaxed) {
|
||||||
|
Ok(_) => {
|
||||||
|
changed.store(true, Ordering::Relaxed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(actual) => cur = actual,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Shortcut every cell to its root.
|
||||||
|
cells.par_iter().for_each(|&idx| {
|
||||||
|
let r = root_of(idx);
|
||||||
|
parent[idx].store(r, Ordering::Relaxed);
|
||||||
|
});
|
||||||
|
if !changed.load(Ordering::Relaxed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut id = vec![usize::MAX; n];
|
||||||
|
let mut pairs: Vec<(usize, usize)> = cells.par_iter().map(|&idx| (root_of(idx), idx)).collect();
|
||||||
|
pairs.par_sort_unstable();
|
||||||
|
let mut members: Vec<Vec<usize>> = Vec::new();
|
||||||
|
let mut singular = Vec::new();
|
||||||
|
let mut last_root = usize::MAX;
|
||||||
|
for &(root, idx) in &pairs {
|
||||||
|
if root != last_root {
|
||||||
|
members.push(Vec::new());
|
||||||
|
singular.push(true);
|
||||||
|
last_root = root;
|
||||||
|
}
|
||||||
|
let c = members.len() - 1;
|
||||||
|
members[c].push(idx);
|
||||||
|
id[idx] = c;
|
||||||
|
if problem.extra_diag[idx] > 0.0 {
|
||||||
|
singular[c] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
members,
|
||||||
|
singular,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,8 @@ impl DeviceCut {
|
|||||||
// S2-7b: the wall velocity at the open part's centroid's foot (the
|
// S2-7b: the wall velocity at the open part's centroid's foot (the
|
||||||
// host predictor's `foot_of`), and the axis feet of the solid exchange.
|
// host predictor's `foot_of`), and the axis feet of the solid exchange.
|
||||||
let centroid_foot = mask.wall_foot_centroid;
|
let centroid_foot = mask.wall_foot_centroid;
|
||||||
let shifts = mask.face_shift_tables().cloned();
|
// Borrowed: a clone here was 830 MB per build at ny 124 (P1-3 found it).
|
||||||
|
let shifts = mask.face_shift_tables();
|
||||||
let axis_foot = mask.wall_exchange_foot;
|
let axis_foot = mask.wall_exchange_foot;
|
||||||
let mut foot: [Vec<f64>; 3] = [vec![0.0], vec![0.0], vec![0.0]];
|
let mut foot: [Vec<f64>; 3] = [vec![0.0], vec![0.0], vec![0.0]];
|
||||||
for c in 0..3 {
|
for c in 0..3 {
|
||||||
@@ -170,7 +171,7 @@ impl DeviceCut {
|
|||||||
*ub_out = match shared {
|
*ub_out = match shared {
|
||||||
Some(sh) => sh[c][idx],
|
Some(sh) => sh[c][idx],
|
||||||
None if dists[c][idx].abs() <= band => {
|
None if dists[c][idx].abs() <= band => {
|
||||||
let xf = match (&shifts, centroid_foot) {
|
let xf = match (shifts, centroid_foot) {
|
||||||
(Some(sh), true) => [
|
(Some(sh), true) => [
|
||||||
x[0] + sh[c][3 * idx],
|
x[0] + sh[c][3 * idx],
|
||||||
x[1] + sh[c][3 * idx + 1],
|
x[1] + sh[c][3 * idx + 1],
|
||||||
@@ -531,7 +532,7 @@ impl DeviceStep {
|
|||||||
smoother: self.solver.params.poisson_smoother,
|
smoother: self.solver.params.poisson_smoother,
|
||||||
..MultigridParameters::default()
|
..MultigridParameters::default()
|
||||||
};
|
};
|
||||||
cg.refresh(&problem, ¶ms);
|
cg.refresh(problem, ¶ms);
|
||||||
}
|
}
|
||||||
rt.stream
|
rt.stream
|
||||||
.memcpy_dtod(&self.u, &mut self.u_star)
|
.memcpy_dtod(&self.u, &mut self.u_star)
|
||||||
|
|||||||
Reference in New Issue
Block a user