RFR: updated draft API for JEP 269 Convenience Collection Factories
Vitaly Davidovich
vitalyd at gmail.com
Mon Nov 9 15:26:42 UTC 2015
There's another issue with relying on EA, which is EA will not analyze
methods above a certain (bytecode) size; IIRC it's around 150. So if this
method gets inlined into a bulky method, the varargs will not be
eliminated, I believe. I don't think it's a problem for this API for the
reasons I mentioned earlier in this thread, but worth considering if EA is
being relied upon.
sent from my phone
On Nov 8, 2015 2:30 PM, "Peter Levart" <peter.levart at gmail.com> wrote:
> Hi Michael,
>
> You see, switch2 is on par with explicit for 0 and 1 args.
>
> switch10 probably suffers from to-many-bytecodes-per-method syndrome.
>
> I tried to shorten your switch2 and switch10 methods by delegating to
> explicit/varargs methods:
>
> @SafeVarargs
> static <E> List<E> varargs_switch2(E... ea) {
> switch (ea.length) {
> case 0: return explicit();
> case 1: return explicit(ea[0]);
> default: return varargs(ea);
> }
> }
>
> @SafeVarargs
> static <E> List<E> varargs_switch10(E... ea) {
> switch (ea.length) {
> case 0: return explicit();
> case 1: return explicit(ea[0]);
> case 2: return explicit(ea[0], ea[1]);
> case 3: return explicit(ea[0], ea[1], ea[2]);
> case 4: return explicit(ea[0], ea[1], ea[2], ea[3]);
> case 5: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4]);
> case 6: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
> case 7: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
> ea[6]);
> case 8: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
> ea[6], ea[7]);
> case 9: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
> ea[6], ea[7], ea[8]);
> case 10: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
> ea[6], ea[7], ea[8], ea[9]);
> default: return varargs(ea);
> }
> }
>
>
> ... and the results are as follows (JDK8u60, i7-2600K, Linux):
>
>
> ListOf.explicit_00 avgt 10
> 2.600 ± 0.022 ns/op
> ListOf.explicit_01 avgt 10
> 4.032 ± 0.237 ns/op
> ListOf.explicit_02 avgt 10
> 7.255 ± 0.457 ns/op
> ListOf.explicit_03 avgt 10
> 7.684 ± 0.485 ns/op
> ListOf.explicit_04 avgt 10
> 8.401 ± 0.803 ns/op
> ListOf.explicit_05 avgt 10
> 9.001 ± 0.771 ns/op
> ListOf.explicit_06 avgt 10
> 9.467 ± 1.008 ns/op
> ListOf.explicit_07 avgt 10
> 10.506 ± 0.774 ns/op
> ListOf.explicit_08 avgt 10
> 11.218 ± 0.946 ns/op
> ListOf.explicit_09 avgt 10
> 12.466 ± 0.735 ns/op
> ListOf.explicit_10 avgt 10
> 13.160 ± 1.680 ns/op
>
> ListOf.varargs_00 avgt 10
> 6.701 ± 0.986 ns/op
> ListOf.varargs_01 avgt 10
> 7.244 ± 0.775 ns/op
> ListOf.varargs_02 avgt 10
> 9.751 ± 0.931 ns/op
> ListOf.varargs_03 avgt 10
> 10.730 ± 1.055 ns/op
> ListOf.varargs_04 avgt 10
> 11.615 ± 0.995 ns/op
> ListOf.varargs_05 avgt 10
> 12.923 ± 1.057 ns/op
> ListOf.varargs_06 avgt 10
> 12.688 ± 0.963 ns/op
> ListOf.varargs_07 avgt 10
> 14.509 ± 0.964 ns/op
> ListOf.varargs_08 avgt 10
> 15.214 ± 1.613 ns/op
> ListOf.varargs_09 avgt 10
> 15.796 ± 0.099 ns/op
> ListOf.varargs_10 avgt 10
> 17.381 ± 2.089 ns/op
>
> ListOf.varargs_switch10_00 avgt 10
> 2.598 ± 0.031 ns/op
> ListOf.varargs_switch10_01 avgt 10
> 4.200 ± 0.377 ns/op
> ListOf.varargs_switch10_02 avgt 10
> 6.829 ± 0.445 ns/op
> ListOf.varargs_switch10_03 avgt 10
> 8.074 ± 1.230 ns/op
> ListOf.varargs_switch10_04 avgt 10
> 8.254 ± 0.644 ns/op
> ListOf.varargs_switch10_05 avgt 10
> 9.955 ± 1.643 ns/op
> ListOf.varargs_switch10_06 avgt 10
> 9.856 ± 1.172 ns/op
> ListOf.varargs_switch10_07 avgt 10
> 11.230 ± 1.182 ns/op
> ListOf.varargs_switch10_08 avgt 10
> 17.431 ± 2.253 ns/op
> ListOf.varargs_switch10_09 avgt 10
> 18.439 ± 2.199 ns/op
> ListOf.varargs_switch10_10 avgt 10
> 20.477 ± 2.698 ns/op
>
> ListOf.varargs_switch2_00 avgt 10
> 2.598 ± 0.031 ns/op
> ListOf.varargs_switch2_01 avgt 10
> 4.306 ± 0.461 ns/op
> ListOf.varargs_switch2_02 avgt 10
> 9.561 ± 0.978 ns/op
> ListOf.varargs_switch2_03 avgt 10
> 10.859 ± 0.596 ns/op
> ListOf.varargs_switch2_04 avgt 10
> 11.810 ± 0.812 ns/op
> ListOf.varargs_switch2_05 avgt 10
> 13.451 ± 1.819 ns/op
> ListOf.varargs_switch2_06 avgt 10
> 12.310 ± 0.106 ns/op
> ListOf.varargs_switch2_07 avgt 10
> 15.589 ± 2.335 ns/op
> ListOf.varargs_switch2_08 avgt 10
> 15.177 ± 0.963 ns/op
> ListOf.varargs_switch2_09 avgt 10
> 18.139 ± 1.968 ns/op
> ListOf.varargs_switch2_10 avgt 10
> 16.802 ± 1.193 ns/op
>
>
> Now switch10 performs on par with explicit up to 7 arguments after which
> there's a cliff.
>
> switch2 has a cliff where expected, when it starts to delegate to varargs.
>
> More interesting, when profiling with "-prof gc", we can see that:
>
>
> ListOf.explicit_00:·gc.alloc.rate.norm avgt 10 ≈
> 10⁻⁶ B/op
> ListOf.explicit_01:·gc.alloc.rate.norm avgt 10
> 24.000 ± 0.001 B/op
> ListOf.explicit_02:·gc.alloc.rate.norm avgt 10
> 48.000 ± 0.001 B/op
> ListOf.explicit_03:·gc.alloc.rate.norm avgt 10
> 56.000 ± 0.001 B/op
> ListOf.explicit_04:·gc.alloc.rate.norm avgt 10
> 56.000 ± 0.001 B/op
> ListOf.explicit_05:·gc.alloc.rate.norm avgt 10
> 64.000 ± 0.001 B/op
> ListOf.explicit_06:·gc.alloc.rate.norm avgt 10
> 64.000 ± 0.001 B/op
> ListOf.explicit_07:·gc.alloc.rate.norm avgt 10
> 72.000 ± 0.001 B/op
> ListOf.explicit_08:·gc.alloc.rate.norm avgt 10
> 72.000 ± 0.001 B/op
> ListOf.explicit_09:·gc.alloc.rate.norm avgt 10
> 80.000 ± 0.001 B/op
> ListOf.explicit_10:·gc.alloc.rate.norm avgt 10
> 80.000 ± 0.001 B/op
>
> ListOf.varargs_00:·gc.alloc.rate.norm avgt 10
> 40.000 ± 0.001 B/op
> ListOf.varargs_01:·gc.alloc.rate.norm avgt 10
> 48.000 ± 0.001 B/op
> ListOf.varargs_02:·gc.alloc.rate.norm avgt 10
> 72.000 ± 0.001 B/op
> ListOf.varargs_03:·gc.alloc.rate.norm avgt 10
> 88.000 ± 0.001 B/op
> ListOf.varargs_04:·gc.alloc.rate.norm avgt 10
> 88.000 ± 0.001 B/op
> ListOf.varargs_05:·gc.alloc.rate.norm avgt 10
> 104.000 ± 0.001 B/op
> ListOf.varargs_06:·gc.alloc.rate.norm avgt 10
> 104.000 ± 0.001 B/op
> ListOf.varargs_07:·gc.alloc.rate.norm avgt 10
> 120.000 ± 0.001 B/op
> ListOf.varargs_08:·gc.alloc.rate.norm avgt 10
> 120.000 ± 0.001 B/op
> ListOf.varargs_09:·gc.alloc.rate.norm avgt 10
> 136.000 ± 0.001 B/op
> ListOf.varargs_10:·gc.alloc.rate.norm avgt 10
> 136.000 ± 0.001 B/op
>
> ListOf.varargs_switch10_00:·gc.alloc.rate.norm avgt 10 ≈
> 10⁻⁶ B/op
> ListOf.varargs_switch10_01:·gc.alloc.rate.norm avgt 10
> 24.000 ± 0.001 B/op
> ListOf.varargs_switch10_02:·gc.alloc.rate.norm avgt 10
> 48.000 ± 0.001 B/op
> ListOf.varargs_switch10_03:·gc.alloc.rate.norm avgt 10
> 56.000 ± 0.001 B/op
> ListOf.varargs_switch10_04:·gc.alloc.rate.norm avgt 10
> 56.000 ± 0.001 B/op
> ListOf.varargs_switch10_05:·gc.alloc.rate.norm avgt 10
> 64.000 ± 0.001 B/op
> ListOf.varargs_switch10_06:·gc.alloc.rate.norm avgt 10
> 64.000 ± 0.001 B/op
> ListOf.varargs_switch10_07:·gc.alloc.rate.norm avgt 10
> 72.000 ± 0.001 B/op
> ListOf.varargs_switch10_08:·gc.alloc.rate.norm avgt 10
> 120.000 ± 0.001 B/op
> ListOf.varargs_switch10_09:·gc.alloc.rate.norm avgt 10
> 136.000 ± 0.001 B/op
> ListOf.varargs_switch10_10:·gc.alloc.rate.norm avgt 10
> 136.000 ± 0.001 B/op
>
> ListOf.varargs_switch2_00:·gc.alloc.rate.norm avgt 10 ≈
> 10⁻⁶ B/op
> ListOf.varargs_switch2_01:·gc.alloc.rate.norm avgt 10
> 24.000 ± 0.001 B/op
> ListOf.varargs_switch2_02:·gc.alloc.rate.norm avgt 10
> 72.000 ± 0.001 B/op
> ListOf.varargs_switch2_03:·gc.alloc.rate.norm avgt 10
> 88.000 ± 0.001 B/op
> ListOf.varargs_switch2_04:·gc.alloc.rate.norm avgt 10
> 88.000 ± 0.001 B/op
> ListOf.varargs_switch2_05:·gc.alloc.rate.norm avgt 10
> 104.000 ± 0.001 B/op
> ListOf.varargs_switch2_06:·gc.alloc.rate.norm avgt 10
> 104.000 ± 0.001 B/op
> ListOf.varargs_switch2_07:·gc.alloc.rate.norm avgt 10
> 120.000 ± 0.001 B/op
> ListOf.varargs_switch2_08:·gc.alloc.rate.norm avgt 10
> 120.000 ± 0.001 B/op
> ListOf.varargs_switch2_09:·gc.alloc.rate.norm avgt 10
> 136.000 ± 0.001 B/op
> ListOf.varargs_switch2_10:·gc.alloc.rate.norm avgt 10
> 136.000 ± 0.001 B/op
>
>
> switch10 allocates exactly the same as explicit up to 7 arguments, after
> that it seems that JIT doesn't want to optimize away the allocation of the
> vararg array.
>
>
> So it looks like that there's no need to burden the public API with
> explicit argument overloads.
>
> Regards, Peter
>
>
> On 11/08/2015 12:44 AM, Michael Hixson wrote:
>
>> Hi Peter,
>>
>> I've attached the source code and JMH output with two new tests:
>>
>> 1. varargs_switch2: Has a switch with cases for 0 and 1 that invoke
>> Collections.emptyList/singletonList.
>> 2. varargs_switch10: Has a switch with ten cases that look exactly
>> like the explicit versions.
>>
>> Both have a default case that falls back to System.arraycopy.
>>
>> switch2 seems like a more sane implementation and it performs better
>> for 0 or 1 arguments. For larger numbers of arguments, they're
>> roughly equivalent.
>>
>> Here is the end snippet from the attached results:
>>
>>
>> Benchmark Mode Cnt Score Error Units
>> ListOf.explicit_00 avgt 40 2.550 ± 0.008 ns/op
>> ListOf.explicit_01 avgt 40 6.929 ± 0.100 ns/op
>> ListOf.explicit_02 avgt 40 15.011 ± 1.410 ns/op
>> ListOf.explicit_03 avgt 40 16.203 ± 0.396 ns/op
>> ListOf.explicit_04 avgt 40 16.397 ± 0.505 ns/op
>> ListOf.explicit_05 avgt 40 18.252 ± 0.229 ns/op
>> ListOf.explicit_06 avgt 40 18.623 ± 0.499 ns/op
>> ListOf.explicit_07 avgt 40 20.614 ± 0.231 ns/op
>> ListOf.explicit_08 avgt 40 20.792 ± 0.259 ns/op
>> ListOf.explicit_09 avgt 40 22.998 ± 0.350 ns/op
>> ListOf.explicit_10 avgt 40 23.105 ± 0.346 ns/op
>> ListOf.varargs_00 avgt 40 11.363 ± 0.131 ns/op
>> ListOf.varargs_01 avgt 40 20.877 ± 0.440 ns/op
>> ListOf.varargs_02 avgt 40 20.004 ± 0.130 ns/op
>> ListOf.varargs_03 avgt 40 24.264 ± 0.091 ns/op
>> ListOf.varargs_04 avgt 40 24.309 ± 0.120 ns/op
>> ListOf.varargs_05 avgt 40 28.936 ± 0.503 ns/op
>> ListOf.varargs_06 avgt 40 28.676 ± 0.052 ns/op
>> ListOf.varargs_07 avgt 40 33.858 ± 1.409 ns/op
>> ListOf.varargs_08 avgt 40 33.685 ± 0.763 ns/op
>> ListOf.varargs_09 avgt 40 37.639 ± 0.207 ns/op
>> ListOf.varargs_10 avgt 40 39.188 ± 1.577 ns/op
>> ListOf.varargs_switch10_00 avgt 40 5.575 ± 0.140 ns/op
>> ListOf.varargs_switch10_01 avgt 40 13.561 ± 0.353 ns/op
>> ListOf.varargs_switch10_02 avgt 40 20.145 ± 0.328 ns/op
>> ListOf.varargs_switch10_03 avgt 40 24.632 ± 0.121 ns/op
>> ListOf.varargs_switch10_04 avgt 40 25.360 ± 0.941 ns/op
>> ListOf.varargs_switch10_05 avgt 40 28.977 ± 0.336 ns/op
>> ListOf.varargs_switch10_06 avgt 40 30.471 ± 1.797 ns/op
>> ListOf.varargs_switch10_07 avgt 40 33.701 ± 0.128 ns/op
>> ListOf.varargs_switch10_08 avgt 40 33.737 ± 0.357 ns/op
>> ListOf.varargs_switch10_09 avgt 40 38.638 ± 1.564 ns/op
>> ListOf.varargs_switch10_10 avgt 40 38.042 ± 0.090 ns/op
>> ListOf.varargs_switch2_00 avgt 40 2.543 ± 0.006 ns/op
>> ListOf.varargs_switch2_01 avgt 40 7.069 ± 0.366 ns/op
>> ListOf.varargs_switch2_02 avgt 40 20.564 ± 0.739 ns/op
>> ListOf.varargs_switch2_03 avgt 40 24.453 ± 0.362 ns/op
>> ListOf.varargs_switch2_04 avgt 40 24.706 ± 0.587 ns/op
>> ListOf.varargs_switch2_05 avgt 40 29.451 ± 0.917 ns/op
>> ListOf.varargs_switch2_06 avgt 40 28.856 ± 0.126 ns/op
>> ListOf.varargs_switch2_07 avgt 40 33.300 ± 0.066 ns/op
>> ListOf.varargs_switch2_08 avgt 40 36.306 ± 3.242 ns/op
>> ListOf.varargs_switch2_09 avgt 40 40.739 ± 1.837 ns/op
>> ListOf.varargs_switch2_10 avgt 40 37.876 ± 0.114 ns/op
>>
>>
>> -Michael
>>
>> On Sat, Nov 7, 2015 at 7:41 AM, Peter Levart <peter.levart at gmail.com>
>> wrote:
>>
>>> Hi Michael,
>>>
>>> The comparison between explicit and varargs is not fair. Varargs is using
>>> arraycopy, which I think prevents vararg array allocation to be
>>> eliminated.
>>> Try to use a switch on varargs array length and then directly reference
>>> it's
>>> elements with constant indices for each case and construct list arrays as
>>> you do in explicit methods. Let's see if this performs any better.
>>>
>>> Regards, Peter
>>>
>>> On Nov 7, 2015 9:43 AM, "Michael Hixson" <michael.hixson at gmail.com>
>>> wrote:
>>>
>>>> (Oops, forgot to cc the mailing list)
>>>>
>>>> Thanks for the explanations, Stuart. That all sounds reasonable and
>>>> makes sense to me.
>>>>
>>>> I have some additional thoughts inline below, because this is
>>>> interesting and I can't resist, but you could ignore them and not hurt
>>>> any feelings.
>>>>
>>>> I also wrote up some quick benchmarks comparing explicit versus
>>>> varargs implementations just to see the impact for myself. The output
>>>> and source code are included at the end of the email.
>>>>
>>>> -Michael
>>>>
>>>>
>>>> On Fri, Nov 6, 2015 at 10:28 AM, Stuart Marks <stuart.marks at oracle.com>
>>>> wrote:
>>>>
>>>>> On 11/6/15 5:12 AM, Michael Hixson wrote:
>>>>>
>>>>>> + static <E> List<E> of(E... es) {
>>>>>> + for (E e : es) {
>>>>>> + Objects.requireNonNull(e);
>>>>>> + }
>>>>>> + // NOTE: this can allow a null element to slip through
>>>>>> + return Collections.unmodifiableList(Arrays.asList(es));
>>>>>> + }
>>>>>>
>>>>>> Even as a skeletal implementation, this one has to be changed to be
>>>>>> truly immutable, right? It currently returns a view of the (mutable)
>>>>>> argument array rather than new storage. Sorry for not providing a
>>>>>> proper test:
>>>>>>
>>>>> Good catch! Funnily I had noticed the TOCTOU case that allowed null
>>>>> elements
>>>>> in the array to slip through, but not that the array itself was still
>>>>> modifiable from the outside. Anyway, I'll fix this. No worries about
>>>>> the
>>>>> test.
>>>>>
>>>>> Has anyone been able to quantify the advantage of having these
>>>>>> overloads as opposed to having the varargs versions only? Is it a
>>>>>> matter of performance?
>>>>>>
>>>>>> I ask because the overloads seem like warts on the APIs (which is a
>>>>>> shame -- List and Set are such important APIs). I'm imagining a
>>>>>> future where:
>>>>>>
>>>>>> 1. We add these overloads for performance gains now.
>>>>>> 2. But they're all skeletal implementations that aren't that perfomant
>>>>>> anyway. Efficient versions don't make it into Java SE 9. People that
>>>>>> care a lot about performance avoid using these ones.
>>>>>> 3. A few years later, varargs performance or some other language / VM
>>>>>> / compiler-level change renders the overloads obsolete.
>>>>>>
>>>>> Yeah, the overloads seem like warts on the API, though probably
>>>>> necessary
>>>>> ones.
>>>>>
>>>>> At present, and for the forseeable future, varargs calls allocate an
>>>>> array
>>>>> on the heap, whereas fixed-args calls do not. I don't know how to
>>>>> quantify
>>>>> the difference though. Certainly the cost of allocation and
>>>>> initialization
>>>>> is borne in-line. Then there is the cost of collection. Collecting
>>>>> short-lived objects is cheap (but not free). There is also the
>>>>> possibility
>>>>> of escape analysis eliminating the allocation. This seems unlikely to
>>>>> me;
>>>>> certainly not something to be relied upon.
>>>>>
>>>>> The most likely possible future optimization is "frozen arrays," part
>>>>> of
>>>>> the
>>>>> "Arrays 2.0" stuff that John Rose has talked about. This is basically
>>>>> about
>>>>> immutable arrays. Here, the possibility is to eliminate the defensive
>>>>> copy,
>>>>> if the array created to hold the varargs arguments is made immutable.
>>>>> (This
>>>>> will require some adjustment on the callee side, as yet unspecified.)
>>>>> There's still an array, though. And a defensive copy would still have
>>>>> to
>>>>> be
>>>>> made if the caller passes an actual array, as opposed to a varargs
>>>>> list.
>>>>>
>>>> (Realizing that we're discussing details of a feature that doesn't
>>>> exist (frozen arrays)...)
>>>>
>>>> It seems to me that as long as the callee invoked the method with
>>>> comma-separated arguments instead of an array, then the callee can
>>>> automatically be opted into frozen arrays. They never had access to
>>>> the array box in the first place.
>>>>
>>>> It also seems like the varargs method could defensively call
>>>> array.clone() and expect a no-op (return this) implementation if the
>>>> array was already frozen, and so both sides could automatically
>>>> benefit from frozen arrays without recompilation. No?
>>>>
>>>> While I can't quantify it, I do think there's an expense to creating the
>>>>> varargs array, and there is only a possibility to reduce (but not
>>>>> eliminate)
>>>>> its cost in future JDK releases. This cost is entirely avoided by
>>>>> fixed-args
>>>>> overloads. (There is the cost of cluttering up the API, though.)
>>>>>
>>>> I asked "Is it a matter of performance?" because I thought the
>>>> justification for similar overloads in other APIs was different. I
>>>> thought EnumSet and Guava (for example) provided the overloads because
>>>> @SafeVarargs did not exist at the time, and they didn't want to scare
>>>> callers away with those silly warnings.
>>>>
>>>> Put another way: if the justification for these new overloads is
>>>> simply "the other APIs did it", I hope those original motivations are
>>>> not being wrongly applied here. It sounds like this is strictly about
>>>> performance, though.
>>>>
>>>> Turning to the skeletal vs. optimized implementation, my plan is
>>>>> certainly
>>>>> to ensure that the optimized implementations get into JDK 9. Of course,
>>>>> plans can change. If the APIs get in without the optimized
>>>>> implementations,
>>>>> I think the big attractor will still be the convenience of using these
>>>>> static factory methods as opposed to conventional code. They're no
>>>>> slower
>>>>> than conventional code, and the space consumed is the same. So I think
>>>>> they'll be popular even if the space efficiency benefits aren't there
>>>>> initially.
>>>>>
>>>> For some reason I thought the optimized implementations had already
>>>> been moved out of scope for Java 9. I'm glad I was wrong!
>>>>
>>>> When the optimized implementations do get in, callers will benefit, even
>>>>> without recompilation. Thus there is some present value added based on
>>>>> potential future benefits.
>>>>>
>>>>> There is always the set of possible future events that cause something
>>>>> not
>>>>> to work out, but I think pursuing the approach I've outlined has a good
>>>>> chance of benefiting the platform in the long term.
>>>>>
>>>>> s'marks
>>>>>
>>>> ----------------------------------------
>>>>
>>>> Benchmark Mode Cnt Score Error Units
>>>> ListOf.explicit_00 avgt 40 2.564 ± 0.007 ns/op
>>>> ListOf.explicit_01 avgt 40 7.859 ± 0.022 ns/op
>>>> ListOf.explicit_02 avgt 40 15.808 ± 0.338 ns/op
>>>> ListOf.explicit_03 avgt 40 19.145 ± 0.978 ns/op
>>>> ListOf.explicit_04 avgt 40 18.558 ± 0.314 ns/op
>>>> ListOf.explicit_05 avgt 40 23.457 ± 1.069 ns/op
>>>> ListOf.explicit_06 avgt 40 21.398 ± 0.255 ns/op
>>>> ListOf.explicit_07 avgt 40 25.307 ± 0.672 ns/op
>>>> ListOf.explicit_08 avgt 40 24.137 ± 0.376 ns/op
>>>> ListOf.explicit_09 avgt 40 27.418 ± 0.560 ns/op
>>>> ListOf.explicit_10 avgt 40 26.871 ± 0.506 ns/op
>>>> ListOf.varargs_00 avgt 40 13.520 ± 0.177 ns/op
>>>> ListOf.varargs_01 avgt 40 23.740 ± 0.346 ns/op
>>>> ListOf.varargs_02 avgt 40 23.435 ± 0.321 ns/op
>>>> ListOf.varargs_03 avgt 40 29.564 ± 0.744 ns/op
>>>> ListOf.varargs_04 avgt 40 29.640 ± 1.329 ns/op
>>>> ListOf.varargs_05 avgt 40 34.552 ± 0.639 ns/op
>>>> ListOf.varargs_06 avgt 40 34.249 ± 0.476 ns/op
>>>> ListOf.varargs_07 avgt 40 40.656 ± 0.589 ns/op
>>>> ListOf.varargs_08 avgt 40 39.900 ± 0.595 ns/op
>>>> ListOf.varargs_09 avgt 40 45.060 ± 1.098 ns/op
>>>> ListOf.varargs_10 avgt 40 44.546 ± 0.816 ns/op
>>>>
>>>> ----------------------------------------
>>>>
>>>> package rnd;
>>>>
>>>> import org.openjdk.jmh.annotations.Benchmark;
>>>> import org.openjdk.jmh.annotations.BenchmarkMode;
>>>> import org.openjdk.jmh.annotations.Fork;
>>>> import org.openjdk.jmh.annotations.Measurement;
>>>> import org.openjdk.jmh.annotations.Mode;
>>>> import org.openjdk.jmh.annotations.OutputTimeUnit;
>>>> import org.openjdk.jmh.annotations.Scope;
>>>> import org.openjdk.jmh.annotations.State;
>>>> import org.openjdk.jmh.annotations.Warmup;
>>>> import org.openjdk.jmh.runner.Runner;
>>>> import org.openjdk.jmh.runner.options.Options;
>>>> import org.openjdk.jmh.runner.options.OptionsBuilder;
>>>>
>>>> import java.util.AbstractList;
>>>> import java.util.Collections;
>>>> import java.util.List;
>>>> import java.util.Objects;
>>>> import java.util.concurrent.TimeUnit;
>>>>
>>>> @State(Scope.Thread)
>>>> @BenchmarkMode(Mode.AverageTime)
>>>> @OutputTimeUnit(TimeUnit.NANOSECONDS)
>>>> @Warmup(iterations = 20)
>>>> @Measurement(iterations = 20)
>>>> @Fork(2)
>>>> public class ListOf {
>>>>
>>>> private static final String o = "";
>>>>
>>>> public static void main(String[] args) throws Exception {
>>>> Options options = new OptionsBuilder()
>>>> .include(ListOf.class.getName())
>>>> .build();
>>>> new Runner(options).run();
>>>> }
>>>>
>>>> @Benchmark public List<String> explicit_00() { return explicit(); }
>>>> @Benchmark public List<String> explicit_01() { return explicit(o); }
>>>> @Benchmark public List<String> explicit_02() { return explicit(o,o);
>>>> }
>>>> @Benchmark public List<String> explicit_03() { return
>>>> explicit(o,o,o); }
>>>> @Benchmark public List<String> explicit_04() { return
>>>> explicit(o,o,o,o);
>>>> }
>>>> @Benchmark public List<String> explicit_05() { return
>>>> explicit(o,o,o,o,o); }
>>>> @Benchmark public List<String> explicit_06() { return
>>>> explicit(o,o,o,o,o,o); }
>>>> @Benchmark public List<String> explicit_07() { return
>>>> explicit(o,o,o,o,o,o,o); }
>>>> @Benchmark public List<String> explicit_08() { return
>>>> explicit(o,o,o,o,o,o,o,o); }
>>>> @Benchmark public List<String> explicit_09() { return
>>>> explicit(o,o,o,o,o,o,o,o,o); }
>>>> @Benchmark public List<String> explicit_10() { return
>>>> explicit(o,o,o,o,o,o,o,o,o,o); }
>>>>
>>>> @Benchmark public List<String> varargs_00() { return varargs(); }
>>>> @Benchmark public List<String> varargs_01() { return varargs(o); }
>>>> @Benchmark public List<String> varargs_02() { return varargs(o,o); }
>>>> @Benchmark public List<String> varargs_03() { return varargs(o,o,o);
>>>> }
>>>> @Benchmark public List<String> varargs_04() { return
>>>> varargs(o,o,o,o); }
>>>> @Benchmark public List<String> varargs_05() { return
>>>> varargs(o,o,o,o,o);
>>>> }
>>>> @Benchmark public List<String> varargs_06() { return
>>>> varargs(o,o,o,o,o,o); }
>>>> @Benchmark public List<String> varargs_07() { return
>>>> varargs(o,o,o,o,o,o,o); }
>>>> @Benchmark public List<String> varargs_08() { return
>>>> varargs(o,o,o,o,o,o,o,o); }
>>>> @Benchmark public List<String> varargs_09() { return
>>>> varargs(o,o,o,o,o,o,o,o,o); }
>>>> @Benchmark public List<String> varargs_10() { return
>>>> varargs(o,o,o,o,o,o,o,o,o,o); }
>>>>
>>>> static <E> List<E> explicit() {
>>>> return Collections.emptyList();
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1) {
>>>> return Collections.singletonList(Objects.requireNonNull(e1));
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3, E e4) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3),
>>>> Objects.requireNonNull(e4)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3),
>>>> Objects.requireNonNull(e4),
>>>> Objects.requireNonNull(e5)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3),
>>>> Objects.requireNonNull(e4),
>>>> Objects.requireNonNull(e5),
>>>> Objects.requireNonNull(e6)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E
>>>> e7) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3),
>>>> Objects.requireNonNull(e4),
>>>> Objects.requireNonNull(e5),
>>>> Objects.requireNonNull(e6),
>>>> Objects.requireNonNull(e7)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E
>>>> e7, E
>>>> e8) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3),
>>>> Objects.requireNonNull(e4),
>>>> Objects.requireNonNull(e5),
>>>> Objects.requireNonNull(e6),
>>>> Objects.requireNonNull(e7),
>>>> Objects.requireNonNull(e8)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E
>>>> e7, E e8, E e9) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3),
>>>> Objects.requireNonNull(e4),
>>>> Objects.requireNonNull(e5),
>>>> Objects.requireNonNull(e6),
>>>> Objects.requireNonNull(e7),
>>>> Objects.requireNonNull(e8),
>>>> Objects.requireNonNull(e9)
>>>> });
>>>> }
>>>>
>>>> static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E
>>>> e7, E e8, E e9, E e10) {
>>>> return new ImmutableList<>(new Object[] {
>>>> Objects.requireNonNull(e1),
>>>> Objects.requireNonNull(e2),
>>>> Objects.requireNonNull(e3),
>>>> Objects.requireNonNull(e4),
>>>> Objects.requireNonNull(e5),
>>>> Objects.requireNonNull(e6),
>>>> Objects.requireNonNull(e7),
>>>> Objects.requireNonNull(e8),
>>>> Objects.requireNonNull(e9),
>>>> Objects.requireNonNull(e10)
>>>> });
>>>> }
>>>>
>>>> @SafeVarargs
>>>> static <E> List<E> varargs(E... elements) {
>>>> int length = elements.length;
>>>> Object[] copy = new Object[length];
>>>> System.arraycopy(elements, 0, copy, 0, length);
>>>> for (Object e : copy) Objects.requireNonNull(e);
>>>> return new ImmutableList<>(copy);
>>>> }
>>>>
>>>> static final class ImmutableList<E> extends AbstractList<E> {
>>>> final Object[] array;
>>>>
>>>> ImmutableList(Object[] array) {
>>>> this.array = array;
>>>> }
>>>>
>>>> @Override
>>>> @SuppressWarnings("unchecked")
>>>> public E get(int index) {
>>>> return (E) array[index];
>>>> }
>>>>
>>>> @Override
>>>> public int size() {
>>>> return array.length;
>>>> }
>>>> }
>>>> }
>>>>
>>>
>
More information about the core-libs-dev
mailing list