Inlining heuristic trouble

Christian Thalinger christian.thalinger at oracle.com
Fri Jun 17 02:50:51 PDT 2011


On Jun 17, 2011, at 11:14 AM, Rémi Forax wrote:
> On 06/17/2011 10:58 AM, Christian Thalinger wrote:
>> On Jun 15, 2011, at 5:26 PM, Rémi Forax wrote:
>>> // with the optimization
>>> [forax at localhost binary-operation]$ time java -cp .:classes PerfOpt
>>> real    0m0.954s
>>> user    0m1.030s
>>> sys    0m0.087s
>>> 
>>> // without
>>> [forax at localhost binary-operation]$ time java -cp .:classes Perf
>>> real    0m0.378s
>>> user    0m0.407s
>>> sys    0m0.081s
>>> 
>>> Knowing that the double xor trick does 4 comparisons and
>>> the constant trick only two, the problem comes from either
>>> my code or the way the VM inlines the method handles.
>>> 
>>> I've found no problem in my code so ... :)
>>> Playing with the VM logs, the method containing (j != MAXINT) is not inlined
>>> because it hits the maximum depth (as far as I remember this problem
>>> is new, the older algorithm, the one that didn't propagate MDO, didn't
>>> exhibit this problem).
>> I fixed a small bug in printing the inlining tree with nested MHs (we're getting flat trees in this case).  Anyway, the inlining for PerfOpt looks actually good.  Here are the inlining trees of Perf and PerfOpt:
>> 
>>     888    1 %           Perf::main @ 17 (47 bytes)
>>                             @ 19   Perf::less (50 bytes)   already compiled into a big method
>>                             @ 27   java.lang.Integer::valueOf (54 bytes)   inline (hot)
>>                             @ 30   java.lang.invoke.MethodHandle::invokeExact (8 bytes)   inline (hot)
>>                               @ 4   java.lang.invoke.MethodHandleImpl$GuardWithTest::invoke_L2 (32 bytes)   inline (hot)
>>                                 @ 6   java.lang.invoke.MethodHandle::invokeExact (5 bytes)   inline (hot)
>>                                   @ 1   jsr292.cookbook.binop.RT::integerCheck (16 bytes)   inline (hot)
>>                                     @ 1   java.lang.Object::getClass (0 bytes)   (intrinsic)
>>                                 @ 18   java.lang.invoke.MethodHandle::invokeExact (8 bytes)   inline (hot)
>>                                   @ 4   java.lang.invoke.MethodHandleImpl$GuardWithTest::invoke_L2 (32 bytes)   inline (hot)
>>                                     @ 6   java.lang.invoke.MethodHandle::invokeExact (5 bytes)   inline (hot)
>>                                       @ 1   jsr292.cookbook.binop.RT::integerCheck (16 bytes)   inline (hot)
>>                                         @ 1   java.lang.Object::getClass (0 bytes)   (intrinsic)
>>                                     @ 18   java.lang.invoke.MethodHandle::invokeExact (57 bytes)   inline (hot)
>>                                       @ 31   java.lang.Integer::intValue (5 bytes)   inline (hot)
>>                                       @ 44   java.lang.Integer::intValue (5 bytes)   inline (hot)
>>                                       @ 53   jsr292.cookbook.binop.RT::safeAdd (35 bytes)   inline (hot)
>>                                         @ 18   java.math.BigInteger::valueOf (62 bytes)   already compiled into a medium method
>>                                         @ 23   java.math.BigInteger::valueOf (62 bytes)   already compiled into a medium method
>>                                         @ 26   java.math.BigInteger::add (123 bytes)   too big
>>                                         @ 31   java.lang.Integer::valueOf (54 bytes)   inline (hot)
>>                                           @ 50   java.lang.Integer::<init>  (10 bytes)   inline (hot)
>>                                             @ 1   java.lang.Number::<init>  (5 bytes)   inline (hot)
>>                                               @ 1   java.lang.Object::<init>  (1 bytes)   inline (hot)
>>                             @ 19   Perf::less (50 bytes)   already compiled into a big method
>> 
>> 
>>     854    1 %           PerfOpt::main @ 17 (43 bytes)
>>                             @ 19   PerfOpt::less (50 bytes)   already compiled into a big method
>>                             @ 26   java.lang.invoke.MethodHandle::invokeExact (7 bytes)   inline (hot)
>>                               @ 3   java.lang.invoke.MethodHandleImpl$GuardWithTest::invoke_L1 (29 bytes)   inline (hot)
>>                                 @ 5   java.lang.invoke.MethodHandle::invokeExact (5 bytes)   inline (hot)
>>                                   @ 1   jsr292.cookbook.binop.RT::integerCheck (16 bytes)   inline (hot)
>>                                     @ 1   java.lang.Object::getClass (0 bytes)   (intrinsic)
>>                                 @ 16   java.lang.invoke.MethodHandle::invokeExact (84 bytes)   inline (hot)
>>                                   @ 11   java.lang.Integer::intValue (5 bytes)   inline (hot)
>>                                   @ 20   java.lang.invoke.MethodHandle::invokeExact (5 bytes)   inline (hot)
>>                                     @ 1   jsr292.cookbook.binop.RT::maxIntCheck (12 bytes)   inline (hot)
>>                                   @ 27   java.lang.Integer::valueOf (54 bytes)   inline (hot)
>>                                     @ 50   java.lang.Integer::<init>  (10 bytes)   inline (hot)
>>                                       @ 1   java.lang.Number::<init>  (5 bytes)   inline (hot)
>>                                         @ 1   java.lang.Object::<init>  (1 bytes)   inline (hot)
>>                                   @ 34   java.lang.Boolean::valueOf (14 bytes)   inline (hot)
>>                                   @ 43   java.lang.invoke.MethodHandle::invokeExact (26 bytes)   inline (hot)
>>                                     @ 11   java.lang.Boolean::booleanValue (5 bytes)   inline (hot)
>>                                     @ 22   java.lang.invoke.MethodHandleImpl::selectAlternative (10 bytes)   inline (hot)
>>                                   @ 64   java.lang.Integer::intValue (5 bytes)   inline (hot)
>>                                   @ 80   java.lang.invoke.MethodHandle::invokeExact (12 bytes)   inline (hot)
>>                                   @ 80   java.lang.invoke.MethodHandle::invokeExact (18 bytes)   inline (hot)
>>                                     @ 4   java.lang.invoke.MethodHandle::invokeExact (6 bytes)   inline (hot)
>>                                       @ 2   jsr292.cookbook.binop.RT::add (4 bytes)   inline (hot)
>>                                     @ 9   java.lang.Integer::valueOf (54 bytes)   inline (hot)
>>                                       @ 50   java.lang.Integer::<init>  (10 bytes)   inline (hot)
>>                                         @ 1   java.lang.Number::<init>  (5 bytes)   inline (hot)
>>                                           @ 1   java.lang.Object::<init>  (1 bytes)   inline (hot)
>>                                     @ 14   sun.invoke.util.ValueConversions::identity (2 bytes)   inline (hot)
>>                                     @ 1   java.lang.Integer::valueOf (54 bytes)   inline (hot)
>>                                       @ 50   java.lang.Integer::<init>  (10 bytes)   inline (hot)
>>                                         @ 1   java.lang.Number::<init>  (5 bytes)   inline (hot)
>>                                           @ 1   java.lang.Object::<init>  (1 bytes)   inline (hot)
>>                                     @ 8   jsr292.cookbook.binop.RT::fallbackOpLeft (115 bytes)   inline (hot)
>>                                       @ 5   java.math.BigInteger::valueOf (62 bytes)   already compiled into a medium method
>>                                       @ 10   java.lang.Object::getClass (0 bytes)   (intrinsic)
>>                                       @ 33   java.lang.Integer::intValue (5 bytes)   inline (hot)
>>                                       @ 37   java.math.BigInteger::valueOf (62 bytes)   already compiled into a medium method
>>                                       @ 45   java.lang.invoke.MethodHandle::invokeWithArguments (61 bytes)   too big
>>                             @ 19   PerfOpt::less (50 bytes)   already compiled into a big method
>> 
>>> Moreover, the VM tries to inline some parts of the fallback method
>>> (twice :( )
>>> even if this code never called.
> 
> It's far more readable, now :)
> 
> I wonder if I haven't introduce a bug in my logic,
> there is a the boxing/unboxing of the return value of the test that 
> should not occur.
> Question, does EA is also disable when MH.invokeExact is called  ?

Yes, as MH.invokeExact is a native method:

[EA] computing results for java/lang/invoke/MethodHandle.invokeExact
Skipping method because: method is native.

There needs to be special machinery to handle that case.

> 
>  @ 34   java.lang.Boolean::valueOf (14 bytes)   inline (hot)
>  @ 43   java.lang.invoke.MethodHandle::invokeExact (26 bytes)   inline (hot)
>    @ 11   java.lang.Boolean::booleanValue (5 bytes)   inline (hot)
> 
> 
> I will check my code.
> 
>> Hmm.  I'm a little curious about how fallbackOpLeft becomes the fallback path.  Usually this is/was done with a guardWithTest.  Is selectAlternative doing this?
> 
> isSelectAlternative is the internal method called when you create a 
> guardWithTest
> with ricochet frame enabled.

I see.

> 
>> I think what's happening here is, we propagate the call site count from the hIot MH call site to all its callees through the MH chain and since fallbackOpLeft is in there it gets the same call site count making it hot, while actually it isn't.
> 
> Yes, one solution is to always set the fallback as cold.
> A better solution is to record the usage of each branch when interpreted.

We do that.  I'm just not sure how to get to that information from the method handle compiler.

-- Christian

> 
>> -- Christian
> 
> Rémi
> 
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev




More information about the mlvm-dev mailing list