Withdrawn: 8293491: Avoid unexpected deoptimization in loop exit due to incorrect branch profiling
Jie Fu
jiefu at openjdk.org
Tue Sep 20 02:27:48 UTC 2022
On Wed, 7 Sep 2022 15:06:18 GMT, Jie Fu <jiefu at openjdk.org> wrote:
> Hi all,
>
> Please review this patch which fixes the unexpected deoptimizations in loop exit due to incorrect branch profiling.
>
> # Background
>
> While analyzing our big data Apps, we observed unexpected deoptimizations in loop exit due to incorrect branch profiling.
>
> Here is a reproducer.
>
> public class UnexpectedLoopExitDeopt {
> public static final int N = 20000000;
>
> public static int d1[] = new int[N];
> public static int d2[] = new int[N];
>
> public static void main(String[] args) {
> System.out.println(test(d1));
> System.out.println(test(d2));
> }
>
> public static int test(int[] a) {
> int sum = 0;
> for(int i = 0; i < a.length; i++) {
> sum += a[i];
> }
> return sum;
> }
> }
>
>
> The following is the compilation sequence.
>
> 77 1 3 java.lang.Object::<init> (1 bytes)
> 83 2 3 java.lang.String::isLatin1 (19 bytes)
> 84 6 3 jdk.internal.util.Preconditions::checkIndex (18 bytes)
> 84 3 3 java.lang.String::charAt (25 bytes)
> 85 4 3 java.lang.StringLatin1::charAt (15 bytes)
> 86 7 3 java.lang.String::coder (15 bytes)
> 86 8 3 java.lang.String::hashCode (60 bytes)
> 87 5 3 java.lang.String::checkIndex (10 bytes)
> 87 9 3 java.lang.String::length (11 bytes)
> 93 10 n 0 java.lang.invoke.MethodHandle::linkToStatic(LLLLLLL)L (native) (static)
> 96 11 n 0 java.lang.invoke.MethodHandle::linkToSpecial(LLLL)L (native) (static)
> 96 12 n 0 java.lang.Object::hashCode (native)
> 97 13 n 0 java.lang.invoke.MethodHandle::invokeBasic(LLLLLL)L (native)
> 98 14 3 java.util.Objects::requireNonNull (14 bytes)
> 98 15 n 0 java.lang.invoke.MethodHandle::linkToSpecial(LLLLLLLL)L (native) (static)
> 98 16 1 java.lang.Enum::ordinal (5 bytes)
> 101 17 n 0 java.lang.invoke.MethodHandle::linkToSpecial(LLLL)V (native) (static)
> 102 18 n 0 java.lang.invoke.MethodHandle::invokeBasic(LL)L (native)
> 212 19 % 3 UnexpectedLoopExitDeopt::test @ 4 (24 bytes)
> 213 20 % 4 UnexpectedLoopExitDeopt::test @ 4 (24 bytes)
> 221 19 % 3 UnexpectedLoopExitDeopt::test @ 4 (24 bytes) made not entrant
> 221 21 4 UnexpectedLoopExitDeopt::test (24 bytes)
> 230 20 % 4 UnexpectedLoopExitDeopt::test @ 4 (24 bytes) made not entrant <--- Unexpected deopt
> 0
> 242 21 4 UnexpectedLoopExitDeopt::test (24 bytes) made not entrant <--- Unexpected deopt
> 0
>
>
> The last two deopts (made not entrant) happened in the loop exit which are unexpected.
>
>
> # Reason
>
> The unexpected deopts were caused by the incorrect branch profiling count (0 taken count for loop predicate).
>
> Here is the profiling data for `UnexpectedLoopExitDeopt::test`.
> We can see that for `if_icmpge` @ bci=7, the count for `not taken` is 264957, while 0 for `taken`.
> The profile count for zero taken is obvious incorrect since the loop will finally exit (when `i >= a.length`).
> So the taken count should be at least 1 for `if_icmpge` @ bci=7.
>
> 0 iconst_0
> 1 istore_1
> 2 iconst_0
> 3 istore_2
>
> 4 iload_2
> 5 fast_aload_0
> 6 arraylength
> 7 if_icmpge 22
> 0 bci: 7 BranchData taken(0) displacement(56)
> not taken(264957)
>
> 10 iload_1
> 11 fast_aload_0
> 12 iload_2
> 13 iaload
> 14 iadd
> 15 istore_1
> 16 iinc #2 1
> 19 goto 4
> 32 bci: 19 JumpData taken(266667) displacement(-32)
>
> 22 iload_1
> 23 ireturn
>
>
> # Fix
>
> The main idea is to detect if the branch taken target is a loop exit.
> If so, set the taken count to be at least 1.
> This is fine because most loops should be finite and would execute the loop exit code at lease once.
> For infinite loops like `while (true) {...}`, the patch won't change the original behaviour since there is no loop exit.
>
> # Testing
>
> tier1~3 on Linux/x64, no regression
>
> Thanks.
> Best regards,
> Jie
This pull request has been closed without being integrated.
-------------
PR: https://git.openjdk.org/jdk/pull/10200
More information about the hotspot-compiler-dev
mailing list