On Sun, Oct 11, 2026 at 12:16 AM zengxx <[email protected]> wrote:
>
> Hi,
>
> While looking at wide numeric aggregates, I found that the digit
> accumulation loop in accum_sum_add() did not auto-vectorize.  It advances
> two indexes together:
>
>     for (val_i = 0; val_i < val_ndigits; val_i++)
>     {
>         accum_digits[i] += (int32) val_digits[val_i];
>         i++;
>     }
>
> The attached patch advances the destination pointer once before the loop:
>
>     accum_digits += accum->weight - val->weight;
>     for (val_i = 0; val_i < val_ndigits; val_i++)
>         accum_digits[val_i] += (int32) val_digits[val_i];

One small nit, could we use i instead of val_i and declare it directly in the
for loop, which seems like a modern coding style accepted by postgres.

>
> This follows the same general loop-canonicalization approach already used
> for the hot numeric multiplication and division loops.  It is a semantic
> no-op and adds no SIMD intrinsics, simd.h changes, ISA-specific code, or
> runtime CPU dispatch.
>
> There is prior precedent for this kind of change in numeric.c, and those
> patches were useful references:
>
> * commit 8870917623 enabled -ftree-vectorize for numeric.c and adjusted
>   the mul_var() inner loop so GCC could auto-vectorize it [1].
> * commit 9c79e646c6 adjusted the same loop form so clang could
>   vectorize it too [2].
> * commit e3d41d08a1 used div_qi = &div[qi] in div_var_fast() to
>   canonicalize the destination array reference for auto-vectorization
>   [3].
>
> The last one is especially close to this patch: it replaces an indexed
> destination with a pointer to the current offset before the hot loop.
>
> With GCC 13.3.0/x86_64 and PostgreSQL's normal -O2 -ftree-vectorize
> flags, the new loop is vectorized with runtime alias versioning:
>
>     numeric.c:11946: optimized: loop vectorized using 16 byte vectors
>     numeric.c:11946: optimized: loop versioned for vectorization because
>                      of possible aliasing
>     numeric.c:11946: optimized: loop vectorized using 8 byte vectors
>
> The generated code contains movdqu/punpckwd/paddd.  The base report for
> the original loop reports that it could not be vectorized because of a
> possible alias involving gather/scatter.
>
> Performance below is from one local machine, so it is motivation rather
> than a universal claim.  The machine is WSL2/Linux on an i5-14400F using
> GCC 13.3.0.  Each number is the median of 11 runs after 2 warmups; base
> and feature used identical task files, settings, row counts, and
> disposable clusters.
>
> 1. Single-column wide numeric SUM
>    - 200000 rows, 1020 decimal digits per value
>    - serial aggregate
>    - round 1: 43.594 ms -> 26.594 ms (1.639x)
>    - round 2: 42.714 ms -> 26.215 ms (1.629x)
>
> 2. Width sweep over a 200000-row table
>    Each query scans the same table, so fixed executor/scan overhead
>    dilutes the accumulator gain.  Values are geomeans of two rounds:
>
>    - 32 digits: 1.026x
>    - 64 digits: 1.028x
>    - 128 digits: 1.073x
>    - 256 digits: 1.161x
>    - 512 digits: 1.154x
>    - 1024 digits: 1.230x
>
>    At 1024 decimal digits:
>    - serial AVG: 1.227x
>    - forced-parallel SUM with 4 workers: 1.264x
>
>    The narrow cases are within the noise range and I would not claim a win
>    there.  The benefit becomes clearer as the numeric value gets wider and
>    accumulation is a larger fraction of total runtime.
>
> Correctness:
>
> * The full core regression suite passes (243/243).
> * Differential SQL covers 32, 64, 128, 256, 512, and 1024 decimal-digit
>   values with both positive and negative inputs, and checks exact SUM and
>   AVG results.
> * A separate check compares exact serial and forced-parallel SUM results
>   over 100000 wide values.
>
> I do not think this promises vectorization on every compiler or
> architecture.  It only puts the loop in the canonical form that GCC can
> vectorize here; other compilers can still emit the scalar form.  With
> that caveat, it is a small local change and gives a useful improvement
> for wide numeric aggregates on the tested configuration.
>
> Patch:
>   0001-numeric-canonicalize-wide-digit-accumulation.patch
>
> [1]
> https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=88709176236caf3cb9655acda6bad2df0323ac8f
> [2]
> https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=9c79e646c6f0f8df06d966c536d0c6aa33bf1b06
> [3]
> https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=e3d41d08a17549fdc60a8b9450c0511c11d666d7
>
> Thanks,
> Xiangxin Zeng



-- 
Regards
Junwang Zhao


Reply via email to