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
