001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.compiler.test; 024 025import java.io.*; 026 027import jdk.internal.jvmci.meta.*; 028 029import org.junit.*; 030 031/** 032 * Tests profiling information provided by the runtime. 033 * <p> 034 * NOTE: These tests are actually not very robust. The problem is that only partial profiling 035 * information may be gathered for any given method. For example, HotSpot's advanced compilation 036 * policy can decide to only gather partial profiles in a first level compilation (see 037 * AdvancedThresholdPolicy::common(...) in advancedThresholdPolicy.cpp). Because of this, 038 * occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only set's 039 * the null_seen bit when doing full profiling. 040 */ 041public class ProfilingInfoTest extends GraalCompilerTest { 042 043 private static final int N = 10; 044 private static final double DELTA = 1d / Integer.MAX_VALUE; 045 046 @Test 047 public void testBranchTakenProbability() { 048 ProfilingInfo info = profile("branchProbabilitySnippet", 0); 049 Assert.assertEquals(0.0, info.getBranchTakenProbability(1), DELTA); 050 Assert.assertEquals(N, info.getExecutionCount(1)); 051 Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA); 052 Assert.assertEquals(0, info.getExecutionCount(8)); 053 054 info = profile("branchProbabilitySnippet", 1); 055 Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA); 056 Assert.assertEquals(N, info.getExecutionCount(1)); 057 Assert.assertEquals(0.0, info.getBranchTakenProbability(8), DELTA); 058 Assert.assertEquals(N, info.getExecutionCount(8)); 059 060 info = profile("branchProbabilitySnippet", 2); 061 Assert.assertEquals(1.0, info.getBranchTakenProbability(1), DELTA); 062 Assert.assertEquals(N, info.getExecutionCount(1)); 063 Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA); 064 Assert.assertEquals(N, info.getExecutionCount(8)); 065 066 continueProfiling(3 * N, "branchProbabilitySnippet", 0); 067 Assert.assertEquals(0.25, info.getBranchTakenProbability(1), DELTA); 068 Assert.assertEquals(4 * N, info.getExecutionCount(1)); 069 Assert.assertEquals(1.0, info.getBranchTakenProbability(8), DELTA); 070 Assert.assertEquals(N, info.getExecutionCount(8)); 071 072 resetProfile("branchProbabilitySnippet"); 073 Assert.assertEquals(-1.0, info.getBranchTakenProbability(1), DELTA); 074 Assert.assertEquals(0, info.getExecutionCount(1)); 075 Assert.assertEquals(-1.0, info.getBranchTakenProbability(8), DELTA); 076 Assert.assertEquals(0, info.getExecutionCount(8)); 077 } 078 079 public static int branchProbabilitySnippet(int value) { 080 if (value == 0) { 081 return -1; 082 } else if (value == 1) { 083 return -2; 084 } else { 085 return -3; 086 } 087 } 088 089 @Test 090 public void testSwitchProbabilities() { 091 ProfilingInfo info = profile("switchProbabilitySnippet", 0); 092 Assert.assertArrayEquals(new double[]{1.0, 0.0, 0.0}, info.getSwitchProbabilities(1), DELTA); 093 094 info = profile("switchProbabilitySnippet", 1); 095 Assert.assertArrayEquals(new double[]{0.0, 1.0, 0.0}, info.getSwitchProbabilities(1), DELTA); 096 097 info = profile("switchProbabilitySnippet", 2); 098 Assert.assertArrayEquals(new double[]{0.0, 0.0, 1.0}, info.getSwitchProbabilities(1), DELTA); 099 100 resetProfile("switchProbabilitySnippet"); 101 Assert.assertNull(info.getSwitchProbabilities(1)); 102 } 103 104 public static int switchProbabilitySnippet(int value) { 105 switch (value) { 106 case 0: 107 return -1; 108 case 1: 109 return -2; 110 default: 111 return -3; 112 } 113 } 114 115 @Test 116 public void testProfileInvokeVirtual() { 117 testTypeProfile("invokeVirtualSnippet", 1); 118 } 119 120 public static int invokeVirtualSnippet(Object obj) { 121 return obj.hashCode(); 122 } 123 124 @Test 125 public void testTypeProfileInvokeInterface() { 126 testTypeProfile("invokeInterfaceSnippet", 1); 127 } 128 129 public static int invokeInterfaceSnippet(CharSequence a) { 130 return a.length(); 131 } 132 133 @Test 134 public void testTypeProfileCheckCast() { 135 testTypeProfile("checkCastSnippet", 1); 136 } 137 138 public static Serializable checkCastSnippet(Object obj) { 139 try { 140 return (Serializable) obj; 141 } catch (ClassCastException e) { 142 return null; 143 } 144 } 145 146 @Test 147 public void testTypeProfileInstanceOf() { 148 testTypeProfile("instanceOfSnippet", 1); 149 } 150 151 public static boolean instanceOfSnippet(Object obj) { 152 return obj instanceof Serializable; 153 } 154 155 private void testTypeProfile(String testSnippet, int bci) { 156 ResolvedJavaType stringType = getMetaAccess().lookupJavaType(String.class); 157 ResolvedJavaType stringBuilderType = getMetaAccess().lookupJavaType(StringBuilder.class); 158 159 ProfilingInfo info = profile(testSnippet, "ABC"); 160 JavaTypeProfile typeProfile = info.getTypeProfile(bci); 161 Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA); 162 Assert.assertEquals(1, typeProfile.getTypes().length); 163 Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType()); 164 Assert.assertEquals(1.0, typeProfile.getTypes()[0].getProbability(), DELTA); 165 166 continueProfiling(testSnippet, new StringBuilder()); 167 typeProfile = info.getTypeProfile(bci); 168 Assert.assertEquals(0.0, typeProfile.getNotRecordedProbability(), DELTA); 169 Assert.assertEquals(2, typeProfile.getTypes().length); 170 Assert.assertEquals(stringType, typeProfile.getTypes()[0].getType()); 171 Assert.assertEquals(stringBuilderType, typeProfile.getTypes()[1].getType()); 172 Assert.assertEquals(0.5, typeProfile.getTypes()[0].getProbability(), DELTA); 173 Assert.assertEquals(0.5, typeProfile.getTypes()[1].getProbability(), DELTA); 174 175 resetProfile(testSnippet); 176 typeProfile = info.getTypeProfile(bci); 177 Assert.assertNull(typeProfile); 178 } 179 180 @Test 181 public void testExceptionSeen() { 182 // NullPointerException 183 ProfilingInfo info = profile("nullPointerExceptionSnippet", 5); 184 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 185 186 info = profile("nullPointerExceptionSnippet", (Object) null); 187 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); 188 189 resetProfile("nullPointerExceptionSnippet"); 190 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 191 192 // ArrayOutOfBoundsException 193 info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[1]); 194 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2)); 195 196 info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[0]); 197 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(2)); 198 199 resetProfile("arrayIndexOutOfBoundsExceptionSnippet"); 200 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(2)); 201 202 // CheckCastException 203 info = profile("checkCastExceptionSnippet", "ABC"); 204 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 205 206 info = profile("checkCastExceptionSnippet", 5); 207 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); 208 209 resetProfile("checkCastExceptionSnippet"); 210 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 211 212 // Invoke with exception 213 info = profile("invokeWithExceptionSnippet", false); 214 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 215 216 info = profile("invokeWithExceptionSnippet", true); 217 Assert.assertEquals(TriState.TRUE, info.getExceptionSeen(1)); 218 219 resetProfile("invokeWithExceptionSnippet"); 220 Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); 221 } 222 223 public static int nullPointerExceptionSnippet(Object obj) { 224 try { 225 return obj.hashCode(); 226 } catch (NullPointerException e) { 227 return 1; 228 } 229 } 230 231 public static int arrayIndexOutOfBoundsExceptionSnippet(int[] array) { 232 try { 233 return array[0]; 234 } catch (ArrayIndexOutOfBoundsException e) { 235 return 1; 236 } 237 } 238 239 public static int checkCastExceptionSnippet(Object obj) { 240 try { 241 return ((String) obj).length(); 242 } catch (ClassCastException e) { 243 return 1; 244 } 245 } 246 247 public static int invokeWithExceptionSnippet(boolean doThrow) { 248 try { 249 return throwException(doThrow); 250 } catch (IllegalArgumentException e) { 251 return 1; 252 } 253 } 254 255 private static int throwException(boolean doThrow) { 256 if (doThrow) { 257 throw new IllegalArgumentException(); 258 } else { 259 return 1; 260 } 261 } 262 263 @Test 264 public void testNullSeen() { 265 testNullSeen("instanceOfSnippet"); 266 testNullSeen("checkCastSnippet"); 267 } 268 269 private void testNullSeen(String snippet) { 270 ProfilingInfo info = profile(snippet, 1); 271 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 272 273 continueProfiling(snippet, "ABC"); 274 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 275 276 continueProfiling(snippet, new Object()); 277 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 278 279 if (TriState.TRUE == info.getNullSeen(1)) { 280 // See the javadoc comment for ProfilingInfoTest. 281 continueProfiling(snippet, (Object) null); 282 Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); 283 284 continueProfiling(snippet, 0.0); 285 Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); 286 287 continueProfiling(snippet, new Object()); 288 Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); 289 } 290 291 resetProfile(snippet); 292 Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); 293 } 294 295 private ProfilingInfo profile(String methodName, Object... args) { 296 return profile(true, N, methodName, args); 297 } 298 299 private void continueProfiling(String methodName, Object... args) { 300 profile(false, N, methodName, args); 301 } 302 303 private void continueProfiling(int executions, String methodName, Object... args) { 304 profile(false, executions, methodName, args); 305 } 306 307 private ProfilingInfo profile(boolean resetProfile, int executions, String methodName, Object... args) { 308 ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName); 309 Assert.assertTrue(javaMethod.isStatic()); 310 if (resetProfile) { 311 javaMethod.reprofile(); 312 } 313 314 for (int i = 0; i < executions; ++i) { 315 try { 316 invoke(javaMethod, null, args); 317 } catch (Throwable e) { 318 Assert.fail("method should not throw an exception: " + e.toString()); 319 } 320 } 321 322 ProfilingInfo info = javaMethod.getProfilingInfo(); 323 // The execution counts are low so force maturity 324 info.setMature(); 325 return info; 326 } 327 328 private void resetProfile(String methodName) { 329 ResolvedJavaMethod javaMethod = getResolvedJavaMethod(methodName); 330 javaMethod.reprofile(); 331 } 332}