Skip to content

Fix slow CPU halo update for the middle (y) decomposed dimension - #124

Merged
omlins merged 2 commits into
eth-cscs:masterfrom
b-fg:fix-dim-view
Jul 2, 2026
Merged

omlins merged 2 commits into
eth-cscs:masterfrom
b-fg:fix-dim-view

Conversation

@b-fg

@b-fg b-fg commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

On CPU arrays, update_halo! is ~25–115× slower (growing with face size) when the middle (y) dimension is the decomposed one than for x or z. This PR closes #123.

The issue is that memcopy! flattens both operands with view(.,:) before copying. The y-face slice view(A,:,iy,:) is IndexCartesian, while x/z faces are IndexLinear. So the flat copy forces a per-element linear→Cartesian index conversion. And this is not a stride effect since the x-face is the most scattered yet fast.

The fix is to branch memcopy! on IndexStyle(dst, src): keep the flat view(.,:) memcopy for the IndexLinear case (x/z faces + all flat buffers), else copyto!(dst, src) on the shaped views so iteration stays contiguous along the inner dimension. Using the combined IndexStyle(dst,src) matters: read_h2h! passes the y-slice as the destination.

I have conducted the tests only on CPU backend, and I think GPU backends use a different function for this. Also I have verified this in WaterLily.jl and in the linked issue MRWE. below is the WaterLily weak scalability plot using master and this PR. In the MRWE, full update_halo! (np=2, Float32) results in y-face 882→26 µs (66³), 13794→120 µs (258³) with x/z unchanged. test/test_update_halo.jl passes 922/922.

Image

PR and debugging assisted by Claude Opus 4.8.

b-fg added 2 commits June 22, 2026 21:15
memcopy! flattened both operands with view(.,:) before copying. For the
middle-dimension face slice view(A,:,iy,:) (IndexCartesian) this forces a
per-element linear->Cartesian index conversion in the copy, making the y-face
halo 25-100x slower than the x/z faces on the CPU (the cost grows with the
face size). The x- and z-face slices are IndexLinear, so they were unaffected.

Branch on IndexStyle(dst, src): keep the flat-vector memcopy for the linear
case (x/z faces, and all the flat send/recv buffers), and copy the shaped
views directly when either operand is IndexCartesian (the y face) so iteration
stays contiguous along the inner dimension. Output is bit-identical.

Measured on update_halo! (np=2, Float32, system OpenMPI), y-face per call:
  N=66:  882.7 -> 25.9 us  (34x)
  N=130: 2836  -> 41.3 us  (69x)
  N=258: 13794 -> 119.7 us (115x)
x and z unchanged. CPU path only; the GPU (CUDAExt/AMDGPUExt) packing kernels
and CUDA-aware MPI buffers do not use this function. The Polyester path already
iterates with eachindex (Cartesian-aware) and is unaffected.

Assisted-by: Claude:claude-opus-4-8
@luraess

luraess commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Thanks for catching that one! LGTM

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 3.56%. Comparing base (6f48cf8) to head (ae3ebb5).
⚠️ Report is 173 commits behind head on master.

Files with missing lines Patch % Lines
src/update_halo.jl 0.00% 2 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff            @@
##           master    #124      +/-   ##
=========================================
+ Coverage    2.91%   3.56%   +0.64%     
=========================================
  Files          23      25       +2     
  Lines         754    1038     +284     
=========================================
+ Hits           22      37      +15     
- Misses        732    1001     +269     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@omlins

omlins commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Thanks a lot for the PR @b-fg !

@omlins
omlins merged commit db3d04c into eth-cscs:master Jul 2, 2026
3 checks passed
b-fg added a commit to WaterLily-jl/WaterLily.jl that referenced this pull request Jul 2, 2026
Brings the grid-independent Poisson stopping criterion to mpi-igg. tol
(default 2e-3) is the max-norm knob max|r| < tol; the bulk term is the
mean residual Σ|r|/N < tol/10 (L1/N, in max-norm units). Convergence
requires BOTH. Supersedes the earlier RMS-only (L2/N) form and its
superseded MPI port c4cec26.

MPI adaptations (dispatch-free, via p.inslen):
- src/parallel.jl: add local_sumabs(a)=sum(abs,a), the L1 reduction
  (didn't exist; only local_dot/local_sum were present).
- src/Poisson.jl: L₁(p)=global_allreduce(local_sumabs(p.r)) (ghosts≡0,
  so the whole-array sum = global interior, no double-count);
  l1n_tol(p::Poisson,tol)=(tol/10)*p.inslen uses the GLOBAL interior
  count (not length(inside), which is rank-local under MPI); L∞ keeps
  mpi-igg's global_max form; both solver!s take PR 307's combined break
  and keep mpi-igg's pin_pressure!+comm! ending.
- test/test_poisson.jl: PR 307's bounds + the new L∞ < 2e-3 checks.

FP64 accumulation — investigated, NOT needed. Julia sum(abs,·) is
pairwise (err ~log₂N·eps): rel.err ~1e-7 at 1e9 cells for both uniform
and peaked residuals, four orders below the ~1% the criterion tolerates.
The earlier Σr² saturation (~290³) was the naive BLAS-dot accumulator
(p.r⋅p.r), not the summation — and L₂ is no longer in the stopping path.
GPU reductions are tree-based; the MPI Allreduce sums only nprocs
partials. Kept plain FP32. (bench/tol_percell/fp64_l1_investigate.jl)

Also bump ImplicitGlobalGrid compat to 0.17.1 (registered 2026-07-02,
carries the y-halo fix, upstream PR eth-cscs/ImplicitGlobalGrid.jl#124).

Validated: serial grid-independence mean_iters=1.0 at 32/64/128 (L∞
3.6e-6→8e-8); MPI np=1 ≡ serial bit-identical; np=4 parity max|u|
−0.13%, ke −0.17%; criterion lowers np=4 iters 97→80 vs the old tol.
KA suite 293/293 (incl. the 2 new L∞<2e-3 checks); MPI suite 23/23.

Assisted-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Performance issue on single-thread CPU backend when decomposing the second dimension of a 3D array

4 participants