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.phases.contract;
  24 
  25 import java.util.ArrayList;
  26 import java.util.List;
  27 import java.util.function.Function;
  28 
  29 import org.graalvm.compiler.core.common.cfg.BlockMap;
  30 import org.graalvm.compiler.debug.Debug;
  31 import org.graalvm.compiler.debug.DebugCounter;
  32 import org.graalvm.compiler.graph.Node;
  33 import org.graalvm.compiler.graph.VerificationError;
  34 import org.graalvm.compiler.nodes.FixedNode;
  35 import org.graalvm.compiler.nodes.StructuredGraph;
  36 import org.graalvm.compiler.nodes.cfg.Block;
  37 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
  38 import org.graalvm.compiler.phases.schedule.SchedulePhase;
  39 
  40 import jdk.vm.ci.meta.ResolvedJavaMethod;
  41 
  42 public class NodeCostUtil {
  43 
  44     private static final DebugCounter sizeComputationCount = Debug.counter("GraphCostComputationCount_Size");
  45     private static final DebugCounter sizeVerificationCount = Debug.counter("GraphCostVerificationCount_Size");
  46 
  47     @SuppressWarnings("try")
  48     public static int computeGraphSize(StructuredGraph graph) {
  49         sizeComputationCount.increment();
  50         int size = 0;
  51         for (Node n : graph.getNodes()) {
  52             size += n.estimatedNodeSize().value;
  53         }
  54         assert size >= 0;
  55         return size;
  56     }
  57 
  58     @SuppressWarnings("try")
  59     public static double computeGraphCycles(StructuredGraph graph, boolean fullSchedule) {
  60         Function<Block, Iterable<? extends Node>> blockToNodes;
  61         ControlFlowGraph cfg;
  62         if (fullSchedule) {
  63             SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true);
  64             schedule.apply(graph);
  65             cfg = graph.getLastSchedule().getCFG();
  66             blockToNodes = b -> graph.getLastSchedule().getBlockToNodesMap().get(b);
  67         } else {
  68             cfg = ControlFlowGraph.compute(graph, true, true, false, false);
  69             BlockMap<List<FixedNode>> nodes = new BlockMap<>(cfg);
  70             for (Block b : cfg.getBlocks()) {
  71                 ArrayList<FixedNode> curNodes = new ArrayList<>();
  72                 for (FixedNode node : b.getNodes()) {
  73                     curNodes.add(node);
  74                 }
  75                 nodes.put(b, curNodes);
  76             }
  77             blockToNodes = b -> nodes.get(b);
  78         }
  79         double weightedCycles = 0D;
  80         try (Debug.Scope s = Debug.scope("NodeCostSummary")) {
  81             for (Block block : cfg.getBlocks()) {
  82                 for (Node n : blockToNodes.apply(block)) {
  83                     double probWeighted = n.estimatedNodeCycles().value * block.probability();
  84                     assert Double.isFinite(probWeighted);
  85                     weightedCycles += probWeighted;
  86                     if (Debug.isLogEnabled()) {
  87                         Debug.log("Node %s contributes cycles:%f size:%d to graph %s [block prob:%f]", n, n.estimatedNodeCycles().value * block.probability(),
  88                                         n.estimatedNodeSize().value, graph, block.probability());
  89                     }
  90                 }
  91             }
  92         }
  93         assert weightedCycles >= 0D;
  94         assert Double.isFinite(weightedCycles);
  95         return weightedCycles;
  96     }
  97 
  98     private static int deltaCompare(double a, double b, double delta) {
  99         if (Math.abs(a - b) <= delta) {
 100             return 0;
 101         }
 102         return Double.compare(a, b);
 103     }
 104 
 105     /**
 106      * Factor to control the "imprecision" of the before - after relation when verifying phase
 107      * effects. If the cost model is perfect the best theoretical value is 0.0D (Ignoring the fact
 108      * that profiling information is not reliable and thus the, probability based, profiling view on
 109      * a graph is different than the reality).
 110      */
 111     private static final double DELTA = 0.001D;
 112 
 113     public static void phaseFulfillsSizeContract(StructuredGraph graph, int codeSizeBefore, int codeSizeAfter, PhaseSizeContract contract) {
 114         sizeVerificationCount.increment();
 115         final double codeSizeIncrease = contract.codeSizeIncrease();
 116         final double graphSizeDelta = codeSizeBefore * DELTA;
 117         if (deltaCompare(codeSizeAfter, codeSizeBefore * codeSizeIncrease, graphSizeDelta) > 0) {
 118             ResolvedJavaMethod method = graph.method();
 119             double increase = (double) codeSizeAfter / (double) codeSizeBefore;
 120             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",
 121                             contract.contractorName(), codeSizeIncrease, increase, codeSizeBefore, codeSizeAfter,
 122                             method != null ? " when compiling method " + method.format("%H.%n(%p)") + "." : ".");
 123         }
 124     }
 125 
 126 }