1 /* 2 * Copyright (c) 2011, 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 */ 23 package org.graalvm.compiler.phases; 24 25 import java.util.regex.Pattern; 26 27 import org.graalvm.compiler.debug.Debug; 28 import org.graalvm.compiler.debug.Debug.Scope; 29 import org.graalvm.compiler.debug.DebugCloseable; 30 import org.graalvm.compiler.debug.DebugCounter; 31 import org.graalvm.compiler.debug.DebugMemUseTracker; 32 import org.graalvm.compiler.debug.DebugTimer; 33 import org.graalvm.compiler.debug.Fingerprint; 34 import org.graalvm.compiler.graph.Graph; 35 import org.graalvm.compiler.graph.Graph.Mark; 36 import org.graalvm.compiler.nodes.StructuredGraph; 37 import org.graalvm.compiler.options.Option; 38 import org.graalvm.compiler.options.OptionType; 39 import org.graalvm.compiler.options.OptionValue; 40 import org.graalvm.compiler.options.StableOptionValue; 41 import org.graalvm.compiler.phases.contract.NodeCostUtil; 42 import org.graalvm.compiler.phases.contract.PhaseSizeContract; 43 import org.graalvm.compiler.phases.tiers.PhaseContext; 44 45 /** 46 * Base class for all compiler phases. Subclasses should be stateless. There will be one global 47 * instance for each compiler phase that is shared for all compilations. VM-, target- and 48 * compilation-specific data can be passed with a context object. 49 */ 50 public abstract class BasePhase<C> implements PhaseSizeContract { 51 52 public static class PhaseOptions { 53 // @formatter:off 54 @Option(help = "Verify before - after relation of the relative, computed, code size of a graph", type = OptionType.Debug) 55 public static final OptionValue<Boolean> VerifyGraalPhasesSize = new StableOptionValue<>(false); 56 // @formatter:on 57 } 58 59 /** 60 * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}. 61 */ 62 private final DebugTimer timer; 63 64 /** 65 * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}. 66 */ 67 private final DebugCounter executionCount; 68 69 /** 70 * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to 71 * {@link #apply(StructuredGraph, Object, boolean)}. 72 */ 73 private final DebugCounter inputNodesCount; 74 75 /** 76 * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}. 77 */ 78 private final DebugMemUseTracker memUseTracker; 79 80 /** Lazy initialization to create pattern only when assertions are enabled. */ 81 static class NamePatternHolder { 82 static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+"); 83 } 84 85 private static class BasePhaseStatistics { 86 /** 87 * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}. 88 */ 89 private final DebugTimer timer; 90 91 /** 92 * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}. 93 */ 94 private final DebugCounter executionCount; 95 96 /** 97 * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to 98 * {@link #apply(StructuredGraph, Object, boolean)}. 99 */ 100 private final DebugCounter inputNodesCount; 101 102 /** 103 * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}. 104 */ 105 private final DebugMemUseTracker memUseTracker; 106 107 BasePhaseStatistics(Class<?> clazz) { 108 timer = Debug.timer("PhaseTime_%s", clazz); 109 executionCount = Debug.counter("PhaseCount_%s", clazz); 110 memUseTracker = Debug.memUseTracker("PhaseMemUse_%s", clazz); 111 inputNodesCount = Debug.counter("PhaseNodes_%s", clazz); 112 } 113 } 114 115 private static final ClassValue<BasePhaseStatistics> statisticsClassValue = new ClassValue<BasePhaseStatistics>() { 116 @Override 117 protected BasePhaseStatistics computeValue(Class<?> c) { 118 return new BasePhaseStatistics(c); 119 } 120 }; 121 122 protected BasePhase() { 123 BasePhaseStatistics statistics = statisticsClassValue.get(getClass()); 124 timer = statistics.timer; 125 executionCount = statistics.executionCount; 126 memUseTracker = statistics.memUseTracker; 127 inputNodesCount = statistics.inputNodesCount; 128 } 129 130 public final void apply(final StructuredGraph graph, final C context) { 131 apply(graph, context, true); 132 } 133 134 @SuppressWarnings("try") 135 protected final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { 136 try (DebugCloseable a = timer.start(); Scope s = Debug.scope(getClass(), this); DebugCloseable c = memUseTracker.start()) { 137 int sizeBefore = 0; 138 Mark before = null; 139 if (PhaseOptions.VerifyGraalPhasesSize.getValue() && checkContract()) { 140 if (context instanceof PhaseContext) { 141 sizeBefore = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider()); 142 before = graph.getMark(); 143 } 144 } 145 if (dumpGraph && Debug.isDumpEnabled(Debug.VERBOSE_LOG_LEVEL)) { 146 Debug.dump(Debug.VERBOSE_LOG_LEVEL, graph, "Before phase %s", getName()); 147 } 148 inputNodesCount.add(graph.getNodeCount()); 149 this.run(graph, context); 150 executionCount.increment(); 151 if (PhaseOptions.VerifyGraalPhasesSize.getValue() && checkContract()) { 152 if (context instanceof PhaseContext) { 153 if (!before.isCurrent()) { 154 int sizeAfter = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider()); 155 NodeCostUtil.phaseFulfillsSizeContract(graph, sizeBefore, sizeAfter, this); 156 } 157 } 158 } 159 if (dumpGraph && Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { 160 Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", getName()); 161 } 162 if (Fingerprint.ENABLED) { 163 String graphDesc = graph.method() == null ? graph.name : graph.method().format("%H.%n(%p)"); 164 Fingerprint.submit("After phase %s nodes in %s are %s", getName(), graphDesc, graph.getNodes().snapshot()); 165 } 166 if (Debug.isVerifyEnabled()) { 167 Debug.verify(graph, "%s", getName()); 168 } 169 assert graph.verify(); 170 } catch (Throwable t) { 171 throw Debug.handle(t); 172 } 173 } 174 175 protected CharSequence getName() { 176 String className = BasePhase.this.getClass().getName(); 177 String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name 178 int innerClassPos = s.indexOf('$'); 179 if (innerClassPos > 0) { 180 /* Remove inner class name. */ 181 s = s.substring(0, innerClassPos); 182 } 183 if (s.endsWith("Phase")) { 184 s = s.substring(0, s.length() - "Phase".length()); 185 } 186 return s; 187 } 188 189 protected abstract void run(StructuredGraph graph, C context); 190 191 @Override 192 public String contractorName() { 193 return (String) getName(); 194 } 195 196 @Override 197 public float codeSizeIncrease() { 198 return 1.25f; 199 } 200 201 }