#15289·Redis

BITOP OR/XOR slows down when short source values leave a scalar tail

Author: GallopmCreated Jun 1, 2026Updated Sep 10, 2026

Describe the bug

After running a Redis build that includes 8dfb823 (Implement DIFF, DIFF1, ANDOR and ONE for BITOP #13898), I noticed performance degradation in existing BITOP operations when the string values stored at the source keys are short and their length is not a multiple of the AVX2 block size.

In my test dataset, the string values stored at these source keys are all 50 bytes long. This refers to the source value length, not the key name length. On an AVX2-capable machine, the new code handles one 32-byte vector block and then processes the remaining 18 bytes in the scalar tail.

To reproduce

I used a build at its parent commit 391e345 as the baseline, and tested a build including 8dfb823. Each benchmark was run for 20 rounds.

The first workload is BITOP XOR with 10 source keys, the string values stored at these source keys are all 50 bytes long:

redis-benchmark -n 1000000 -P 10 --csv \
  BITOP XOR tmp key:1789 key:8988 key:345 key:12 key:5467 \
  key:998 key:7345 key:4 key:3098 key:9999

The slowdown was obvious and consistent:

Metric Baseline 391e3452 8dfb823 build Change p-value
RPS 372704.21 352532.08 -5.41% 0.000000007
avg latency ms 1.28755 1.36395 +5.93% 0.000000001
p50 latency ms 1.26340 1.33340 +5.54% < 0.000000001
p95 latency ms 2.04500 2.21580 +8.35% 0.000036038
p99 latency ms 2.20460 2.37460 +7.71% 0.000000001

The second workload is BITOP OR with the same 10 source keys, the string values stored at these source keys are all 50 bytes long:

redis-benchmark -n 1000000 -P 10 --csv \
  BITOP OR tmp key:1789 key:8988 key:345 key:12 key:5467 \
  key:998 key:7345 key:4 key:3098 key:9999

The OR signal is weaker than XOR, but it follows the same direction:

Metric Baseline 391e3452 8dfb823 build Change p-value
RPS 367978.76 355405.10 -3.42% 0.011832295
avg latency ms 1.30615 1.35535 +3.77% 0.005207520
p50 latency ms 1.28780 1.33180 +3.42% < 0.000000001
p95 latency ms 2.07580 2.17420 +4.74% 0.193815248
p99 latency ms 2.26620 2.36020 +4.15% 0.026845751

Expected behavior

Existing BITOP OR and BITOP XOR workloads should not become slower for short unaligned source string values. Can this degradation be eliminated or alleviated while keeping the improvement for larger bitmap values?

Additional information

This does not look like a general AVX2 regression. In local length sweeps, the new code was faster for larger source values, for example 1024-byte and 8192-byte string values. The slowdown mainly appeared for short source values whose length is not a multiple of 32, such as 50, 56, or 63 bytes.

For example, with BITOP OR over 10 source keys whose string values have the listed lengths:

String length Baseline avg latency ms 8dfb823 avg latency ms Change
50 0.93775 0.96875 +3.31%
56 0.97600 1.00550 +3.02%
63 1.00825 1.07325 +6.45%
64 0.84950 0.83750 -1.41%
1024 1.00825 0.93725 -7.04%
8192 2.26950 1.72025 -24.20%

The code path that looks relevant is that BITOP XOR and BITOP OR now enter the AVX2 helper when available, and the scalar byte tail loop was rewritten to support the newly added operators as well as the existing ones.

For these 50-byte source values, only the first 32 bytes are handled by AVX2. The remaining 18 bytes go through the rewritten scalar tail. In a local experiment, disabling AVX2 did not remove the short-value slowdown, while keeping the new commit but splitting the old operators (AND, OR, XOR, NOT) back into a simpler scalar tail path may recovered most of it. That makes the shared tail loop a likely place to check.