perf(reader): SIMD kernels mirroring Rust: C2-shaped scalar loops, opt-in Vector API for filter compress/bitmap/small-table take
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 5/5
- Tempo estimado
- Mais de uma semana
- Facilidade para iniciantes
- 8/100
- Tipo de issue
- Funcionalidade
- Clareza
- Razoavelmente clara
- Status de atividade
- Ativa
- Stack de tecnologia
- java
- Domínio
- data, performance
Direção de pesquisa
Start with DeltaEncodingDecoder#undeltaChunk and the new SimdOperations#undeltaChunk on perf/simd-kernels, then the FusedFilterAggregate and FusedFilterSum classes for the filter-plus-aggregate loop. Run the JMH baselines and check C2 vectorization with perfasm or JFR. Done means the acceptance checklist is met, with ADR 0005 updated with the numbers, whether or not a Vector API kernel is adopted.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Summary
ADR 0005 defers the Vector API, partly because a hard --add-modules jdk.incubator.vector would tax every consumer. This issue covers the read side: which loops get an optional Vector API kernel, and which stay scalar loops shaped for C2. The write side is #484.
Selection rule (prime directive: parity with Rust). The Rust reference uses SIMD at two levels (survey: https://github.com/dfa1/vortex-java/issues/484#issuecomment-6081505161):
- Level 1, scalar loops shaped for the auto-vectorizer. All encode/decode work: the
fastlanescrate (bit-pack, delta, FoR, RLE), casts, ALP. No intrinsics. - Level 2, hand-written SIMD with one-time CPU dispatch (
vortex-buffer/src/dispatch.rsCpuKernel,fearless_simd). Used only for selection and bitmap work: filter compress, take, bitmap pack/popcount/select, UTF-8.
A Java kernel gets a Vector API implementation only if (a) the corresponding Rust operation is level 2, or (b) C2 provably fails to vectorize a level-1 loop that LLVM does. Everything else stays scalar and C2-shaped. ADR 0005's bar still applies on top: ≥ 10% over the best scalar loop on two architectures, and hot in a real profile.
Level 2: Vector API candidates (Rust uses hand-written SIMD)
Ranked by fit to the Java API:
| # | Operation | Rust | Java Vector API | Java call site |
|---|---|---|---|---|
| R1 | Filter compress: mask-select fixed-width values | arrays/filter/execute/simd_compress/ (AVX-512 maskz_compress, AVX2 permutevar8x32, NEON vqtbl1q_u8 + LUT, portable swizzle_dyn for 1/2-byte); rung 3 of the filter/execute/buffer.rs ladder |
XxxVector.compress(VectorMask) (JDK 19+, intrinsified on AVX-512/SVE; NEON lowering unverified) + VectorMask.fromLong |
none today: row filtering is fused or per-row, scans prune by zone only (see comment) |
| R2 | bool → bitmap pack (collect_bool) |
vortex-buffer/src/bit/pack.rs (AVX-512BW vptestmb, pmovmskb, NEON ushl + addp) |
compare(...) → VectorMask.toLong() |
predicate result → validity/selection bitmap |
| R3 | Small-table take: u8 codes, ≤ 16 one-byte values | fixed_width/take/small_table/{neon,avx2}.rs (vqtbl1q_u8, vmaxq_u8 bound check) |
ByteVector.selectFrom / rearrange |
DictEncodingDecoder with small u8 dictionaries; its code bound check (vmaxq_u8) shipped as maxUnsigned (fbecfb45) |
| R4 | Bitmap popcount / nth-set-bit select | bit/count_ones.rs, bit/select.rs, vortex-mask/src/intersect_by_rank.rs (SIMD popcount, BMI2 pdep/tzcnt) |
Long.bitCount is already a C2 intrinsic: measure only |
mask true-count, row-range selection |
| R5 | Take / gather | fixed_width/take/avx2/ (AVX2 gather, 4/8-byte only) |
fromArray(..., indexMap, ...) exists only for heap arrays, not MemorySegment. Weak fit, not proposed |
n/a |
| R6 | UTF-8 validation | simdutf8 |
The JDK String decode is already intrinsified (countPositives). No action |
n/a |
Each candidate needs JMH A/B (-f 3, ClassName.methodName) at selectivities 1%/50%/99% where relevant, plus a JFR profile of a real filtered scan (e.g. JavaVsJniFilterBenchmark, CalciteBoundaryAggregateBenchmark) showing the loop is hot.
Not proposed
- Dictionary gather (except the R3 small-table case),
LazyAlp*/FoR/ZigZag: level 1 in Rust, and C2 already handles the clean ones. - Any
DecodeContext/ReadOptionsflag (Strategy B).
Design constraints
- Bit-identical to the scalar path. Differential test in
SimdOperationsTest(hardwood pattern): seeded random plus edge cases (empty, tail,Long.MIN_VALUE, unsigned, NaN/-0.0). - Opt-in only, scalar default. A link failure falls back silently (DEBUG log).
- Security contract unchanged: bounds are checked before the kernel, and a kernel throws only
VortexException. - ADR 0005 (status and evidence),
docs/reference.md, and CHANGELOG are updated in the same commit.
Acceptance
- Packaging (hardwood-style, opt-in):
SimdOperationsseam withAutoVectorizedSimdOperations(default) andVectorApiSimdOperations, chosen once per JVM bySimdOperationsSupport - Level 1: scalar, C2-shaped loops (no Vector API):
AutoVectorizedSimdOperationsis the Rust-parity default for all eleven ptypes - Delta undelta: JMH baseline vs pre-interchange, C2 vectorization confirmed (perfasm/JFR), result recorded
- Fused filter-aggregate: plain-Java branch-free compare loop tried first (Rust analogue:
compare_fused.rs; keep doubleSUMsequential), result recorded - R1–R3: JMH baselines on M5 + one x86 machine before any kernel
- Vector kernel only if rule (a)/(b) holds and it is ≥ 10% over the best scalar loop on both machines
- Differential test against the scalar path
- ADR 0005 updated with the numbers either way
- Linguagem predominante
- Java
- Estrelas
- 3
- Forks
- 2
- Merge médio
- 9h 51min
- PRs com merge (30d)
- 127
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Sem modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de dfa1/vortex-java
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 66/100
dfa1/vortex-java#636 ·
Mantenedores costumam responder em até 1 dia
-
bug
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 35/100
dfa1/vortex-java#657 ·
Mantenedores costumam responder em até 1 dia
-
bug
Dificuldade 3/5 1-2 dias Facilidade para iniciantes 70/100
dfa1/vortex-java#655 ·
Mantenedores costumam responder em até 1 dia
-
perf
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 30/100
dfa1/vortex-java#651 ·
Mantenedores costumam responder em até 1 dia
-
Writer: string columns written as per-chunk dicts where Rust uses its dict layout (up to 2x larger)Abertaperf
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 30/100
dfa1/vortex-java#650 ·
Mantenedores costumam responder em até 1 dia
Todas as issues de dfa1/vortex-java
Issues semelhantes
-
maintenance
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 83/100
apache/maven-resources-plugin#569 ·
Mantenedores costumam responder em até 1 dia
-
Data Sources visit drilldown returns an empty visitDurationByType for Achilles 1.7+ results (query still reads analysis 211)Talvez já em andamento @DG47 assumiu hoje. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 77/100
Mantenedores costumam responder em até 1 dia
-
BUG
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 77/100
camel-tooling/camel-language-server#1482 ·
Mantenedores costumam responder em até 1 dia
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
Mantenedores costumam responder em até 3 dias
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
micronaut-projects/micronaut-redis#844 ·
Mantenedores costumam responder em até 4 dias