HashMap collision speed (regression 7->8)

Doug Lea dl at cs.oswego.edu
Sun Jan 11 21:00:33 UTC 2015


On 01/11/2015 02:26 PM, Peter Levart wrote:

> Although majority of entries constitute the bins of size 13 or 14, there's only
> a single hashCode value per bin.
>
> So in this benchmark, treeifying with non-comparable keys is a waste of effort.

On the other hand, the waste seems to only cost about 10% in your runs.
I wonder why the original report using jdk7 vs jdk8 seemed larger.

>
> Are there (non-forged) sets of non-comparable keys with hashCodes where
> treeifying makes sense?

Try using a class like:
   class FHC { float f; int hashCode() { return Float.floatToIntBits(f); } }
and populate with instances with integral values for f.

Similarly for doubles.

Pre-jdk8, we devised a bit-smearing function that (among other
constraints) did OK for float/double keys with integral values,
that are not all that rare.  With treeification, we don't need to
penalize classes with decent hashCodes by bit-smearing to still
get OK performance for these kinds of cases where the tree-based
hashCode comparison helps more than Comparability per se.

Also...

It looks like the simplest path to a minor improvement is
just to cache internally (your fourth test below). But I now
recall not doing this because it adds to footprint and
the field could prevent class unloading, for only a small
benefit.

(Every time HashMap has changed, there have been reports of
performance regressions even though typical performance
generally improves.)

-Doug


>> Original JDK9 HashMap:
>>
>> Benchmark                               (initialSize)   Mode Samples
>> Score  Score error    Units
>> j.t.HashMapCollision.badDistNoComp                 16 ss        60
>> 3011.738       78.249       ms
>> j.t.HashMapCollision.badDistWithComp               16 ss        60
>> 2984.280       48.315       ms
>> j.t.HashMapCollision.goodDistNoComp                16 ss        60
>> 682.060       52.341       ms
>> j.t.HashMapCollision.goodDistWithComp              16 ss        60
>> 685.705       55.183       ms
>>
>> Original JDK9 HashMap with TREEIFY_THRESHOLD = 1 << 20:
>>
>> Benchmark                               (initialSize)   Mode Samples
>> Score  Score error    Units
>> j.t.HashMapCollision.badDistNoComp                 16 ss        60
>> 2780.771      236.647       ms
>> j.t.HashMapCollision.badDistWithComp               16 ss        60
>> 2541.740      233.429       ms
>> j.t.HashMapCollision.goodDistNoComp                16 ss        60
>> 757.364       67.869       ms
>> j.t.HashMapCollision.goodDistWithComp              16 ss        60
>> 671.617       54.943       ms
>>
>> Caching of comparableClassFor (in ClassRepository - good for heterogeneous
>> keys too):
>>
>> Benchmark                               (initialSize)   Mode Samples
>> Score  Score error    Units
>> j.t.HashMapCollision.badDistNoComp                 16 ss        60
>> 3014.888       71.778       ms
>> j.t.HashMapCollision.badDistWithComp               16 ss        60
>> 2279.757       54.159       ms
>> j.t.HashMapCollision.goodDistNoComp                16 ss        60
>> 760.743       70.674       ms
>> j.t.HashMapCollision.goodDistWithComp              16 ss        60
>> 725.188       67.853       ms
>>
>> Caching of comparableClassFor (internally - good for homogeneous keys only):
>>
>> Benchmark                               (initialSize)   Mode Samples
>> Score  Score error    Units
>> j.t.HashMapCollision.badDistNoComp                 16 ss        60
>> 3026.707       84.571       ms
>> j.t.HashMapCollision.badDistWithComp               16 ss        60
>> 2137.296       66.140       ms
>> j.t.HashMapCollision.goodDistNoComp                16 ss        60
>> 635.964        8.213       ms
>> j.t.HashMapCollision.goodDistWithComp              16 ss        60
>> 685.129       46.783       ms
>>
>>




More information about the core-libs-dev mailing list