RFR: 8223504: improve performance of forall loops by better inlining of "iterator()" methods.
Vladimir Ivanov
vladimir.x.ivanov at oracle.com
Wed May 22 17:47:01 UTC 2019
Thanks for the thorough explanation, Sergey.
What I like about the patch you propose is its simplicity.
More accurate heuristic which takes inlining effects into account (e.g.,
on EA) would scale to a much wider range of use cases and C2 has a rich
toolkit to make such heuristic possible, but it would definitely require
more effort.
Thinking about it for a while, I agree with your proposal: the heuristic
is acceptable for the case of iterators, the benefits are evident, and
risks (with overinlining and premature inlining) are low.
I still hope there'll be a more generic solution available at some point
which will supersede such special case for Iterable.
Regarding the check itself, I'm in favor of limiting it
toIterable::iterator() overrides/overloads, but I'm OK with a more
generic check on return type.
Best regards,
Vladimir Ivanov
On 10/05/2019 21:47, Sergey Kuksenko wrote:
> Let me do a broader description.
>
> When hotspot makes a decision to the "ultimate question compilation,
> optimization and everything" inline or not inline there are two key
> part of that decision. It is check of sizes (callee and caller) and
> check of frequencies (invocation count). Frequency check is reasonable,
> why should we inline rarely invoked method? But sometimes we loose
> optimization opportunities with that.
>
> Let's narrow the scenario. We have a loop and a method invocation before
> the loop. Inline of the method is a vital for the loop performance. I
> see at least two key optimizations here: constant propagation and scalar
> replacement, maybe more. But if the loop has large enough amount of
> iterations -> hotspot has large enough backedge counters -> but it means
> that prolog is considered as relatively cold code (small amount of
> invocation counter) -> that method (potentially vital for performance)
> is not inlined (due to frequency/MinInlineThreashold cut off).
>
> We can't say if inlining is important until we look into the loop (even
> if there is a loop there). But we have to make a decision about inline
> before that. So let's try to make reasonable heuristic and narrow the
> scenario again. Limit our sight to Iterators. There is a very high
> probability that after Iterable::iterator() invocation there is a loop
> (covers all for-all loop). Also there is a high correlation between
> collection size and amount of loop iterations. Let's inline all
> iterators. I don't think the idea to analyze if "returned Iterator is a
> freshly-allocated instance" makes sense. First of all it's unnecessary
> complication. Moreover, I have results when we have chain of iterators,
> hotspot can't inline the whole chain due to absence of profile (and/or
> profile pollution), but partial inline of the chain have shown
> performance benefits. To get more effective prediction if that
> particular inline is important we should look not into the method, but
> to the usage of the method results (into the loop).
>
> About the first comment (to broad or to narrow check). I have to note
> that this fix doesn't force inline for all methods with "iterator" name.
> The fix only excludes frequency cut off. All other checks (by sizes) are
> still in place. I did broader check for two reasons: to simplify
> modifications and to have wider appliances when it works. I could narrow
> it if you insist, but at the same time I think we have to make that
> check broader - don't look into method name at all. If you have
> something that returns Iterator - there will be loop after that with a
> very high probability. So I'd vote for making that wider - check only
> return type.
>
> On 5/8/19 3:10 PM, Vladimir Ivanov wrote:
>>> http://cr.openjdk.java.net/~skuksenko/hotspot/8223504/webrev.01/
>> returned Iterator is a freshly-allocated instance
>> src/hotspot/share/opto/bytecodeInfo.cpp:
>>
>> + if (callee_method->name() == ciSymbol::iterator_name()) {
>> + if
>> (callee_method->signature()->return_type()->is_subtype_of(C->env()->Iterator_klass()))
>> {
>> + return true;
>> + }
>> + }
>>
>> The check looks too broad for me: it returns true for any method with
>> a name "iterator" which returns an instance of Iterator which is much
>> broader that just overrides/overloads of Iterable::iterator().
>>
>> Can you elaborate, please, why did you decide to extend the check for
>> non-Iterables?
>>
>> Commenting on the general approach, it looks like a good candidate for
>> a fist-line filter before performing a more extensive analysis. I'd
>> prefer to see BCEscapeAnalyzer extended to determine that returned
>> Iterator is a freshly-allocated instance and decide whether to inline
>> or not based on that instead. Among java.util classes you mentioned
>> most iterators are trivial, so even naive analysis should get decent
>> results.
>>
>> And then the analysis can be applied to any method which returns an
>> Object to see whether EA may benefit from inlining.
>>
>> What do you think?
>>
>> Best regards,
>> Vladimir Ivanov
>>
>>> On 5/7/19 11:56 AM, Aleksey Shipilev wrote:
>>>> On 5/7/19 8:39 PM, Sergey Kuksenko wrote:
>>>>> Hi All,
>>>>>
>>>>> I would like to ask for review the following change/update:
>>>>>
>>>>> https://bugs.openjdk.java.net/browse/JDK-8223504
>>>>>
>>>>> http://cr.openjdk.java.net/~skuksenko/hotspot/8223504/webrev.00/
>>>> The idea sounds fine.
>>>>
>>>> Nits (the usual drill):
>>>>
>>>> *) Copyright years need to be updated, at least in bytecodeInfo.cpp
>>>>
>>>> *) Do we need to put Iterator_klass initialization this early in
>>>> WK_KLASSES_DO? It feels safer to
>>>> initialize it at the end, to avoid surprising bootstrap issues.
>>>>
>>>> *) Backslash indent is off here in vmSymbols.hpp:
>>>>
>>>> 129 template(java_util_Iterator,
>>>> "java/util/Iterator") \
>>>>
>>>> *) Space after "if"? Also, I think you can use
>>>> ciType::is_subtype_of instead here. Plus, since you
>>>> declared iterator in WK klasses, SystemDictionary::Iterator_klass()
>>>> should be available.
>>>>
>>>> 100 if(retType->is_klass() &&
>>>> retType->as_klass()->is_subtype_of(C->env()->Iterator_klass())) {
>>>>
More information about the hotspot-compiler-dev
mailing list