Optimized HashSet.toArray()
Martin Buchholz
martinrb at google.com
Mon Oct 1 17:35:32 UTC 2018
Thanks, Tagir.
I agree these optimizations are worth doing. I have worked on similar
toArray methods in other Collection implementations.
I have a benchmark that is also a correctness test
Collection/IteratorMicroBenchmark.java
but I never added any Set implementations since I intentionally want to
test duplicates and we'd have to special-case Sets somehow.
We probably want to check in the jmh benchmark, but not sure where - there
have been recent discussions ... """Reviving JEP 230: Microbenchmark
Suite"""
On Sun, Sep 30, 2018 at 10:03 PM, Tagir Valeev <amaembo at gmail.com> wrote:
> 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