Skip to content

Simple64#16245

Open
vsop-479 wants to merge 47 commits into
apache:mainfrom
vsop-479:simple64
Open

Simple64#16245
vsop-479 wants to merge 47 commits into
apache:mainfrom
vsop-479:simple64

Conversation

@vsop-479

@vsop-479 vsop-479 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Description

Simple64: pack multiple small non-negative integers into a single long.

This change try to implement Simple64 to bulk encode/decode small ints, and use it to write terms' suffixLengths or somewhere else.

@vsop-479 vsop-479 marked this pull request as draft June 11, 2026 09:37
@vsop-479 vsop-479 added the skip-changelog Apply to PRs that don't need a changelog entry, stopping the automated changelog check. label Jun 12, 2026
@vsop-479

Copy link
Copy Markdown
Contributor Author

This change has passed the core tests. And I measured its performance:

When suffix lengths are small (1~8), each value fits in a single VInt byte, making VInt extremely fast due to near-perfect branch prediction. Simple64 is slower in this case (~1.6x disadvantage).

When suffix lengths are larger (1~200), some values spill into two VInt bytes, causing branch mispredictions. Simple64 pulls ahead here (~1.3x advantage) since it uses pure bitwise operations with no branching.

For typical BlockTree suffix lengths (1~15), values stay within the single-byte VInt range, so VInt is likely faster in practice. Simple64's main benefit in this scenario is compression ratio rather than decode speed — it uses roughly half the bytes of VInt for small integers.

@vsop-479

Copy link
Copy Markdown
Contributor Author

suffix length: 1 ~ 8 integers

Benchmark                         (blockSize)  (maxSuffix)   Mode  Cnt   Score   Error   Units
Simple64Benchmark.decodeSimple64           40            8  thrpt    5  50.400 ± 0.892  ops/us
Simple64Benchmark.decodeVInt               40            8  thrpt    5  76.696 ± 0.453  ops/us

Simple64Benchmark.encodeSimple64           40            8  thrpt    5  17.514 ± 0.395  ops/us
Simple64Benchmark.encodeVInt               40            8  thrpt    5  88.496 ± 3.522  ops/us

suffix length: 1 ~ 200 integers

Benchmark                         (blockSize)  (maxSuffix)   Mode  Cnt   Score   Error   Units
Simple64Benchmark.decodeSimple64           40          200  thrpt    5  37.229 ± 0.455  ops/us
Simple64Benchmark.decodeVInt               40          200  thrpt    5  27.770 ± 0.228  ops/us

Simple64Benchmark.encodeSimple64           40          200  thrpt    5   7.014 ± 0.245  ops/us
Simple64Benchmark.encodeVInt               40          200  thrpt    5  26.317 ± 2.062  ops/us

@vsop-479 vsop-479 marked this pull request as ready for review June 16, 2026 08:18
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This PR has not had activity in the past 2 weeks, labeling it as stale. If the PR is waiting for review, notify the dev@lucene.apache.org list. Thank you for your contribution!

@github-actions github-actions Bot added the Stale label Jul 1, 2026
@vsop-479

vsop-479 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

After unrolling, Simple64 decode beats VInt across SMALL_1_8, MID_1_64, and LARGE_1_200, with the gap much larger on LARGE_1_200 (~ +47%) than on SMALL_1_8/MID_1_64 (~ +1-8%):

Benchmark                         (blockSize)  (distribution)   Mode  Cnt   Score   Error   Units
Simple64Benchmark.decodeSimple64           40       SMALL_1_8  thrpt    5  31.479 ± 0.289  ops/us
Simple64Benchmark.decodeSimple64           40        MID_1_64  thrpt    5  29.405 ± 0.197  ops/us
Simple64Benchmark.decodeSimple64           40     LARGE_1_200  thrpt    5  29.014 ± 0.209  ops/us
Simple64Benchmark.decodeSimple64           40           MIXED  thrpt    5  28.845 ± 0.100  ops/us
Simple64Benchmark.decodeVInt               40       SMALL_1_8  thrpt    5  29.156 ± 0.434  ops/us
Simple64Benchmark.decodeVInt               40        MID_1_64  thrpt    5  29.210 ± 0.205  ops/us
Simple64Benchmark.decodeVInt               40     LARGE_1_200  thrpt    5  19.704 ± 0.170  ops/us
Simple64Benchmark.decodeVInt               40           MIXED  thrpt    5  29.209 ± 0.200  ops/us
Simple64Benchmark.encodeSimple64           40       SMALL_1_8  thrpt    5  13.937 ± 0.200  ops/us
Simple64Benchmark.encodeSimple64           40        MID_1_64  thrpt    5   4.809 ± 0.022  ops/us
Simple64Benchmark.encodeSimple64           40     LARGE_1_200  thrpt    5   3.832 ± 0.047  ops/us
Simple64Benchmark.encodeSimple64           40           MIXED  thrpt    5   4.995 ± 0.035  ops/us
Simple64Benchmark.encodeVInt               40       SMALL_1_8  thrpt    5  67.789 ± 0.568  ops/us
Simple64Benchmark.encodeVInt               40        MID_1_64  thrpt    5  67.903 ± 0.231  ops/us
Simple64Benchmark.encodeVInt               40     LARGE_1_200  thrpt    5  14.346 ± 0.091  ops/us
Simple64Benchmark.encodeVInt               40           MIXED  thrpt    5  68.144 ± 0.749  ops/us

@vsop-479

vsop-479 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@mikemccand Please take a look when you get a chance -- there are TODOs mentioning simple64 in Lucene103BlockTreeTermsWriter.
Also, simple64 performs significantly faster than VInt in the LARGE_1_200 scenario, so it might be worth considering using it in other place as well.

@vsop-479

vsop-479 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Update performance.

Benchmark                         (blockSize)  (distribution)   Mode  Cnt   Score   Error   Units
Simple64Benchmark.decodeSimple64           40       SMALL_1_8  thrpt    5  33.206 ± 0.574  ops/us
Simple64Benchmark.decodeSimple64           40        MID_1_64  thrpt    5  30.486 ± 0.946  ops/us
Simple64Benchmark.decodeSimple64           40     LARGE_1_200  thrpt    5  30.372 ± 0.083  ops/us
Simple64Benchmark.decodeSimple64           40           MIXED  thrpt    5  29.892 ± 2.022  ops/us
Simple64Benchmark.decodeVInt               40       SMALL_1_8  thrpt    5  29.195 ± 0.166  ops/us
Simple64Benchmark.decodeVInt               40        MID_1_64  thrpt    5  29.103 ± 0.526  ops/us
Simple64Benchmark.decodeVInt               40     LARGE_1_200  thrpt    5  19.624 ± 0.209  ops/us
Simple64Benchmark.decodeVInt               40           MIXED  thrpt    5  29.065 ± 0.234  ops/us
Simple64Benchmark.encodeSimple64           40       SMALL_1_8  thrpt    5  13.055 ± 0.123  ops/us
Simple64Benchmark.encodeSimple64           40        MID_1_64  thrpt    5   7.561 ± 0.147  ops/us
Simple64Benchmark.encodeSimple64           40     LARGE_1_200  thrpt    5   9.451 ± 0.213  ops/us
Simple64Benchmark.encodeSimple64           40           MIXED  thrpt    5  11.357 ± 0.079  ops/us
Simple64Benchmark.encodeVInt               40       SMALL_1_8  thrpt    5  66.986 ± 3.095  ops/us
Simple64Benchmark.encodeVInt               40        MID_1_64  thrpt    5  67.117 ± 1.323  ops/us
Simple64Benchmark.encodeVInt               40     LARGE_1_200  thrpt    5  14.028 ± 0.217  ops/us
Simple64Benchmark.encodeVInt               40           MIXED  thrpt    5  66.962 ± 1.100  ops/us

@vsop-479

vsop-479 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @mikemccand for the detailed review and all the suggestions. I pushed updates addressing the comments.

I'm worried about the added GC (allocating lots of small things, briefly). They are short lived so maybe it's all in the noise. Have you run luceneutil benchy to check?

Yes, this change does add allocations for simple64 decoding (but it no longer uses suffixLengthBytes or suffixLengthsReader).
I will run luceneutil.

Was there no existing reasonably-licensed open source Simple64 impl already?

I looked around but did not find a mature, reasonably licensed Simple64 implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module:core/codecs module:core/index module:core/store skip-changelog Apply to PRs that don't need a changelog entry, stopping the automated changelog check.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants