1 /* 2 * Copyright (c) 2013, 2018, 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 * These tests are explicitly testing the profiling behavior of the 26 * interpreter. C1-based profiling differs slightly and when -Xcomp 27 * is present, profiles will be created by C1 compiled code, not the 28 * interpreter. 29 * 30 * @test 31 * @requires vm.jvmci 32 * @requires vm.compMode != "Xcomp" 33 * @requires vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel > 1 34 * @modules jdk.internal.vm.ci/jdk.vm.ci.meta 35 * jdk.internal.vm.ci/jdk.vm.ci.runtime 36 * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -Xbootclasspath/a:. compiler.jvmci.meta.ProfilingInfoTest 37 */ 38 package compiler.jvmci.meta; 39 40 import java.io.Serializable; 41 import java.lang.reflect.Constructor; 42 import java.lang.reflect.Executable; 43 import java.lang.reflect.InvocationTargetException; 44 import java.lang.reflect.Method; 45 46 import org.junit.Assert; 47 import org.junit.Assume; 48 import org.junit.Test; 49 50 import jdk.vm.ci.meta.JavaTypeProfile; 51 import jdk.vm.ci.meta.MetaAccessProvider; 52 import jdk.vm.ci.meta.ProfilingInfo; 53 import jdk.vm.ci.meta.ResolvedJavaMethod; 54 import jdk.vm.ci.meta.ResolvedJavaType; 55 import jdk.vm.ci.meta.TriState; 56 import jdk.vm.ci.runtime.JVMCI; 57 58 /** 59 * Tests profiling information provided by the runtime. 60 * <p> 61 * NOTE: These tests are actually not very robust. The problem is that only partial profiling 62 * information may be gathered for any given method. For example, HotSpot's advanced compilation 63 * policy can decide to only gather partial profiles in a first level compilation (see 64 * AdvancedThresholdPolicy::common(...) in advancedThresholdPolicy.cpp). Because of this, 65 * occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only sets 66 * the null_seen bit when doing full profiling. 67 */ 68 public class ProfilingInfoTest { 69 70 private static final int N = 10; 71 private static final double DELTA = 1d / Integer.MAX_VALUE; 72 73 @Test 74 public void testBranchTakenProbability() { 75 ProfilingInfo info = profile("branchProbabilitySnippet", 0); 76 Assert.assertEquals(0.0, info.getBranchTakenProbability(1), DELTA); 77 Assert.assertEquals(N, info.getExecutionCount(1)); 78 Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA); 79 Assert.assertEquals(0, info.getExecutionCount(8)); 80 81 info = profile("branchProbabilitySnippet", 1); 82 Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA); 83 Assert.assertEquals(N, info.getExecutionCount(1)); 84 Assert.assertEquals(0.0, info.getBranchTakenProbability(8), DELTA); 85 Assert.assertEquals(N, info.getExecutionCount(8)); 86 87 info = profile("branchProbabilitySnippet", 2); 88 Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA); 89 Assert.assertEquals(N, info.getExecutionCount(1)); 90 Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA); 91 Assert.assertEquals(N, info.getExecutionCount(8)); 92 93 continueProfiling(3 * N, "branchProbabilitySnippet", 0); 94 Assert.assertEquals(0.25, info.getBranchTakenProbability(1), DELTA); 95 Assert.assertEquals(4 * N, info.getExecutionCount(1)); 96 Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA); 97 Assert.assertEquals(N, info.getExecutionCount(8)); 98 99 resetProfile("branchProbabilitySnippet"); 100 Assert.assertEquals(-1.0, info.getBranchTakenProbability(1), DELTA); 101 Assert.assertEquals(0, info.getExecutionCount(1)); 102 Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA); 103 Assert.assertEquals(0, info.getExecutionCount(8)); 104 } 105 106 public static int branchProbabilitySnippet(int value) { 107 if (value == 0) { 108 return -1; 109 } else if (value == 1) { 110 return -2; 111 } else { 112 return -3; 113 } 114 } 115 116 @Test 117 public void testSwitchProbabilities() { 118 ProfilingInfo info = profile("switchProbabilitySnippet", 0); 119 Assert.assertArrayEquals(new double[]{1.0, 0.0, 0.0}, info.getSwitchProbabilities(1), DELTA); 120 121 info = profile("switchProbabilitySnippet", 1); 122 Assert.assertArrayEquals(new double[]{0.0, 1.0, 0.0}, info.getSwitchProbabilities(1), DELTA); 123 124 info = profile("switchProbabilitySnippet", 2); 125 Assert.assertArrayEquals(new double[]{0.0, 0.0, 1.0}, info.getSwitchProbabilities(1), DELTA); 126 127 resetProfile("switchProbabilitySnippet"); 128 Assert.assertNull(info.getSwitchProbabilities(1)); 129 } 130 131 public static int switchProbabilitySnippet(int value) { 132 switch (value) { 133 case 0: 134 return -1; 135 case 1: 136 return -2; 137 default: 138 return -3; 139 } 140 } 141 142 @Test 143 public void testProfileInvokeVirtual() { 144 testTypeProfile("invokeVirtualSnippet", 1); 145 } 146 147 public static int invokeVirtualSnippet(Object obj) { 148 return obj.hashCode(); 149 } 150 151 @Test 152 public void testTypeProfileInvokeInterface() { 153 testTypeProfile("invokeInterfaceSnippet", 1); 154 } 155 156 public static int invokeInterfaceSnippet(CharSequence a) { 157 return a.length(); 158 } 159 160 @Test 161 public void testTypeProfileCheckCast() { 162 testTypeProfile("checkCastSnippet", 1); 163 } 164 165 public static Serializable checkCastSnippet(Object obj) { 166 try { 167 return (Serializable) obj; 168 } catch (ClassCastException e) { 169 return null; 170 } 171 } 172 173 @Test 174 public void testTypeProfileInstanceOf() { 175 testTypeProfile("instanceOfSnippet", 1); 176 } 177 178 public static boolean instanceOfSnippet(Object obj) { 179 return obj instanceof Serializable; 180 } 181 182 private void testTypeProfile(String testSnippet, int bci) { 183 MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); 184 ResolvedJavaType stringType = metaAccess.lookupJavaType(String.class); 185 ResolvedJavaType stringBuilderType = metaAccess.lookupJavaType(StringBuilder.class); 186 187 ProfilingInfo info = profile(testSnippet, "ABC"); 188 JavaTypeProfile typeProfile = info.getTypeProfile(bci); 189 Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA); 190 Assert.assertEquals(1, typeProfile.getTypes().length); 191 Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType()); 192 Assert.assertEquals(1.0, typeProfile.getTypes()[0].getProbability(), DELTA); 193 194 continueProfiling(testSnippet, new StringBuilder()); 195 typeProfile = info.getTypeProfile(bci); 196 Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA); 197 Assert.assertEquals(2, typeProfile.getTypes().length); 198 Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType()); 199 Assert.assertEquals(stringBuilderType, typeProfile.getTypes()[1].getType()); 200 Assert.assertEquals(0.5, typeProfile.getTypes()[0].getProbability(), DELTA); 201 Assert.assertEquals(0.5, typeProfile.getTypes()[1].getProbability(), DELTA); 202 203 resetProfile(testSnippet); 204 typeProfile = info.getTypeProfile(bci); 205 Assert.assertNull(typeProfile); 206 } 207 208 public ProfilingInfoTest() { 209 } 210 211 @Test 212 public void testExceptionSeen() { 213 // NullPointerException 214 ProfilingInfo info = profile("nullPointerExceptionSnippet", 5); 215 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 216 217 info = profile("nullPointerExceptionSnippet", (Object) null); 218 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); 219 220 resetProfile("nullPointerExceptionSnippet"); 221 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 222 223 // ArrayOutOfBoundsException 224 info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[1]); 225 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2)); 226 227 info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[0]); 228 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(2)); 229 230 resetProfile("arrayIndexOutOfBoundsExceptionSnippet"); 231 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2)); 232 233 // CheckCastException 234 info = profile("checkCastExceptionSnippet", "ABC"); 235 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 236 237 info = profile("checkCastExceptionSnippet", 5); 238 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); 239 240 resetProfile("checkCastExceptionSnippet"); 241 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 242 243 // Invoke with exception 244 info = profile("invokeWithExceptionSnippet", false); 245 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 246 247 info = profile("invokeWithExceptionSnippet", true); 248 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); 249 250 resetProfile("invokeWithExceptionSnippet"); 251 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 252 } 253 254 public static int nullPointerExceptionSnippet(Object obj) { 255 try { 256 return obj.hashCode(); 257 } catch (NullPointerException e) { 258 return 1; 259 } 260 } 261 262 public static int arrayIndexOutOfBoundsExceptionSnippet(int[] array) { 263 try { 264 return array[0]; 265 } catch (ArrayIndexOutOfBoundsException e) { 266 return 1; 267 } 268 } 269 270 public static int checkCastExceptionSnippet(Object obj) { 271 try { 272 return ((String) obj).length(); 273 } catch (ClassCastException e) { 274 return 1; 275 } 276 } 277 278 public static int invokeWithExceptionSnippet(boolean doThrow) { 279 try { 280 return throwException(doThrow); 281 } catch (IllegalArgumentException e) { 282 return 1; 283 } 284 } 285 286 private static int throwException(boolean doThrow) { 287 if (doThrow) { 288 throw new IllegalArgumentException(); 289 } else { 290 return 1; 291 } 292 } 293 294 @Test 295 public void testNullSeen() { 296 testNullSeen("instanceOfSnippet"); 297 testNullSeen("checkCastSnippet"); 298 } 299 300 private void testNullSeen(String snippet) { 301 ProfilingInfo info = profile(snippet, 1); 302 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 303 304 continueProfiling(snippet, "ABC"); 305 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 306 307 continueProfiling(snippet, new Object()); 308 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 309 310 if (TriState.TRUE == info.getNullSeen(1)) { 311 // See the javadoc comment for ProfilingInfoTest. 312 continueProfiling(snippet, (Object) null); 313 Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); 314 315 continueProfiling(snippet, 0.0); 316 Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); 317 318 continueProfiling(snippet, new Object()); 319 Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); 320 } 321 322 resetProfile(snippet); 323 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 324 } 325 326 private ProfilingInfo profile(String methodName, Object... args) { 327 return profile(true, N, methodName, args); 328 } 329 330 private void continueProfiling(String methodName, Object... args) { 331 profile(false, N, methodName, args); 332 } 333 334 private void continueProfiling(int executions, String methodName, Object... args) { 335 profile(false, executions, methodName, args); 336 } 337 338 private ProfilingInfo profile(boolean resetProfile, int executions, String methodName, Object... args) { 339 MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); 340 Method method = getMethod(methodName); 341 ResolvedJavaMethod javaMethod = metaAccess.lookupJavaMethod(method); 342 Assert.assertTrue(javaMethod.isStatic()); 343 if (resetProfile) { 344 javaMethod.reprofile(); 345 } 346 347 for (int i = 0; i < executions; ++i) { 348 try { 349 method.invoke(null, args); 350 } catch (Throwable e) { 351 Assert.fail("method should not throw an exception: " + e.toString()); 352 } 353 } 354 355 ProfilingInfo info = javaMethod.getProfilingInfo(); 356 // The execution counts are low so force maturity 357 info.setMature(); 358 return info; 359 } 360 361 static Method getMethod(String methodName) { 362 for (Method method : ProfilingInfoTest.class.getDeclaredMethods()) { 363 if (method.getName().equals(methodName)) { 364 return method; 365 } 366 } 367 throw new IllegalArgumentException(); 368 } 369 370 private void resetProfile(String methodName) { 371 MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); 372 ResolvedJavaMethod javaMethod = metaAccess.lookupJavaMethod(getMethod(methodName)); 373 javaMethod.reprofile(); 374 } 375 }