1 /*
   2  * Copyright (c) 2012, 2012, 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 package jdk.vm.ci.meta;
  24 
  25 /**
  26  * Provides access to the profiling information of one specific method. Every accessor method
  27  * returns the information that is available at the time of invocation. If a method is invoked
  28  * multiple times, it may return significantly different results for every invocation as the
  29  * profiling information may be changed by other Java threads at any time.
  30  */
  31 public interface ProfilingInfo {
  32 
  33     /**
  34      * Returns the length of the bytecodes associated with this profile.
  35      */
  36     int getCodeSize();
  37 
  38     /**
  39      * Returns an estimate of how often the branch at the given byte code was taken.
  40      *
  41      * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if
  42      *         this information is not available.
  43      */
  44     double getBranchTakenProbability(int bci);
  45 
  46     /**
  47      * Returns an estimate of how often the switch cases are taken at the given BCI. The default
  48      * case is stored as the last entry.
  49      *
  50      * @return A double value that contains the estimated probabilities, with 0.0 meaning never and
  51      *         1.0 meaning always, or -1 if this information is not available.
  52      */
  53     double[] getSwitchProbabilities(int bci);
  54 
  55     /**
  56      * Returns the TypeProfile for the given BCI.
  57      *
  58      * @return Returns a JavaTypeProfile object, or null if not available.
  59      */
  60     JavaTypeProfile getTypeProfile(int bci);
  61 
  62     /**
  63      * Returns the MethodProfile for the given BCI.
  64      *
  65      * @return Returns a JavaMethodProfile object, or null if not available.
  66      */
  67     JavaMethodProfile getMethodProfile(int bci);
  68 
  69     /**
  70      * Returns information if the given BCI did ever throw an exception.
  71      *
  72      * @return {@link TriState#TRUE} if the instruction has thrown an exception at least once,
  73      *         {@link TriState#FALSE} if it never threw an exception, and {@link TriState#UNKNOWN}
  74      *         if this information was not recorded.
  75      */
  76     TriState getExceptionSeen(int bci);
  77 
  78     /**
  79      * Returns information if null was ever seen for the given BCI. This information is collected
  80      * for the aastore, checkcast and instanceof bytecodes.
  81      *
  82      * @return {@link TriState#TRUE} if null was seen for the instruction, {@link TriState#FALSE} if
  83      *         null was NOT seen, and {@link TriState#UNKNOWN} if this information was not recorded.
  84      */
  85     TriState getNullSeen(int bci);
  86 
  87     /**
  88      * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts
  89      * to each other, as the returned value highly depends on the time of invocation.
  90      *
  91      * @return the estimated execution count or -1 if not available.
  92      */
  93     int getExecutionCount(int bci);
  94 
  95     /**
  96      * Returns how frequently a method was deoptimized for the given deoptimization reason. This
  97      * only indicates how often the method did fall back to the interpreter for the execution and
  98      * does not indicate how often it was recompiled.
  99      *
 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 }