On Wed, 4 Nov 2026 14:32:01 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-mul...
>
> Larry has updated the pull request incrementally with one additional commit
> since the last revision:
>
> 8394260: Align AVX-512 Adler32 loop entry
src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp line 423:
> 421:
> 422: reduce_mod_base(a_d, rcx);
> 423: reduce_mod_base(b_d, rcx);
If `size` is 0 at this point these 2 calls will be executed again at
`FINAL_REDUCE`.
test/hotspot/jtreg/compiler/intrinsics/zip/TestAdler32.java line 169:
> 167: byte[] bytes = new byte[M + offset];
> 168: if (Boolean.getBoolean("allFF")) {
> 169: Arrays.fill(bytes, (byte) 0xFF);
Consider using the `0xfff0fff0` pattern instead.
test/micro/org/openjdk/bench/java/util/TestAdler32.java line 40:
> 38:
> 39: @Param({"1", "2", "4", "8", "15", "16", "24", "31", "32",
> 40: "64", "128", "256", "512", "1024", "2048", "5012", "8192",
consider adding `4096` which you use in benchmark in Description.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/33338#discussion_r4470540387
PR Review Comment: https://git.openjdk.org/jdk/pull/33338#discussion_r4470569954
PR Review Comment: https://git.openjdk.org/jdk/pull/33338#discussion_r4470629845