Suggestion: Use AVX-512DQ for XXH3_scrambleAcc_avx512 #1100

Closed
opened 2026-03-11 14:31:42 -05:00 by NexusXe · 2 comments
NexusXe commented 2026-03-11 14:31:42 -05:00 (Migrated from github.com)

Currently, the XXH3_scrambleAcc_avx512 function needs to simulate 64-bit multiplications using 4 instructions:

const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1);
// ...
__m512i const data_key_hi = _mm512_srli_epi64(data_key, 32);
__m512i const prod_lo     = _mm512_mul_epu32(data_key, prime32);
__m512i const prod_hi     = _mm512_mul_epu32(data_key_hi, prime32);
*xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32));

With AVX-512DQ, this can be done with a single instruction:

const __m512i prime64 = _mm512_set1_epi64((unsigned long long)XXH_PRIME32_1);
// ...
*xacc = _mm512_mullo_epi64(data_key, prime64);

Performance:

Running this quick benchmark on my machine (AMD AI 9 HX 370) shows a ~38% speedup.

Almost every CPU that implements AVX-512 also implements the DQ extension. The only exceptions are Intel's long-discontinued Xeon Phi accelerators (Knights Landing and Knights Mill). Since Xeon Phi saw very low adoption and support for it was recently removed in GCC 15, this kind of optimization that relies on AVX-512DQ is, in my opinion, worth it.

I'm not very familiar with this codebase, but if preferred I can attempt to implement this and open a PR.

Currently, the `XXH3_scrambleAcc_avx512` function needs to simulate 64-bit multiplications using 4 instructions: ```cpp const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); // ... __m512i const data_key_hi = _mm512_srli_epi64(data_key, 32); __m512i const prod_lo = _mm512_mul_epu32(data_key, prime32); __m512i const prod_hi = _mm512_mul_epu32(data_key_hi, prime32); *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); ``` With AVX-512DQ, this can be done with a single instruction: ```cpp const __m512i prime64 = _mm512_set1_epi64((unsigned long long)XXH_PRIME32_1); // ... *xacc = _mm512_mullo_epi64(data_key, prime64); ``` ## Performance: Running this quick [benchmark](https://github.com/user-attachments/files/25917457/benchmark.cpp) on my machine (AMD AI 9 HX 370) shows a ~38% speedup. Almost every CPU that implements AVX-512 [also implements the DQ extension](https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX-512). The only exceptions are Intel's long-discontinued Xeon Phi accelerators (Knights Landing and Knights Mill). Since Xeon Phi saw very low adoption and support for it was recently removed in GCC 15, this kind of optimization that relies on AVX-512DQ is, in my opinion, worth it. I'm not very familiar with this codebase, but if preferred I can attempt to implement this and open a PR.
Andarwinux commented 2026-03-21 13:10:21 -05:00 (Migrated from github.com)

On AMD, vpmullq is native 64-bit multiplier units, whereas on Intel, it is emulated by FMA units. So your optimization will actually reduce performance for all Intel CPU.

see
https://github.com/llvm/llvm-project/issues/158854
https://uops.info/html-instr/VPMULLQ_ZMM_ZMM_ZMM.html

On AMD, vpmullq is native 64-bit multiplier units, whereas on Intel, it is emulated by FMA units. So your optimization will actually reduce performance for all Intel CPU. see https://github.com/llvm/llvm-project/issues/158854 https://uops.info/html-instr/VPMULLQ_ZMM_ZMM_ZMM.html
Cyan4973 commented 2026-09-16 23:20:48 -05:00 (Migrated from github.com)

Nice idea,
but indeed, the performance difference between AMD and Intel on this specific instruction is very large,
making it not universal.

Moreover, the current AVX512 implementation is only tied to avx512f, but not avx512dq yet.

For both these reasons, I think it's proper to not follow this direction in the reference implementation.
Feel free to open an AMD specific fork that could benefit from this change.

Nice idea, but indeed, the performance difference between AMD and Intel on this specific instruction is very large, making it not universal. Moreover, the current AVX512 implementation is only tied to `avx512f`, but not `avx512dq` yet. For both these reasons, I think it's proper to not follow this direction in the reference implementation. Feel free to open an AMD specific fork that could benefit from this change.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-Cyan4973/xxHash#1100
No description provided.