perf(reader): SIMD kernels mirroring Rust: C2-shaped scalar loops, opt-in Vector API for filter compress/bitmap/small-table take
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Anfängerfreundlichkeit
- 8/100
- Issue-Typ
- Feature
- Klarheit
- Größtenteils klar
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- java
- Bereich
- data, performance
Rechercherichtung
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.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
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
- Vorherrschende Sprache
- Java
- Sterne
- 3
- Forks
- 2
- Ø Merge
- 9 Std. 47 Min.
- Gemergte PRs (30 T.)
- 128
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus dfa1/vortex-java
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 66/100
dfa1/vortex-java#636 ·
Maintainer antworten meist innerhalb von 1 Tag
-
bug
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 70/100
dfa1/vortex-java#655 ·
Maintainer antworten meist innerhalb von 1 Tag
-
perf
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 30/100
dfa1/vortex-java#651 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Writer: string columns written as per-chunk dicts where Rust uses its dict layout (up to 2x larger)Offenperf
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 30/100
dfa1/vortex-java#650 ·
Maintainer antworten meist innerhalb von 1 Tag
-
perf
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 28/100
dfa1/vortex-java#649 ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in dfa1/vortex-java
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 66/100
a2aproject/a2a-java#1275 ·
Maintainer antworten meist innerhalb von 1 Tag
-
module/ftp Type/Bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
ballerina-platform/ballerina-library#9476 ·
Maintainer antworten meist innerhalb von 1 Tag
-
enhancement
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
anwilli5/coin-collection-android-US#515 ·
Maintainer antworten meist innerhalb von 1 Tag
-
status: waiting-for-triage type: bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
spring-projects/spring-integration#11654 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 Unter einer Stunde Anfängerfreundlichkeit 70/100
Vakore/ZappierGames#248 ·