RFR: 8293491: Avoid unexpected deoptimization in loop exit due to incorrect branch profiling
Jie Fu
jiefu at openjdk.org
Wed Sep 7 15:13:37 UTC 2022
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
-------------
Commit messages:
- 8293491: Avoid unexpected deoptimization in loop exit due to incorrect branch profiling
Changes: https://git.openjdk.org/jdk/pull/10200/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=10200&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8293491
Stats: 92 lines in 5 files changed: 86 ins; 2 del; 4 mod
Patch: https://git.openjdk.org/jdk/pull/10200.diff
Fetch: git fetch https://git.openjdk.org/jdk pull/10200/head:pull/10200
PR: https://git.openjdk.org/jdk/pull/10200
More information about the hotspot-compiler-dev
mailing list