1 /* 2 * Copyright (c) 2016, 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.hotspot.phases.profiling; 24 25 import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode.getProfileInvokeNodes; 26 import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode.getProfileNodes; 27 28 import java.util.HashMap; 29 import java.util.Map; 30 31 import org.graalvm.compiler.core.common.cfg.Loop; 32 import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; 33 import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; 34 import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode; 35 import org.graalvm.compiler.nodes.ConstantNode; 36 import org.graalvm.compiler.nodes.InvokeNode; 37 import org.graalvm.compiler.nodes.LoopBeginNode; 38 import org.graalvm.compiler.nodes.PhiNode; 39 import org.graalvm.compiler.nodes.ValuePhiNode; 40 import org.graalvm.compiler.nodes.StructuredGraph; 41 import org.graalvm.compiler.nodes.ValueNode; 42 import org.graalvm.compiler.nodes.calc.AddNode; 43 import org.graalvm.compiler.nodes.calc.MulNode; 44 import org.graalvm.compiler.nodes.cfg.Block; 45 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 46 import org.graalvm.compiler.nodes.util.GraphUtil; 47 import org.graalvm.compiler.options.Option; 48 import org.graalvm.compiler.options.OptionType; 49 import org.graalvm.compiler.options.OptionValue; 50 import org.graalvm.compiler.phases.BasePhase; 51 import org.graalvm.compiler.phases.tiers.PhaseContext; 52 53 import jdk.vm.ci.meta.ResolvedJavaMethod; 54 55 public class FinalizeProfileNodesPhase extends BasePhase<PhaseContext> { 56 private int inlineeInvokeNotificationFreqLog; 57 58 public static class Options { 59 @Option(help = "Profile simple methods", type = OptionType.Expert)// 60 public static final OptionValue<Boolean> ProfileSimpleMethods = new OptionValue<>(true); 61 @Option(help = "Maximum number of nodes in a graph for a simple method", type = OptionType.Expert)// 62 public static final OptionValue<Integer> SimpleMethodGraphSize = new OptionValue<>(256); 63 @Option(help = "Maximum number of calls in a simple method", type = OptionType.Expert)// 64 public static final OptionValue<Integer> SimpleMethodCalls = new OptionValue<>(1); 65 @Option(help = "Maximum number of indirect calls in a simple moethod", type = OptionType.Expert)// 66 public static final OptionValue<Integer> SimpleMethodIndirectCalls = new OptionValue<>(0); 67 68 } 69 70 public FinalizeProfileNodesPhase(int inlineeInvokeNotificationFreqLog) { 71 this.inlineeInvokeNotificationFreqLog = inlineeInvokeNotificationFreqLog; 72 } 73 74 private static void removeAllProfilingNodes(StructuredGraph graph) { 75 getProfileNodes(graph).forEach((n) -> GraphUtil.removeFixedWithUnusedInputs(n)); 76 } 77 78 private void assignInlineeInvokeFrequencies(StructuredGraph graph) { 79 for (ProfileInvokeNode node : getProfileInvokeNodes(graph)) { 80 ResolvedJavaMethod profiledMethod = node.getProfiledMethod(); 81 if (!profiledMethod.equals(graph.method())) { 82 // Some inlinee, reassign the inlinee frequency 83 node.setNotificationFreqLog(inlineeInvokeNotificationFreqLog); 84 } 85 } 86 } 87 88 // Hacky heuristic to determine whether we want any profiling in this method. 89 // The heuristic is applied after the graph is fully formed and before the first lowering. 90 private static boolean simpleMethodHeuristic(StructuredGraph graph) { 91 if (Options.ProfileSimpleMethods.getValue()) { 92 return false; 93 } 94 95 // Check if the graph is smallish.. 96 if (graph.getNodeCount() > Options.SimpleMethodGraphSize.getValue()) { 97 return false; 98 } 99 100 // Check if method has loops 101 if (graph.hasLoops()) { 102 return false; 103 } 104 105 // Check if method has calls 106 if (graph.getNodes().filter(InvokeNode.class).count() > Options.SimpleMethodCalls.getValue()) { 107 return false; 108 } 109 110 // Check if method has calls that need profiling 111 if (graph.getNodes().filter(InvokeNode.class).filter((n) -> ((InvokeNode) n).getInvokeKind().isIndirect()).count() > Options.SimpleMethodIndirectCalls.getDefaultValue()) { 112 return false; 113 } 114 115 return true; 116 } 117 118 private static void assignRandomSources(StructuredGraph graph) { 119 ValueNode seed = graph.unique(new RandomSeedNode()); 120 ControlFlowGraph cfg = ControlFlowGraph.compute(graph, false, true, false, false); 121 Map<LoopBeginNode, ValueNode> loopRandomValueCache = new HashMap<>(); 122 123 for (ProfileNode node : getProfileNodes(graph)) { 124 ValueNode random; 125 Block block = cfg.blockFor(node); 126 Loop<Block> loop = block.getLoop(); 127 // Inject <a href=https://en.wikipedia.org/wiki/Linear_congruential_generator>LCG</a> 128 // pseudo-random number generator into the loop 129 if (loop != null) { 130 LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode(); 131 random = loopRandomValueCache.get(loopBegin); 132 if (random == null) { 133 PhiNode phi = graph.addWithoutUnique(new ValuePhiNode(seed.stamp(), loopBegin)); 134 phi.addInput(seed); 135 // X_{n+1} = a*X_n + c, using glibc-like constants 136 ValueNode a = ConstantNode.forInt(1103515245, graph); 137 ValueNode c = ConstantNode.forInt(12345, graph); 138 ValueNode next = graph.addOrUniqueWithInputs(new AddNode(c, new MulNode(phi, a))); 139 for (int i = 0; i < loopBegin.getLoopEndCount(); i++) { 140 phi.addInput(next); 141 } 142 random = phi; 143 loopRandomValueCache.put(loopBegin, random); 144 } 145 } else { 146 // Graal doesn't compile methods with irreducible loops. So all profile nodes that 147 // are not in a loop are guaranteed to be executed at most once. We feed the seed 148 // value to such nodes directly. 149 random = seed; 150 } 151 node.setRandom(random); 152 } 153 } 154 155 @Override 156 protected void run(StructuredGraph graph, PhaseContext context) { 157 if (simpleMethodHeuristic(graph)) { 158 removeAllProfilingNodes(graph); 159 return; 160 } 161 162 assignInlineeInvokeFrequencies(graph); 163 if (ProfileNode.Options.ProbabilisticProfiling.getValue()) { 164 assignRandomSources(graph); 165 } 166 } 167 168 @Override 169 public boolean checkContract() { 170 return false; 171 } 172 }