Skip to content

Benchmark: preconditioner

Effect of the reference-material (Green's-function) preconditioner of Ladecký et al., Appl. Math. Comput. 446 (2023) 127835, on the homogenization example-P reference vs. -P none. Both use the same fused matvec kernel and are run to convergence (relative tolerance 1e-06).

Test machine & code version

  • CPU: AMD Instinct MI300A Accelerator (192 logical cores)
  • GPU: 4x AMD Instinct MI300A
  • muGrid: 0.110.0-dirty — run 2026-06-29T12:13:40

Run configuration: 3D, single spherical inclusion, fused stiffness kernel, 6 load cases (iterations summed over all cases).

CG iterations vs. grid size

The central result: unpreconditioned CG iterations grow with the grid (the condition number is O(h⁻²)), while the reference preconditioner makes the count nearly independent of grid size. The count depends only on the operator and preconditioner, not the device or the MPI decomposition, so this is measured on a single CPU core.

Preconditioner 16³ (4k) 24³ (14k) 32³ (33k) 48³ (111k) 64³ (262k)
none 765 1290 1593 2418 3225
reference 105 105 105 102 102
CPU-core wall-time speedup 10× 15× 19×

(last row: unpreconditioned ÷ reference wall time on one CPU core)

Iterations vs. grid size

Reference solve: device & MPI scaling

This mirrors the (unpreconditioned) homogenization benchmark, but for the reference-preconditioned solve: the same single-CPU-core / full-machine-MPI-CPU / single-GPU / multi-GPU comparison, across 3D grid sizes. Because the iteration count is grid-independent, this isolates the per-iteration cost — and each preconditioned iteration applies a forward/inverse FFT pair, so it is where the FFT-engine paths matter: the native N-D transform on the GPU, and the slab MPI decomposition on multi-rank runs.

Each configuration is swept to the largest grid that still fits in memory: the first size that runs out of memory is recorded as OOM in the table and dropped from the plot, and larger sizes for that configuration are not attempted.

Configuration 16³ (4k) 24³ (14k) 32³ (33k) 48³ (111k) 64³ (262k) 96³ (885k) 128³ (2.1M) 192³ (7.1M) 256³ (16.8M) 384³ (56.6M) 512³ (134.2M) 768³ (453.0M)
CPU (1 core) 0.279 0.88 2.04 7.16 17.4 60.9 153
CPU (92 cores, MPI) 0.22 0.345 1.69 3.5 12.8 22.8 86.2 195
GPU (1 device) 0.605 0.722 0.728 0.664 0.65 1.09 1.99 5.89 13.2 OOM
GPU (4 devices, MPI) 3.07 1.33 2.1 1.73 5.12 10.2 36.6 75.7 OOM

(values are solve time in seconds, run to convergence; OOM = ran out of memory)

Reference solve time vs. grid size

The preconditioner parallelises cleanly: it is applied in Fourier space by the FFT engine, which owns its MPI decomposition, and the per-mode block solve is rank-local. -P reference gives identical iteration counts and homogenised stiffness in serial and under MPI, so the single CPU core is quickly left behind and the largest grids are reached by MPI domain decomposition across all CPU cores or across several GPUs (one rank per device, round-robin).

All data points live in the shared benchmark database benchmarks/results.csv (date, code version, machine, parameters, results). This page is generated by examples/benchmark_homogenization_preconditioner.py; re-render from the database with --render-only, or run a fresh measurement that appends a new dated row set:

python examples/benchmark_homogenization_preconditioner.py \
    --doc-out docs/benchmark_homogenization_preconditioner.md