On Tue, 13 Oct 2026 08:56:30 GMT, Larry <[email protected]> wrote:
> ### Description
>
> The AVX2 loop in generate_updateBytesAdler32() processed 16 bytes per
> iteration using two vpshufb and four vpaddd instructions, and reduced the
> accumulators with vpmulld followed by a vphaddd chain.
>
> VPHADDD is not a cheap single-µop operation: it decodes to three µops on
> Intel P-cores — two in-lane shuffle µops plus one add — and those shuffle
> µops contend for the shuffle pipes; the AVX forms are also microcoded on AMD
> Zen and Intel E-cores
> ([uops.info](https://uops.info/html-instr/VPHADDD_YMM_YMM_YMM.html)). In a
> hot reduction loop this makes the vphaddd chain throughput-limited by the
> shuffle pipes, hence relatively costly.
>
> This change rewrites the AVX2 loop as a dot product:
> - vpsadbw computes the byte sum for a;
> - vpmaddubsw/vpmaddwd compute the weighted byte sums for b, using two new
> weight tables;
> - the loop processes 64 bytes per iteration with two independent accumulators
> to shorten the dependency chain;
> - the AVX2 horizontal reduction uses 128-bit adds and shuffles instead of the
> vphaddd chain;
> - the 16/32-byte tails are handled with SIMD blocks.
> - the reduction mod BASE (65521) uses the gcc magic multiply (q = (x *
> 2147975281) >> 47) instead of two divl instructions.
>
> ### TEST
>
> - env: Intel Xeon 6980P (Granite Rapids), single socket, 128 cores / 256
> threads (SMT2), 3 NUMA nodes, 755 GiB RAM, Ubuntu 22.04.4 LTS, glibc 2.35
> - JMH: test/micro/org/openjdk/bench/java/util/TestAdler32.java;
> - jvmArgs: "-Xms4g -Xmx4g -XX:UseAVX=2"
> - results (ops/ms, mean):
> | size | baseline | patched | delta |
> | ---: | ---: | ---: | ---: |
> | 1 | 104097.5 | 167073.8 | +60.5% |
> | 2 | 101692.6 | 159382.4 | +56.7% |
> | 4 | 94645.6 | 145376.2 | +53.6% |
> | 8 | 84128.9 | 122917.0 | +46.1% |
> | 15 | 69304.3 | 91653.2 | +32.2% |
> | 16 | 66870.0 | 161618.9 | +141.7% |
> | 24 | 56286.5 | 111292.6 | +97.7% |
> | 31 | 50346.7 | 84490.9 | +67.8% |
> | 32 | 56756.3 | 71429.1 | +25.9% |
> | 64 | 52268 | 70605 | +35% |
> | 256 | 30809 | 59958 | +95% |
> | 1024 | 14318 | 33684 | +135% |
> | 4096 | 4475 | 10687 | +139% |
> | 8192 | 2268 | 5487 | +142% |
> | 65536 | 291.3 | 564.9 | +94% |
>
> Sizes below 16 bytes use the scalar loop in both versions; the only relevant
> difference is the final reduction modulo BASE, which baseline performs with
> two divl instructions and the patched version with the magic multiply (q = (x
> * 2147975281) >> 47). These rows therefore isolate the magic-multiply change.
> Sizes 16-31 additionally use a new 16-byte SIMD block, and size ...
Correctness looks fine, a fuzz test against a Java Adler-32 (0xFF data near
LIMIT, `-XX:UseAVX=2`, `CopyAVX3Threshold` 0 and 8192) found no mismatches.
Main question is the AVX-512 dispatch, inline. Could the jtreg `TestAdler32`
also get a `-XX:UseAVX=2` run with 0xFF data near LIMIT?
src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp line 89:
> 87: const int BASE = 65521;
> 88: const int DIV_BASE_MAGIC_SHIFT = 47;
> 89: const int DIV_BASE_MAGIC = 2147975281U; // gcc magic for unsigned
> divide by 65521
Doesn't fit in an `int`, relies on `movl` zero-extending. Could this be
`juint`? The comment above should also say 2^32 unsigned rather than
Integer.MAX_VALUE.
src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp line 167:
> 165: if (VM_Version::supports_avx512vl()) {
> 166: // AVX2 performs better for smaller inputs because of leaner post
> loop reduction sequence..
> 167: __ cmpl(s, MAX2(128, CopyAVX3Threshold));
`CopyAVX3Threshold` is 0 by default on Zen 5 and Intel server parts with
`serialize`, so chunks over 128 bytes still take the AVX-512 loop. On a
9950X3D2, 256 to 65536 bytes are within 1.3% of baseline with default flags,
and 40 to 88% faster with `-XX:CopyAVX3Threshold=8192`. What do you get on
Granite Rapids with default flags?
-------------
PR Review: https://git.openjdk.org/jdk/pull/33338#pullrequestreview-5722446498
PR Review Comment: https://git.openjdk.org/jdk/pull/33338#discussion_r4431478628
PR Review Comment: https://git.openjdk.org/jdk/pull/33338#discussion_r4431478630