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