Repository navigation
IBM: parallelize the IB marker kernel over patch and bounding-box cell - #2214
sbryngelson wants to merge 1 commit into
Conversation
many_ib_patch_parallelism ran one GPU thread per patch, each walking its bounding box serially: a bed of small bodies left the GPU nearly idle and one large body held the whole kernel. s_get_ib_boxes now stores each patch's bounding cells in every periodic image (ib_box, allocated on first use) and returns the largest box, and the marker kernels collapse over (patch, box cell). The geometry tests and the atomic max on the marker are unchanged, so the markers are bit-identical to master. Marker update, bodies moving every step, periodic box, per call: A100 1.8 vs 6.5 ms (3D, 10 spheres), 2.6 vs 8.0 ms (3D, 2000); MI300A 5-18 vs 75-96 ms; mixed body sizes 6 to 230 times faster. A non-GPU build is slower than master for this option. Adds IBM -> Periodic Bodies -> many_ib_patch_parallelism (2D and 3D, one and two fluids): bodies of different size, one straddling each periodic face and moving across it. Goldens generated on master.
Lines of Code
|
|
Claude Code Review Head SHA: af59396 Files changed:
Findings: The prepared context directory was empty. The checkout is master, not the PR head, so I could not read the post-change files. The review is based on the diff plus the master versions of the unchanged callees. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2214 +/- ##
==========================================
+ Coverage 63.71% 63.99% +0.28%
==========================================
Files 90 90
Lines 24569 24604 +35
Branches 3584 3588 +4
==========================================
+ Hits 15653 15745 +92
+ Misses 6135 6065 -70
- Partials 2781 2794 +13 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
IBM: parallelize the IB marker kernel over patch and bounding-box cell
One commit on
origin/master175ec9f (after #2207). It changessrc/simulation/m_ib_patches.fpp(the marker kernel behindmany_ib_patch_parallelism), one line insrc/simulation/m_ibm.fpp, adds a test totoolchain/mfc/test/cases.pyand the goldens of its four variants.Summary
many_ib_patch_parallelism = Tdraws the immersed-boundary markers withs_apply_ib_patches_ib_parallelism. That kernel ran one GPU thread per patch, each walking its bounding box serially. A bed of a few hundred small bodies therefore used a few hundred threads, and one large body (a wall, a plate) held the whole kernel for as long as it took one thread to walk its box. With moving bodies the markers are rebuilt every Runge-Kutta stage, and in 3D with periodic faces the kernel is launched once per periodic image (27 launches), so the cost is paid 3 x 27 times a step.Now:
s_get_ib_boxes(new, one kernel) stores the bounding cells of every patch in every periodic image inib_box(6 integers per patch and image, allocated on first use, freed ins_finalize_ibm_module) and returns the largest box in cells with a max reduction.(patch, box cell)instead of looping over patches only. A thread reads its box fromib_box, leaves at once if its cell is outside the patch's own box, and otherwise does what the old loop body did.IBM -> Periodic Bodies -> many_ib_patch_parallelism(2D: circle, rectangle, ellipse; 3D: sphere, cuboid, cylinder; one body straddling each periodic face and moving across it), 1 and 2 fluids, so four goldens. No existing test used the flag in a periodic domain; the only user was the2D_mibm_particle_cloudexample.AI disclosure: made with Claude Code.
The markers are unchanged
To compare master and this branch, a temporary wrapper around
s_apply_ib_patches(not part of the PR) hashed the whole marker array, halo cells included, after every call, and the runs also wrote the restart data. Both builds usemany_ib_patch_parallelism = T, prescribed motion (moving_ibm = 1, translation plus spin) so that markers are rebuilt at every stage, random positions, and a tenth of the bodies started on a periodic face.Result on both machines (below): the hash and the number of marked cells agree at every call; every restart file (conservative variables and the marker file
ib.dat) is byte-identical (cmp). The only restart files that differ are the body-state files (ib_state_*.dat, the forces and torques), by at most 6e-17 relative: the forces are summed with atomics, and the same binary differs from itself by the same amount (master against a second run of master: 6e-17).--gpu mp --mpi--gpu acc --mpi--no-gpu --mpiAll IBM-labelled tests (the 105 listed by
--listthat contain "IBM", 93 of them non-chemistry) were also run with the flag forced on in both builds (a debug switch, not in the PR) and the goldens they generate compared. Master against this branch: the same 14 tests differ in a handful of entries each (1 to 73 entries out of 6 760 to 436 000), by at most 1e-14 absolute (4e-15 relative to the largest entry); these are two-way and force-coupled tests, and master run twice differs in the same 14 tests by the same amount. On the A100 node, 10 of them.Speed
Time of one call of
s_apply_ib_patches(system_clockaround the call, synchronized by a one-element device-to-host update), one rank, prescribed motion with bodies moving every step, periodic box, random positions at about 3 % (3D) and 10 % (2D) volume fraction, 6 (3D) and 12 (2D) cells across a body. Median over calls 4 to 46 of a 15-step run (three calls a step); the mixed-size rows are 5 (3D) and 8 (2D) steps, the plate rows 2 (3D) and 3 (2D) steps, so they are medians of 13 to 22 and 4 to 7 calls. "branch" is this PR, "master" is 175ec9f.NVIDIA A100, nvfortran 25.11,
--gpu acc(two replicates agree to within 6 %; the first is shown):AMD MI300A (Tuolumne), LLVM flang 24.0.0 (AFAR 24.3.0),
--gpu mp; the last column is the speedup of the median of the last 15 calls (see the second note):Notes on these numbers:
(number of bodies) x (largest box)threads that mostly leave at once. That is still much faster than master in every case tried, but it is wasted work that grows with both numbers.So the step time moves where the marker update was a visible part of the step: on the A100 a bed of equal bodies gains 0 to 6 % of the step, a mixed-size case 2.7 to 14 times. On the MI300A the old kernel was a large part of the step and the gain is up to 2.7 times for equal bodies and 2 to 17 times for mixed sizes.
(patch, cell)pair is visited, including the empty periodic images, so the marker update is slower than in master. nvfortran CPU, one core per rank: 0.91 ms to 13.7 ms (2D, 30 circles + 3 large bodies, 6 cells per diameter), 0.90 ms to 5.8 ms (3D, 60 spheres), medians over 118 and 34 calls. The option is documented as a GPU option; nothing else changes on CPU, but a CPU user ofmany_ib_patch_parallelismgets a slower marker update.Tests
./mfc.sh test --no-chemistry --only <UUIDs>on the 93 non-chemistry tests with immersed boundaries (every test whose name contains "IBM", the IBM Example cases included), unmodified branch, goldens as on master:--gpu mp --mpi--gpu acc --mpiThe same 93 on master: 93 / 0 on the MI300A, 93 / 0 on the A100.
The four new tests, goldens generated on master (175ec9f, MI300A,
--gpu mp) so that they also check this branch against master, run on the branch:--gpu mp --mpi--gpu acc --mpi--no-gpu --mpiCI covers Frontier (Cray CCE) and GNU on CPU; I did not run either by hand, and I did not run NVHPC 26.x.
Limitations
(bodies) x (largest box)threads per periodic image, most of which leave immediately. It is large for a case with thousands of bodies and one box hundreds of cells across. It beat master in every case I tried, including the plates; I did not try a box comparable to the whole domain.ib_boxis allocated on first use withnum_local_ibs_maxx 27 x 6 integers (19 MB at the current limit of 30 000); it is not allocated unlessmany_ib_patch_parallelism = T.moving_ibm = 1) and fixed bodies; two-way bodies (moving_ibm = 2) were only in the test-label runs.This PR was made with Claude Code (AI).