Skip to content

Optimize JVM array hashing without reflection#3312

Merged
He-Pin merged 1 commit into
mainfrom
perf/optimize-hash-code-arrays
Jul 10, 2026
Merged

Optimize JVM array hashing without reflection#3312
He-Pin merged 1 commit into
mainfrom
perf/optimize-hash-code-arrays

Conversation

@He-Pin

@He-Pin He-Pin commented Jul 10, 2026

Copy link
Copy Markdown
Member

Motivation

HashCode.hash iterates JVM arrays through java.lang.reflect.Array, adding reflective per-element access and boxing in a shared utility. A focused JDK 17 JMH comparison showed this path is substantially slower than typed array loops.

Modification

  • Dispatch all nine JVM array kinds to typed while loops.
  • Add a directional test that uses the original java.lang.reflect.Array algorithm as the parity oracle for primitive, reference, empty, null-element, and nested arrays.
  • Add a reproducible JMH benchmark for primitive and reference arrays.

Result

Hash values remain compatible while the measured array paths improve by roughly 39x to 135x. JDK 17, 2 forks, 5 warmup iterations, 8 measurement iterations, 250 ms each:

Benchmark main optimized speedup
Int[16] 824.277 ns/op 6.106 ns/op 135.0x
Int[256] 12749.433 ns/op 183.033 ns/op 69.7x
AnyRef[16] 635.492 ns/op 13.945 ns/op 45.6x
AnyRef[256] 9491.604 ns/op 240.387 ns/op 39.5x

Tests

  • sbt "actor-tests / Test / testOnly org.apache.pekko.util.HashCodeSpec" - passed, 3 tests
  • sbt "++3.3.8" "actor-tests / Test / testOnly org.apache.pekko.util.HashCodeSpec" - passed, 3 tests
  • sbt "bench-jmh/Jmh/run -wi 5 -i 8 -f 2 -w 250ms -r 250ms -t 1 -p size=16,256 .*HashCodeArrayBenchmark.*" - passed; results above
  • sbt +headerCheckAll - passed
  • sbt checkCodeStyle - passed
  • scalafmt --list --mode diff-ref=origin/main - passed
  • git diff --check - passed
  • qodercli formal stdout review - no must-fix findings

References

Refs #3300

Motivation:
HashCode.hash iterates JVM arrays through java.lang.reflect.Array, adding reflective per-element access and boxing in a shared utility.

Modification:
Dispatch all nine JVM array kinds to typed while loops. Add a directional test that uses the original reflective algorithm as the parity oracle across primitive, reference, empty, null-element, and nested arrays. Add a JMH benchmark for primitive and reference arrays.

Result:
Hash values remain compatible while JDK 17 JMH measurements improve by roughly 39x to 135x for the measured 16- and 256-element arrays.

Tests:
- JDK 17 Scala 2.13 HashCodeSpec: 3 tests passed
- JDK 17 Scala 3.3.8 HashCodeSpec: 3 tests passed
- JDK 17 JMH: Int[16] 824.277 to 6.106 ns/op; Int[256] 12749.433 to 183.033 ns/op; AnyRef[16] 635.492 to 13.945 ns/op; AnyRef[256] 9491.604 to 240.387 ns/op
- sbt +headerCheckAll and checkCodeStyle passed
- scalafmt --list --mode diff-ref=origin/main passed
- git diff --check passed
- qodercli formal stdout review found no must-fix findings

References:
Refs #3300

@pjfanning pjfanning left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@He-Pin He-Pin merged commit 15dcac1 into main Jul 10, 2026
10 checks passed
@He-Pin He-Pin deleted the perf/optimize-hash-code-arrays branch July 10, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants