001/*
002 * Copyright (c) 2013, 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 com.oracle.graal.truffle;
024
025import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
026
027import java.util.*;
028
029public class CompilationProfile {
030
031    /**
032     * Number of times an installed code for this tree was invalidated.
033     */
034    private int invalidationCount;
035    private int deferedCount;
036
037    private int interpreterCallCount;
038    private int interpreterCallAndLoopCount;
039    private int compilationCallThreshold;
040    private int compilationCallAndLoopThreshold;
041
042    private long timestamp;
043
044    public CompilationProfile() {
045        compilationCallThreshold = TruffleMinInvokeThreshold.getValue();
046        compilationCallAndLoopThreshold = TruffleCompilationThreshold.getValue();
047    }
048
049    @Override
050    public String toString() {
051        return String.format("CompilationProfile(callCount=%d/%d, callAndLoopCount=%d/%d)", interpreterCallCount, compilationCallThreshold, interpreterCallAndLoopCount,
052                        compilationCallAndLoopThreshold);
053    }
054
055    public Map<String, Object> getDebugProperties() {
056        Map<String, Object> properties = new LinkedHashMap<>();
057        String callsThreshold = String.format("%7d/%5d", getInterpreterCallCount(), getCompilationCallThreshold());
058        String loopsThreshold = String.format("%7d/%5d", getInterpreterCallAndLoopCount(), getCompilationCallAndLoopThreshold());
059        String invalidations = String.format("%5d", invalidationCount);
060        properties.put("Calls/Thres", callsThreshold);
061        properties.put("CallsAndLoop/Thres", loopsThreshold);
062        properties.put("Inval#", invalidations);
063        return properties;
064    }
065
066    public int getInvalidationCount() {
067        return invalidationCount;
068    }
069
070    public int getInterpreterCallAndLoopCount() {
071        return interpreterCallAndLoopCount;
072    }
073
074    public int getInterpreterCallCount() {
075        return interpreterCallCount;
076    }
077
078    public int getDeferedCount() {
079        return deferedCount;
080    }
081
082    public int getCompilationCallAndLoopThreshold() {
083        return compilationCallAndLoopThreshold;
084    }
085
086    public int getCompilationCallThreshold() {
087        return compilationCallThreshold;
088    }
089
090    void ensureProfiling(int calls, int callsAndLoop) {
091        int increaseCallAndLoopThreshold = callsAndLoop - (this.compilationCallAndLoopThreshold - this.interpreterCallAndLoopCount);
092        if (increaseCallAndLoopThreshold > 0) {
093            this.compilationCallAndLoopThreshold += increaseCallAndLoopThreshold;
094        }
095
096        int increaseCallsThreshold = calls - (this.compilationCallThreshold - this.interpreterCallCount);
097        if (increaseCallsThreshold > 0) {
098            this.compilationCallThreshold += increaseCallsThreshold;
099        }
100    }
101
102    public void reportInvalidated() {
103        invalidationCount++;
104        int reprofile = TruffleInvalidationReprofileCount.getValue();
105        ensureProfiling(reprofile, reprofile);
106    }
107
108    public void reportInterpreterCall() {
109        interpreterCallCount++;
110        interpreterCallAndLoopCount++;
111
112        int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount;
113        if (callsMissing == getTimestampThreshold()) {
114            timestamp = System.nanoTime();
115        }
116    }
117
118    public void reportDirectCall() {
119
120    }
121
122    public void reportIndirectCall() {
123
124    }
125
126    public void reportInlinedCall() {
127
128    }
129
130    public void deferCompilation() {
131        ensureProfiling(0, getTimestampThreshold() + 1);
132        timestamp = 0;
133        deferedCount++;
134    }
135
136    void reportLoopCount(int count) {
137        interpreterCallAndLoopCount += count;
138
139        int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount;
140        if (callsMissing <= getTimestampThreshold() && callsMissing + count > getTimestampThreshold()) {
141            timestamp = System.nanoTime();
142        }
143    }
144
145    void reportNodeReplaced() {
146        // delay compilation until tree is deemed stable enough
147        int replaceBackoff = TruffleReplaceReprofileCount.getValue();
148        ensureProfiling(1, replaceBackoff);
149    }
150
151    public long getTimestamp() {
152        return timestamp;
153    }
154
155    private static int getTimestampThreshold() {
156        return Math.max(TruffleCompilationThreshold.getValue() / 2, 1);
157    }
158}