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