CPU profile fit: the Gaussian's cells in a loop that vectorises, output unchanged

Building each reflection's Gaussian profile was a third of the CPU pass B's samples (cytochrome C),
one scalar BraggExp per cell. BraggExp branched to its two ends before the arithmetic, and the
branches - with GCC's -ftrapping-math, which forbids running float arithmetic on a path that does not
need it - kept every loop over it scalar. It now tells the ends apart on the bits of x, an integer
comparison, runs the same arithmetic on x (or on 0 out of range) and masks the result: the same bits for
every float but NaN, checked over all 2^32 inputs against the old function, scalar and vectorised.
The cells are filled a row at a time and summed afterwards in the same order, so the loop vectorises
(8 lanes, AVX2) and the profile is unchanged. BraggScale2 chooses its operands instead of a branch;
scaling by 1 is exact. The Metal kernel shares the header and gets the same arithmetic.

cytochrome C --no-gpu: p.hkl and MTZ data identical; user cycles -7% against the previous commit on
the same (loaded, load 16-32) machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-15 15:14:51 +02:00
1 parent 81b81ec683
commit aca2b2fdc3
2 files changed
+30 -14

No files matched your search

@@ -486,13 +486,14 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
prefetch_row(img.address(static_cast<size_t>(y) * W + gx0),
img.address(static_cast<size_t>(y) * W + gx1));
cells.resize(static_cast<size_t>(Gf) * Gf);
// The cells a row at a time, a loop that vectorises; then their sum, in the same order.
for (int dy = -Rf; dy <= Rf; ++dy) {
float *row = cells.data() + static_cast<size_t>(dy + Rf) * Gf;
for (int dx = -Rf; dx <= Rf; ++dx)
row[dx + Rf] = BraggGaussian(dx, dy, s.fx, s.fy, s.ux, s.uy, s.inv_2s2r, s.inv_2s2t);
}
float gs = 0.0f;
for (int dy = -Rf; dy <= Rf; ++dy)
for (int dx = -Rf; dx <= Rf; ++dx) {
const float g = BraggGaussian(dx, dy, s.fx, s.fy, s.ux, s.uy, s.inv_2s2r, s.inv_2s2t);
cells[(dy + Rf) * Gf + (dx + Rf)] = g;
gs += g;
}
for (const float g : cells) gs += g;
const float inv_gs = 1.0f / gs;
for (float &p : cells) p *= inv_gs;
P = cells.data();