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 
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