1 /* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /** 26 * @test 27 * @bug 8031320 28 * @summary Verify that if we use RTMDeopt, then deoptimization 29 * caused by reason other then rtm_state_change will reset 30 * method's RTM state. And if we don't use RTMDeopt, then 31 * RTM state remain the same after such deoptimization. 32 * @library /test/lib / 33 * @modules java.base/jdk.internal.misc 34 * java.management 35 * @build sun.hotspot.WhiteBox 36 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 37 * sun.hotspot.WhiteBox$WhiteBoxPermission 38 * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions 39 * -XX:+WhiteBoxAPI 40 * compiler.rtm.locking.TestRTMAfterNonRTMDeopt 41 */ 42 43 package compiler.rtm.locking; 44 45 import compiler.testlibrary.rtm.AbortProvoker; 46 import compiler.testlibrary.rtm.CompilableTest; 47 import compiler.testlibrary.rtm.RTMLockingStatistics; 48 import compiler.testlibrary.rtm.RTMTestBase; 49 import compiler.testlibrary.rtm.predicate.SupportedCPU; 50 import compiler.testlibrary.rtm.predicate.SupportedOS; 51 import compiler.testlibrary.rtm.predicate.SupportedVM; 52 import jdk.internal.misc.Unsafe; 53 import jdk.test.lib.Asserts; 54 import jdk.test.lib.process.OutputAnalyzer; 55 import jdk.test.lib.unsafe.UnsafeHelper; 56 import jdk.test.lib.cli.CommandLineOptionTest; 57 import jdk.test.lib.cli.predicate.AndPredicate; 58 59 import java.util.List; 60 61 /** 62 * To verify that with +UseRTMDeopt method's RTM state will be 63 * changed to ProfileRTM on deoptimization unrelated to 64 * rtm_state_change following sequence of events is used: 65 * <pre> 66 * 67 * rtm state ^ 68 * | 69 * UseRTM | ******| ****** 70 * | | 71 * ProfileRTM |******| |*****| 72 * | | | | 73 * 0-------|-----|-----|---------------------> time 74 * | | \ force abort 75 * | | 76 * | \ force deoptimization 77 * | 78 * \ force xabort 79 * </pre> 80 * When xabort is forced by native method call method should 81 * change it's state to UseRTM, because we use RTMAbortRatio=100 82 * and low RTMLockingThreshold, so at this point actual abort 83 * ratio will be below 100% and there should be enough lock 84 * attempts to recompile method without RTM profiling. 85 */ 86 public class TestRTMAfterNonRTMDeopt extends CommandLineOptionTest { 87 private static final int ABORT_THRESHOLD = 1000; 88 private static final String RANGE_CHECK = "range_check"; 89 90 private TestRTMAfterNonRTMDeopt() { 91 super(new AndPredicate(new SupportedCPU(), new SupportedOS(), new SupportedVM())); 92 } 93 94 @Override 95 protected void runTestCases() throws Throwable { 96 verifyRTMAfterDeopt(false, false); 97 verifyRTMAfterDeopt(true, false); 98 99 verifyRTMAfterDeopt(false, true); 100 verifyRTMAfterDeopt(true, true); 101 } 102 103 private void verifyRTMAfterDeopt(boolean useStackLock, 104 boolean useRTMDeopt) throws Throwable { 105 CompilableTest test = new Test(); 106 String logFile = String.format("rtm_%s_stack_lock_%s_deopt.xml", 107 (useStackLock ? "use" : "no"), (useRTMDeopt ? "use" : "no")); 108 109 OutputAnalyzer outputAnalyzer = RTMTestBase.executeRTMTest( 110 logFile, 111 test, 112 "-XX:CompileThreshold=1", 113 CommandLineOptionTest.prepareBooleanFlag("UseRTMForStackLocks", 114 useStackLock), 115 CommandLineOptionTest.prepareBooleanFlag("UseRTMDeopt", 116 useRTMDeopt), 117 "-XX:RTMAbortRatio=100", 118 CommandLineOptionTest.prepareNumericFlag("RTMAbortThreshold", 119 TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD), 120 CommandLineOptionTest.prepareNumericFlag("RTMLockingThreshold", 121 TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD / 2L), 122 "-XX:RTMTotalCountIncrRate=1", 123 "-XX:+PrintPreciseRTMLockingStatistics", 124 Test.class.getName(), 125 Boolean.toString(!useStackLock) 126 ); 127 128 outputAnalyzer.shouldHaveExitValue(0); 129 130 int traps = RTMTestBase.firedRTMStateChangeTraps(logFile); 131 132 if (useRTMDeopt) { 133 Asserts.assertEQ(traps, 2, "Two uncommon traps with " 134 + "reason rtm_state_change should be fired."); 135 } else { 136 Asserts.assertEQ(traps, 0, "No uncommon traps with " 137 + "reason rtm_state_change should be fired."); 138 } 139 140 int rangeCheckTraps = RTMTestBase.firedUncommonTraps(logFile, 141 TestRTMAfterNonRTMDeopt.RANGE_CHECK); 142 143 Asserts.assertEQ(rangeCheckTraps, 1, 144 "One range_check uncommon trap should be fired."); 145 146 List<RTMLockingStatistics> statistics = RTMLockingStatistics.fromString( 147 test.getMethodWithLockName(), outputAnalyzer.getOutput()); 148 149 int expectedStatEntries = (useRTMDeopt ? 4 : 2); 150 151 Asserts.assertEQ(statistics.size(), expectedStatEntries, 152 String.format("VM output should contain %d RTM locking " 153 + "statistics entries.", expectedStatEntries)); 154 } 155 156 public static class Test implements CompilableTest { 157 // Following field have to be static in order to avoid escape analysis. 158 @SuppressWarnings("UnsuedDeclaration") 159 private static int field = 0; 160 private static final int ITERATIONS = 10000; 161 private static final int RANGE_CHECK_AT = ITERATIONS / 2; 162 private static final Unsafe UNSAFE = UnsafeHelper.getUnsafe(); 163 private final Object monitor = new Object(); 164 165 @Override 166 public String getMethodWithLockName() { 167 return this.getClass().getName() + "::forceAbort"; 168 } 169 170 @Override 171 public String[] getMethodsToCompileNames() { 172 return new String[] { getMethodWithLockName() }; 173 } 174 175 public void forceAbort(int a[], boolean abort) { 176 try { 177 synchronized(monitor) { 178 a[0]++; 179 if (abort) { 180 Test.field = Test.UNSAFE.addressSize(); 181 } 182 } 183 } catch (Throwable t) { 184 // suppress any throwables 185 } 186 } 187 188 /** 189 * Usage: 190 * Test <inflate monitor> 191 */ 192 public static void main(String args[]) throws Throwable { 193 Test t = new Test(); 194 195 boolean shouldBeInflated = Boolean.valueOf(args[0]); 196 if (shouldBeInflated) { 197 AbortProvoker.inflateMonitor(t.monitor); 198 } 199 200 int tmp[] = new int[1]; 201 202 for (int i = 0; i < Test.ITERATIONS; i++ ) { 203 AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); 204 if (i == Test.RANGE_CHECK_AT) { 205 t.forceAbort(new int[0], false); 206 } else { 207 boolean isThreshold 208 = (i == TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD); 209 boolean isThresholdPlusRange 210 = (i == TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD 211 + Test.RANGE_CHECK_AT); 212 t.forceAbort(tmp, isThreshold || isThresholdPlusRange); 213 } 214 } 215 } 216 } 217 218 public static void main(String args[]) throws Throwable { 219 new TestRTMAfterNonRTMDeopt().test(); 220 } 221 } 222