001/*
002 * Copyright (c) 2012, 2012, 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 jdk.internal.jvmci.meta;
024
025/**
026 * Provides access to the profiling information of one specific method. Every accessor method
027 * returns the information that is available at the time of invocation. If a method is invoked
028 * multiple times, it may return significantly different results for every invocation as the
029 * profiling information may be changed by other Java threads at any time.
030 */
031public interface ProfilingInfo {
032
033    /**
034     * Returns the length of the bytecodes associated with this profile.
035     */
036    int getCodeSize();
037
038    /**
039     * Returns an estimate of how often the branch at the given byte code was taken.
040     *
041     * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if
042     *         this information is not available.
043     */
044    double getBranchTakenProbability(int bci);
045
046    /**
047     * Returns an estimate of how often the switch cases are taken at the given BCI. The default
048     * case is stored as the last entry.
049     *
050     * @return A double value that contains the estimated probabilities, with 0.0 meaning never and
051     *         1.0 meaning always, or -1 if this information is not available.
052     */
053    double[] getSwitchProbabilities(int bci);
054
055    /**
056     * Returns the TypeProfile for the given BCI.
057     *
058     * @return Returns a JavaTypeProfile object, or null if not available.
059     */
060    JavaTypeProfile getTypeProfile(int bci);
061
062    /**
063     * Returns the MethodProfile for the given BCI.
064     *
065     * @return Returns a JavaMethodProfile object, or null if not available.
066     */
067    JavaMethodProfile getMethodProfile(int bci);
068
069    /**
070     * Returns information if the given BCI did ever throw an exception.
071     *
072     * @return {@link TriState#TRUE} if the instruction has thrown an exception at least once,
073     *         {@link TriState#FALSE} if it never threw an exception, and {@link TriState#UNKNOWN}
074     *         if this information was not recorded.
075     */
076    TriState getExceptionSeen(int bci);
077
078    /**
079     * Returns information if null was ever seen for the given BCI. This information is collected
080     * for the aastore, checkcast and instanceof bytecodes.
081     *
082     * @return {@link TriState#TRUE} if null was seen for the instruction, {@link TriState#FALSE} if
083     *         null was NOT seen, and {@link TriState#UNKNOWN} if this information was not recorded.
084     */
085    TriState getNullSeen(int bci);
086
087    /**
088     * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts
089     * to each other, as the returned value highly depends on the time of invocation.
090     *
091     * @return the estimated execution count or -1 if not available.
092     */
093    int getExecutionCount(int bci);
094
095    /**
096     * Returns how frequently a method was deoptimized for the given deoptimization reason. This
097     * only indicates how often the method did fall back to the interpreter for the execution and
098     * does not indicate how often it was recompiled.
099     *
100     * @param reason the reason for which the number of deoptimizations should be queried
101     * @return the number of times the compiled method deoptimized for the given reason.
102     */
103    int getDeoptimizationCount(DeoptimizationReason reason);
104
105    /**
106     * Records the size of the compiler intermediate representation (IR) associated with this
107     * method.
108     *
109     * @param irType the IR type for which the size is being recorded
110     * @param irSize the IR size to be recorded. The unit depends on the IR.
111     * @return whether recording this information for {@code irType} is supported
112     */
113    boolean setCompilerIRSize(Class<?> irType, int irSize);
114
115    /**
116     * Gets the size of the compiler intermediate representation (IR) associated with this method
117     * last recorded by {@link #setCompilerIRSize(Class, int)}.
118     *
119     * @param irType the IR type for which the size is being requested
120     * @return the requested IR size or -1 if it is unavailable for {@code irType}
121     */
122    int getCompilerIRSize(Class<?> irType);
123
124    /**
125     * Returns true if the profiling information can be assumed as sufficiently accurate.
126     *
127     * @return true if the profiling information was recorded often enough mature enough, false
128     *         otherwise.
129     */
130    boolean isMature();
131
132    /**
133     * Force data to be treated as mature if possible.
134     */
135    void setMature();
136
137    /**
138     * Formats this profiling information to a string.
139     *
140     * @param method an optional method that augments the profile string returned
141     * @param sep the separator to use for each separate profile record
142     */
143    default String toString(ResolvedJavaMethod method, String sep) {
144        StringBuilder buf = new StringBuilder(100);
145        if (method != null) {
146            buf.append(String.format("canBeStaticallyBound: %b%s", method.canBeStaticallyBound(), sep));
147        }
148        for (int i = 0; i < getCodeSize(); i++) {
149            if (getExecutionCount(i) != -1) {
150                buf.append(String.format("executionCount@%d: %d%s", i, getExecutionCount(i), sep));
151            }
152
153            if (getBranchTakenProbability(i) != -1) {
154                buf.append(String.format("branchProbability@%d: %.6f%s", i, getBranchTakenProbability(i), sep));
155            }
156
157            double[] switchProbabilities = getSwitchProbabilities(i);
158            if (switchProbabilities != null) {
159                buf.append(String.format("switchProbabilities@%d:", i));
160                for (int j = 0; j < switchProbabilities.length; j++) {
161                    buf.append(String.format(" %.6f", switchProbabilities[j]));
162                }
163                buf.append(sep);
164            }
165
166            if (getExceptionSeen(i) != TriState.UNKNOWN) {
167                buf.append(String.format("exceptionSeen@%d: %s%s", i, getExceptionSeen(i).name(), sep));
168            }
169
170            if (getNullSeen(i) != TriState.UNKNOWN) {
171                buf.append(String.format("nullSeen@%d: %s%s", i, getNullSeen(i).name(), sep));
172            }
173
174            JavaTypeProfile typeProfile = getTypeProfile(i);
175            MetaUtil.appendProfile(buf, typeProfile, i, "types", sep);
176
177            JavaMethodProfile methodProfile = getMethodProfile(i);
178            MetaUtil.appendProfile(buf, methodProfile, i, "methods", sep);
179        }
180
181        boolean firstDeoptReason = true;
182        for (DeoptimizationReason reason : DeoptimizationReason.values()) {
183            int count = getDeoptimizationCount(reason);
184            if (count > 0) {
185                if (firstDeoptReason) {
186                    buf.append("deoptimization history").append(sep);
187                    firstDeoptReason = false;
188                }
189                buf.append(String.format(" %s: %d%s", reason.name(), count, sep));
190            }
191        }
192        if (buf.length() == 0) {
193            return "";
194        }
195        String s = buf.toString();
196        return s.substring(0, s.length() - sep.length());
197    }
198
199}