comparison truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java @ 22503:828c67903db2

Moving profiles into their own project to ensure the core API doesn't reference these utility classes.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Thu, 17 Dec 2015 10:01:38 +0100
parents truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java@a63bda98cfdb
children d80a5ff56f51
comparison
equal deleted inserted replaced
22502:d2b4fe945c23 22503:828c67903db2
1 /*
2 * Copyright (c) 2015, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.oracle.truffle.api.profiles;
26
27 import com.oracle.truffle.api.CompilerDirectives;
28 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
29 import com.oracle.truffle.api.Truffle;
30
31 /**
32 * <p>
33 * LoopConditionProfiles are designed to profile the outcome of loop conditions. Loop profiles can
34 * be used to profile unpredictable loops as well as predictable loops.
35 * </p>
36 *
37 * <p>
38 * <b> Arbitrary loop usage example: </b>
39 *
40 * <pre>
41 * class LoopNode extends Node {
42 *
43 * final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
44 *
45 * void execute() {
46 * // loop count cannot be predicted
47 * while (loopProfile.profile(Math.random() &gt;= 0.9)) {
48 * // work
49 * }
50 * }
51 * }
52 * </pre>
53 *
54 * </p>
55 *
56 * <p>
57 * <b> Counted loop usage example: </b>
58 *
59 * <pre>
60 * class CountedLoopNode extends Node {
61 *
62 * final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
63 *
64 * void execute(int length) {
65 * // loop count can be predicted
66 * loopProfile.profileCounted(length);
67 * for (int i = 0; loopProfile.inject(i &lt; length); i++) {
68 * // work
69 * }
70 * }
71 * }
72 * </pre>
73 *
74 * </p>
75 * <p>
76 * The advantage of using {@link #profileCounted(long)} to using {@link #profile(boolean)} is that
77 * it incurs less overhead in the interpreter. Using {@link LoopConditionProfile#inject(boolean)} is
78 * a no-op in the interpreter while {@link #profile(boolean)} needs to use a counter for each
79 * iteration.
80 * </p>
81 *
82 *
83 * {@inheritDoc}
84 *
85 * @see #createBinaryProfile()
86 * @see #createCountingProfile()
87 * @see LoopConditionProfile
88 */
89 public abstract class LoopConditionProfile extends ConditionProfile {
90
91 LoopConditionProfile() {
92 }
93
94 @Override
95 public abstract boolean profile(boolean value);
96
97 /**
98 * Provides an alternative way to profile counted loops with less interpreter footprint. Please
99 * see {@link LoopConditionProfile} for an usage example.
100 *
101 * @see #inject(boolean)
102 */
103 public abstract void profileCounted(long length);
104
105 /**
106 * Provides an alternative way to profile counted loops with less interpreter footprint. Please
107 * see {@link LoopConditionProfile} for an usage example.
108 *
109 * @see #inject(boolean)
110 */
111 public abstract boolean inject(boolean condition);
112
113 /**
114 * Returns a {@link LoopConditionProfile} that speculates on loop conditions to be never
115 * <code>true</code>. It also captures loop probabilities for the compiler. Loop condition
116 * profiles are intended to be used for loop conditions.
117 *
118 * @see LoopConditionProfile
119 */
120 public static LoopConditionProfile createCountingProfile() {
121 if (Truffle.getRuntime().isProfilingEnabled()) {
122 return Enabled.create();
123 } else {
124 return Disabled.INSTANCE;
125 }
126 }
127
128 static final class Enabled extends LoopConditionProfile {
129
130 @CompilationFinal private long trueCount; // long for long running loops.
131 @CompilationFinal private int falseCount;
132
133 @Override
134 public boolean profile(boolean condition) {
135 if (CompilerDirectives.inInterpreter()) {
136 if (condition) {
137 // local required to guarantee no overflow in multi-threaded environments
138 long localTrueCount = trueCount;
139 if (localTrueCount < Long.MAX_VALUE) {
140 trueCount = localTrueCount + 1;
141 }
142 } else {
143 // local required to guarantee no overflow in multi-threaded environments
144 int localFalseCount = falseCount;
145 if (localFalseCount < Integer.MAX_VALUE) {
146 falseCount = localFalseCount + 1;
147 }
148 }
149 // no branch probability calculation in the interpreter
150 return condition;
151 } else {
152 long trueCountLocal = trueCount;
153 int falseCountLocal = falseCount;
154 if (trueCountLocal == 0) {
155 /* Deopt for never entering the loop. */
156 if (condition) {
157 CompilerDirectives.transferToInterpreterAndInvalidate();
158 trueCount = trueCountLocal = 1;
159 }
160 }
161 /* No deopt for not entering the loop. */
162 return CompilerDirectives.injectBranchProbability(calculateProbability(trueCountLocal, falseCountLocal), condition);
163 }
164 }
165
166 @Override
167 public void profileCounted(long length) {
168 if (CompilerDirectives.inInterpreter()) {
169 long trueCountLocal = trueCount + length;
170 if (trueCountLocal >= 0) { // don't write overflow values
171 trueCount = trueCountLocal;
172 int falseCountLocal = falseCount;
173 if (falseCountLocal < Integer.MAX_VALUE) {
174 falseCount = falseCountLocal + 1;
175 }
176 }
177 }
178 }
179
180 @Override
181 public boolean inject(boolean condition) {
182 if (CompilerDirectives.inCompiledCode()) {
183 return CompilerDirectives.injectBranchProbability(calculateProbability(trueCount, falseCount), condition);
184 } else {
185 return condition;
186 }
187 }
188
189 private static double calculateProbability(long trueCountLocal, int falseCountLocal) {
190 if (falseCountLocal == 0 && trueCountLocal == 0) {
191 /* Avoid division by zero if profile was never used. */
192 return 0.0;
193 } else {
194 return (double) trueCountLocal / (double) (trueCountLocal + falseCountLocal);
195 }
196 }
197
198 /* for testing */
199 long getTrueCount() {
200 return trueCount;
201 }
202
203 /* for testing */
204 int getFalseCount() {
205 return falseCount;
206 }
207
208 @Override
209 public String toString() {
210 return toString(LoopConditionProfile.class, falseCount == 0, false, //
211 String.format("trueProbability=%s (trueCount=%s, falseCount=%s)", calculateProbability(trueCount, falseCount), falseCount, trueCount));
212 }
213
214 /* Needed for lazy class loading. */
215 static LoopConditionProfile create() {
216 return new Enabled();
217 }
218
219 }
220
221 static final class Disabled extends LoopConditionProfile {
222
223 static final LoopConditionProfile INSTANCE = new Disabled();
224
225 @Override
226 protected Object clone() {
227 return INSTANCE;
228 }
229
230 @Override
231 public boolean profile(boolean condition) {
232 return condition;
233 }
234
235 @Override
236 public void profileCounted(long length) {
237 }
238
239 @Override
240 public boolean inject(boolean condition) {
241 return condition;
242 }
243
244 @Override
245 public String toString() {
246 return toStringDisabled(LoopConditionProfile.class);
247 }
248
249 }
250
251 }