--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java 2016-12-09 00:56:26.755713712 -0800 @@ -0,0 +1,127 @@ +/* + * 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.phases.contract; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import org.graalvm.compiler.core.common.cfg.BlockMap; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.VerificationError; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.nodes.spi.NodeCostProvider; +import org.graalvm.compiler.phases.schedule.SchedulePhase; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class NodeCostUtil { + + private static final DebugCounter sizeComputationCount = Debug.counter("GraphCostComputationCount_Size"); + private static final DebugCounter sizeVerificationCount = Debug.counter("GraphCostVerificationCount_Size"); + + @SuppressWarnings("try") + public static int computeGraphSize(StructuredGraph graph, NodeCostProvider nodeCostProvider) { + sizeComputationCount.increment(); + int size = 0; + for (Node n : graph.getNodes()) { + size += nodeCostProvider.getEstimatedCodeSize(n); + } + assert size >= 0; + return size; + } + + @SuppressWarnings("try") + public static double computeGraphCycles(StructuredGraph graph, NodeCostProvider nodeCostProvider, boolean fullSchedule) { + Function> blockToNodes; + ControlFlowGraph cfg; + if (fullSchedule) { + SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); + schedule.apply(graph); + cfg = graph.getLastSchedule().getCFG(); + blockToNodes = b -> graph.getLastSchedule().getBlockToNodesMap().get(b); + } else { + cfg = ControlFlowGraph.compute(graph, true, true, false, false); + BlockMap> nodes = new BlockMap<>(cfg); + for (Block b : cfg.getBlocks()) { + ArrayList curNodes = new ArrayList<>(); + for (FixedNode node : b.getNodes()) { + curNodes.add(node); + } + nodes.put(b, curNodes); + } + blockToNodes = b -> nodes.get(b); + } + double weightedCycles = 0D; + try (Debug.Scope s = Debug.scope("NodeCostSummary")) { + for (Block block : cfg.getBlocks()) { + for (Node n : blockToNodes.apply(block)) { + double probWeighted = nodeCostProvider.getEstimatedCPUCycles(n) * block.probability(); + assert Double.isFinite(probWeighted); + weightedCycles += probWeighted; + if (Debug.isLogEnabled()) { + Debug.log("Node %s contributes cycles:%f size:%d to graph %s [block prob:%f]", n, nodeCostProvider.getEstimatedCPUCycles(n) * block.probability(), + nodeCostProvider.getEstimatedCodeSize(n), graph, block.probability()); + } + } + } + } + assert weightedCycles >= 0D; + assert Double.isFinite(weightedCycles); + return weightedCycles; + } + + private static int deltaCompare(double a, double b, double delta) { + if (Math.abs(a - b) <= delta) { + return 0; + } + return Double.compare(a, b); + } + + /** + * Factor to control the "imprecision" of the before - after relation when verifying phase + * effects. If the cost model is perfect the best theoretical value is 0.0D (Ignoring the fact + * that profiling information is not reliable and thus the, probability based, profiling view on + * a graph is different than the reality). + */ + private static final double DELTA = 0.001D; + + public static void phaseFulfillsSizeContract(StructuredGraph graph, int codeSizeBefore, int codeSizeAfter, PhaseSizeContract contract) { + sizeVerificationCount.increment(); + final double codeSizeIncrease = contract.codeSizeIncrease(); + final double graphSizeDelta = codeSizeBefore * DELTA; + if (deltaCompare(codeSizeAfter, codeSizeBefore * codeSizeIncrease, graphSizeDelta) > 0) { + ResolvedJavaMethod method = graph.method(); + double increase = (double) codeSizeAfter / (double) codeSizeBefore; + throw new VerificationError("Phase %s expects to increase code size by at most a factor of %.2f but an increase of %.2f was seen (code size before: %d, after: %d)%s", + contract.contractorName(), codeSizeIncrease, increase, codeSizeBefore, codeSizeAfter, + method != null ? " when compiling method " + method.format("%H.%n(%p)") + "." : "."); + } + } + +}