ProfilingInfoTest.java revision 12651:6ef01bd40ce2
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 */
23package org.graalvm.compiler.core.test;
24
25import java.io.Serializable;
26
27import jdk.vm.ci.meta.JavaTypeProfile;
28import jdk.vm.ci.meta.ProfilingInfo;
29import jdk.vm.ci.meta.ResolvedJavaMethod;
30import jdk.vm.ci.meta.ResolvedJavaType;
31import jdk.vm.ci.meta.TriState;
32
33import org.junit.Assert;
34import 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 */
46public 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}
338