--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java 2016-12-07 13:50:37.511436048 -0800 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.phases.profiling; + +import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode.getProfileInvokeNodes; +import static org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode.getProfileNodes; + +import java.util.HashMap; +import java.util.Map; + +import org.graalvm.compiler.core.common.cfg.Loop; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileInvokeNode; +import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode; +import org.graalvm.compiler.hotspot.nodes.profiling.RandomSeedNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.ValuePhiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.MulNode; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class FinalizeProfileNodesPhase extends BasePhase { + private int inlineeInvokeNotificationFreqLog; + + public static class Options { + @Option(help = "Profile simple methods", type = OptionType.Expert)// + public static final OptionValue ProfileSimpleMethods = new OptionValue<>(true); + @Option(help = "Maximum number of nodes in a graph for a simple method", type = OptionType.Expert)// + public static final OptionValue SimpleMethodGraphSize = new OptionValue<>(256); + @Option(help = "Maximum number of calls in a simple method", type = OptionType.Expert)// + public static final OptionValue SimpleMethodCalls = new OptionValue<>(1); + @Option(help = "Maximum number of indirect calls in a simple moethod", type = OptionType.Expert)// + public static final OptionValue SimpleMethodIndirectCalls = new OptionValue<>(0); + + } + + public FinalizeProfileNodesPhase(int inlineeInvokeNotificationFreqLog) { + this.inlineeInvokeNotificationFreqLog = inlineeInvokeNotificationFreqLog; + } + + private static void removeAllProfilingNodes(StructuredGraph graph) { + getProfileNodes(graph).forEach((n) -> GraphUtil.removeFixedWithUnusedInputs(n)); + } + + private void assignInlineeInvokeFrequencies(StructuredGraph graph) { + for (ProfileInvokeNode node : getProfileInvokeNodes(graph)) { + ResolvedJavaMethod profiledMethod = node.getProfiledMethod(); + if (!profiledMethod.equals(graph.method())) { + // Some inlinee, reassign the inlinee frequency + node.setNotificationFreqLog(inlineeInvokeNotificationFreqLog); + } + } + } + + // Hacky heuristic to determine whether we want any profiling in this method. + // The heuristic is applied after the graph is fully formed and before the first lowering. + private static boolean simpleMethodHeuristic(StructuredGraph graph) { + if (Options.ProfileSimpleMethods.getValue()) { + return false; + } + + // Check if the graph is smallish.. + if (graph.getNodeCount() > Options.SimpleMethodGraphSize.getValue()) { + return false; + } + + // Check if method has loops + if (graph.hasLoops()) { + return false; + } + + // Check if method has calls + if (graph.getNodes().filter(InvokeNode.class).count() > Options.SimpleMethodCalls.getValue()) { + return false; + } + + // Check if method has calls that need profiling + if (graph.getNodes().filter(InvokeNode.class).filter((n) -> ((InvokeNode) n).getInvokeKind().isIndirect()).count() > Options.SimpleMethodIndirectCalls.getDefaultValue()) { + return false; + } + + return true; + } + + private static void assignRandomSources(StructuredGraph graph) { + ValueNode seed = graph.unique(new RandomSeedNode()); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, false, true, false, false); + Map loopRandomValueCache = new HashMap<>(); + + for (ProfileNode node : getProfileNodes(graph)) { + ValueNode random; + Block block = cfg.blockFor(node); + Loop loop = block.getLoop(); + // Inject LCG + // pseudo-random number generator into the loop + if (loop != null) { + LoopBeginNode loopBegin = (LoopBeginNode) loop.getHeader().getBeginNode(); + random = loopRandomValueCache.get(loopBegin); + if (random == null) { + PhiNode phi = graph.addWithoutUnique(new ValuePhiNode(seed.stamp(), loopBegin)); + phi.addInput(seed); + // X_{n+1} = a*X_n + c, using glibc-like constants + ValueNode a = ConstantNode.forInt(1103515245, graph); + ValueNode c = ConstantNode.forInt(12345, graph); + ValueNode next = graph.addOrUniqueWithInputs(new AddNode(c, new MulNode(phi, a))); + for (int i = 0; i < loopBegin.getLoopEndCount(); i++) { + phi.addInput(next); + } + random = phi; + loopRandomValueCache.put(loopBegin, random); + } + } else { + // Graal doesn't compile methods with irreducible loops. So all profile nodes that + // are not in a loop are guaranteed to be executed at most once. We feed the seed + // value to such nodes directly. + random = seed; + } + node.setRandom(random); + } + } + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + if (simpleMethodHeuristic(graph)) { + removeAllProfilingNodes(graph); + return; + } + + assignInlineeInvokeFrequencies(graph); + if (ProfileNode.Options.ProbabilisticProfiling.getValue()) { + assignRandomSources(graph); + } + } + + @Override + public boolean checkContract() { + return false; + } +}