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