Optimized HashSet.toArray()
Tagir Valeev
amaembo at gmail.com
Mon Oct 1 05:03:20 UTC 2018
Hello!
I think that HashSet.toArray(), HashMap.keySet().toArray() and
HashMap.values().toArray() methods are used often enough to deserve a
dedicated optimized implementation. Here's the patch I propose which
is based on KeySet#forEach and AbstractCollection#toArray
implementations:
http://cr.openjdk.java.net/~tvaleev/patches/hashset_toarray/patch.txt
I performed quick JMH test for HashSet.toArray(). The source code is here:
http://cr.openjdk.java.net/~tvaleev/patches/hashset_toarray/jmh/ToArray.java
Result on JDK 11+28 is here:
http://cr.openjdk.java.net/~tvaleev/patches/hashset_toarray/jmh/jmh_toArray_11.txt
Result on JDK 11+28 with patch applied is here
http://cr.openjdk.java.net/~tvaleev/patches/hashset_toarray/jmh/jmh_toArray_11_patched.txt
Summary (non-patched):
Benchmark (size) Score Error Units
ToArray.toArray 0 6,327 ± 0,094 ns/op
ToArray.toArray 1 55,040 ± 0,389 ns/op
ToArray.toArray 10 112,903 ± 3,571 ns/op
ToArray.toArray 1000 11281,875 ± 74,423 ns/op
ToArray.toArray 100000 2795345,640 ± 57164,196 ns/op
ToArray.toArray 10000000 443763064,267 ± 82551994,563 ns/op
ToArray.toArrayPresized 0 8,244 ± 0,054 ns/op
ToArray.toArrayPresized 1 57,094 ± 0,431 ns/op
ToArray.toArrayPresized 10 105,456 ± 3,831 ns/op
ToArray.toArrayPresized 1000 11935,895 ± 251,150 ns/op
ToArray.toArrayPresized 100000 2771938,363 ± 42917,423 ns/op
ToArray.toArrayPresized 10000000 421335484,317 ± 66222482,723 ns/op
ToArray.toObjectArray 0 8,288 ± 0,060 ns/op
ToArray.toObjectArray 1 49,415 ± 2,454 ns/op
ToArray.toObjectArray 10 94,243 ± 2,346 ns/op
ToArray.toObjectArray 1000 10061,125 ± 77,197 ns/op
ToArray.toObjectArray 100000 2455011,037 ± 86539,734 ns/op
ToArray.toObjectArray 10000000 416595706,650 ± 84619961,188 ns/op
Summary (patched):
Benchmark (size) Score Error Units
ToArray.toArray 0 5,319 ± 0,050 ns/op
ToArray.toArray 1 22,235 ± 0,365 ns/op
ToArray.toArray 10 57,515 ± 0,687 ns/op
ToArray.toArray 1000 6586,112 ± 71,258 ns/op
ToArray.toArray 100000 1700754,903 ± 41289,676 ns/op
ToArray.toArray 10000000 299815797,250 ± 37778823,759 ns/op
ToArray.toArrayPresized 0 6,689 ± 0,042 ns/op
ToArray.toArrayPresized 1 44,852 ± 0,813 ns/op
ToArray.toArrayPresized 10 66,904 ± 0,748 ns/op
ToArray.toArrayPresized 1000 7839,880 ± 75,954 ns/op
ToArray.toArrayPresized 100000 1605381,429 ± 55070,143 ns/op
ToArray.toArrayPresized 10000000 292954965,933 ± 45912224,761 ns/op
ToArray.toObjectArray 0 6,608 ± 0,049 ns/op
ToArray.toObjectArray 1 28,085 ± 0,326 ns/op
ToArray.toObjectArray 10 58,170 ± 2,716 ns/op
ToArray.toObjectArray 1000 5979,407 ± 55,930 ns/op
ToArray.toObjectArray 100000 1420318,139 ± 27226,724 ns/op
ToArray.toObjectArray 10000000 255417541,372 ± 33366555,142 ns/op
As you can see, the patched version is always faster, sometimes 2x and
even more. Also it doesn't allocate anything except the target array
when necessary (current version allocates an iterator).
If anybody is interested to sponsor this change, I can log a JBS issue
and provide proper webrev for review. Do we need to add new unit-tests
or these methods are covered enough by existing tests?
With best regards,
Tagir Valeev.
More information about the core-libs-dev
mailing list