HappenLee opened a new pull request, #65738:
URL: https://github.com/apache/doris/pull/65738
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary:
`BitPacking::UnpackValues` currently decodes every complete 32-value batch
with scalar shifts and masks. This PR adds an x86 PDEP implementation for
`uint8_t`, `uint16_t`, and `uint32_t`, with AVX2 widening for narrow `uint16_t`
and `uint32_t` values.
The optimized functions are compiled with `target("bmi2,avx2")`. Runtime
dispatch uses `__builtin_cpu_supports("bmi2")` and
`__builtin_cpu_supports("avx2")`; unsupported CPUs, architectures, output
types, and remainder values continue to use the generic scalar implementation.
Doris therefore does not require a global `-mbmi2` build flag.
The PR also adds unit tests for every supported bit width, including full
batches and truncated/remainder input, plus a reproducible benchmark comparing:
- the generic scalar kernel;
- the direct PDEP kernel;
- the actual `BitPacking::UnpackValues` dispatch path.
The benchmark covers 4K, 256K, and 1M values and validates optimized output
against the scalar reference before measuring.
#### Benchmark results
Hardware: Intel Xeon Platinum 8457C, 2 MiB private L2 per core. Release
build pinned to one CPU. Values below are CPU-time medians in microseconds.
L2-sized working set: 256K `uint32_t` values. The output is 1 MiB and the
packed input is 64-448 KiB.
| bit width | scalar | PDEP | speedup |
| ---: | ---: | ---: | ---: |
| 2 | 41.0 | 27.9 | 1.47x |
| 4 | 38.5 | 29.0 | 1.33x |
| 6 | 61.6 | 28.6 | 2.15x |
| 8 | 32.5 | 31.5 | 1.03x |
| 10 | 77.6 | 36.0 | 2.16x |
| 12 | 51.1 | 35.9 | 1.42x |
| 14 | 50.6 | 47.1 | 1.07x |
The same original cross-implementation benchmark with 1M `uint32_t` values
produced the following medians:
| bit width | Velox | Doris generic/scalar | Doris actual/PDEP |
| ---: | ---: | ---: | ---: |
| 2 | 766.6 | 184.2 | 279.0 |
| 4 | 769.9 | 199.7 | 290.7 |
| 6 | 768.8 | 260.1 | 277.1 |
| 8 | 768.9 | 193.8 | 323.8 |
| 10 | 770.8 | 372.9 | 267.2 |
| 12 | 769.7 | 365.5 | 298.8 |
| 14 | 769.1 | 351.0 | 322.4 |
The result is workload- and bit-width-dependent. PDEP is faster for all
measured widths while the working set remains in L2, although the gains at
widths 8 and 14 are marginal. At 1M values, the actual PDEP path is faster than
the scalar path at widths 10, 12, and 14, but slower at widths 2, 4, 6, and 8.
Both Doris paths remain faster than the Velox baseline in this test. The
multi-size benchmark is included so this trade-off remains visible and
reproducible during review.
### Release note
Improve bit-packed integer decoding on BMI2 and AVX2 capable x86 CPUs.
### Check List (For Author)
- Test:
- [x] Unit Test: `./run-be-ut.sh -j 48 --run --filter=BitPackingTest.*`
- [x] Manual test: compiled and linked `benchmark_test`; ran scalar,
direct PDEP, and actual-path cases at 256K and 1M values
- [x] `build-support/check-format.sh`
- [x] `build-support/run-clang-tidy.sh --build-dir be/build_RELEASE
--files be/benchmark/benchmark_main.cpp be/test/util/bit_packing_test.cpp`
- Behavior changed: Yes. Supported x86 CPUs use the PDEP path for complete
32-value batches; all other cases retain the scalar path.
- Does this need documentation: No
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]