RFR: 8312424: 80% throughput decrease in Arrays.hashCode(Object[]) after JDK-8312164

Jorn Vernee jvernee at openjdk.org
Thu Jul 20 14:44:42 UTC 2023


On Thu, 20 Jul 2023 01:11:43 GMT, Glavo <duke at openjdk.org> wrote:

> The changes to `Arrays.hashCode(Object[])` in JDK-8312164 caused its performance  is reduced by about 80%.
> 
> This PR reverts this change.

With a size of `1`, the polymorphic version is not really polymorphic. This seems to be about profile pollution inside `Objects.hashCode(Object)`. But, the same pollution can happen for `Arrays.hashCode(Object[])` as well, unless an application only ever calls this method with arrays with the same element type (seems unlikely).

To create a representative 'polluted' benchmark, you should create at least 2 other arrays that hold instances of another type than `Integer`, and then call `Arrays.hashCode` a bunch (like 10K times) in the setup method. [1]. Note how the polluted case is exactly the same with the old code:


Objects.hashCode(Object)

Benchmark               (pollute)  (size)  Mode  Cnt      Score    Error  Units
ArraysHashCode.objects       true       1  avgt   15      3.053 ±  0.011  ns/op
ArraysHashCode.objects       true      10  avgt   15     26.955 ±  0.192  ns/op
ArraysHashCode.objects       true     100  avgt   15    269.441 ±  1.788  ns/op
ArraysHashCode.objects       true   10000  avgt   15  26419.822 ± 56.444  ns/op
ArraysHashCode.objects      false       1  avgt   15      3.049 ±  0.007  ns/op
ArraysHashCode.objects      false      10  avgt   15     26.797 ±  0.040  ns/op
ArraysHashCode.objects      false     100  avgt   15    268.127 ±  0.351  ns/op
ArraysHashCode.objects      false   10000  avgt   15  26446.978 ± 66.340  ns/op


(element == null ? 0 : element.hashCode())

Benchmark               (pollute)  (size)  Mode  Cnt      Score     Error  Units
ArraysHashCode.objects       true       1  avgt   15      3.056 ±   0.015  ns/op
ArraysHashCode.objects       true      10  avgt   15     26.840 ±   0.081  ns/op
ArraysHashCode.objects       true     100  avgt   15    268.204 ±   0.462  ns/op
ArraysHashCode.objects       true   10000  avgt   15  26410.336 ±  77.897  ns/op
ArraysHashCode.objects      false       1  avgt   15      0.818 ±   0.001  ns/op
ArraysHashCode.objects      false      10  avgt   15      5.130 ±   0.013  ns/op
ArraysHashCode.objects      false     100  avgt   15     58.394 ±   0.508  ns/op
ArraysHashCode.objects      false   10000  avgt   15   6274.471 ± 427.928  ns/op


If you look at `PrintInlining` output for the `(element == null ? 0 : element.hashCode())` version of the code:

Non-polluted:
    
                            @ 1   java.util.Arrays::hashCode (56 bytes)   inline (hot)
                              @ 43   java.lang.Integer::hashCode (8 bytes)   inline (hot)
                               -> TypeProfile (15360/15360 counts) = java/lang/Integer
                                @ 4   java.lang.Integer::hashCode (2 bytes)   inline (hot)
                                
 Polluted:
 
                             @ 1   java.util.Arrays::hashCode (56 bytes)   inline (hot)
                              @ 43   java.lang.Object::hashCode (0 bytes)   (intrinsic, virtual)

i.e. `Arrays::hashCode(Object[])` is still susceptible to pollution, and I don't really think that the benchmark you've added in this PR is representative of a real world scenario since it only uses one element type. I don't think using `Objects.hashCode` is really that much of a problem here. Though, I'll grant that it at least has an observable difference.

[1]: https://github.com/openjdk/jdk/compare/master...JornVernee:jdk:PollutedBenchmark

-------------

PR Comment: https://git.openjdk.org/jdk/pull/14944#issuecomment-1644050455


More information about the core-libs-dev mailing list