src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java
changeset 52578 7dd81e82d083
child 52910 583fd71c47d6
equal deleted inserted replaced
52577:5b87d3fc1093 52578:7dd81e82d083
       
     1 /*
       
     2  * Copyright (c) 2014, 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 
       
    24 
       
    25 package org.graalvm.compiler.phases.graph;
       
    26 
       
    27 import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyRelativeFrequencies;
       
    28 
       
    29 import java.util.function.ToDoubleFunction;
       
    30 
       
    31 import jdk.internal.vm.compiler.collections.EconomicMap;
       
    32 import jdk.internal.vm.compiler.collections.Equivalence;
       
    33 import org.graalvm.compiler.debug.CounterKey;
       
    34 import org.graalvm.compiler.debug.DebugContext;
       
    35 import org.graalvm.compiler.graph.Node;
       
    36 import org.graalvm.compiler.graph.NodeInputList;
       
    37 import org.graalvm.compiler.nodes.AbstractBeginNode;
       
    38 import org.graalvm.compiler.nodes.AbstractEndNode;
       
    39 import org.graalvm.compiler.nodes.AbstractMergeNode;
       
    40 import org.graalvm.compiler.nodes.ControlSplitNode;
       
    41 import org.graalvm.compiler.nodes.EndNode;
       
    42 import org.graalvm.compiler.nodes.FixedNode;
       
    43 import org.graalvm.compiler.nodes.LoopBeginNode;
       
    44 import org.graalvm.compiler.nodes.StartNode;
       
    45 
       
    46 /**
       
    47  * Compute relative frequencies for fixed nodes on the fly and cache them at
       
    48  * {@link AbstractBeginNode}s.
       
    49  */
       
    50 public class FixedNodeRelativeFrequencyCache implements ToDoubleFunction<FixedNode> {
       
    51 
       
    52     private static final CounterKey computeNodeRelativeFrequencyCounter = DebugContext.counter("ComputeNodeRelativeFrequency");
       
    53 
       
    54     private final EconomicMap<FixedNode, Double> cache = EconomicMap.create(Equivalence.IDENTITY);
       
    55 
       
    56     /**
       
    57      * <p>
       
    58      * Given a {@link FixedNode} this method finds the most immediate {@link AbstractBeginNode}
       
    59      * preceding it that either:
       
    60      * <ul>
       
    61      * <li>has no predecessor (ie, the begin-node is a merge, in particular a loop-begin, or the
       
    62      * start-node)</li>
       
    63      * <li>has a control-split predecessor</li>
       
    64      * </ul>
       
    65      * </p>
       
    66      *
       
    67      * <p>
       
    68      * The thus found {@link AbstractBeginNode} is equi-probable with the {@link FixedNode} it was
       
    69      * obtained from. When computed for the first time (afterwards a cache lookup returns it) that
       
    70      * relative frequency is computed as follows, again depending on the begin-node's predecessor:
       
    71      * <ul>
       
    72      * <li>No predecessor. In this case the begin-node is either:</li>
       
    73      * <ul>
       
    74      * <li>a merge-node, whose relative frequency adds up those of its forward-ends</li>
       
    75      * <li>a loop-begin, with frequency as above multiplied by the loop-frequency</li>
       
    76      * </ul>
       
    77      * <li>Control-split predecessor: frequency of the branch times that of the control-split</li>
       
    78      * </ul>
       
    79      * </p>
       
    80      *
       
    81      * <p>
       
    82      * As an exception to all the above, a frequency of 1 is assumed for a {@link FixedNode} that
       
    83      * appears to be dead-code (ie, lacks a predecessor).
       
    84      * </p>
       
    85      *
       
    86      */
       
    87     @Override
       
    88     public double applyAsDouble(FixedNode node) {
       
    89         assert node != null;
       
    90         computeNodeRelativeFrequencyCounter.increment(node.getDebug());
       
    91 
       
    92         FixedNode current = findBegin(node);
       
    93         if (current == null) {
       
    94             // this should only appear for dead code
       
    95             return 1D;
       
    96         }
       
    97 
       
    98         assert current instanceof AbstractBeginNode;
       
    99         Double cachedValue = cache.get(current);
       
   100         if (cachedValue != null) {
       
   101             return cachedValue;
       
   102         }
       
   103 
       
   104         double relativeFrequency = 0.0;
       
   105         if (current.predecessor() == null) {
       
   106             if (current instanceof AbstractMergeNode) {
       
   107                 relativeFrequency = handleMerge(current, relativeFrequency);
       
   108             } else {
       
   109                 assert current instanceof StartNode;
       
   110                 relativeFrequency = 1D;
       
   111             }
       
   112         } else {
       
   113             ControlSplitNode split = (ControlSplitNode) current.predecessor();
       
   114             relativeFrequency = multiplyRelativeFrequencies(split.probability((AbstractBeginNode) current), applyAsDouble(split));
       
   115         }
       
   116         assert !Double.isNaN(relativeFrequency) && !Double.isInfinite(relativeFrequency) : current + " " + relativeFrequency;
       
   117         cache.put(current, relativeFrequency);
       
   118         return relativeFrequency;
       
   119     }
       
   120 
       
   121     private double handleMerge(FixedNode current, double relativeFrequency) {
       
   122         double result = relativeFrequency;
       
   123         AbstractMergeNode currentMerge = (AbstractMergeNode) current;
       
   124         NodeInputList<EndNode> currentForwardEnds = currentMerge.forwardEnds();
       
   125         /*
       
   126          * Use simple iteration instead of streams, since the stream infrastructure adds many frames
       
   127          * which causes the recursion to overflow the stack earlier than it would otherwise.
       
   128          */
       
   129         for (AbstractEndNode endNode : currentForwardEnds) {
       
   130             result += applyAsDouble(endNode);
       
   131         }
       
   132         if (current instanceof LoopBeginNode) {
       
   133             result = multiplyRelativeFrequencies(result, ((LoopBeginNode) current).loopFrequency());
       
   134         }
       
   135         return result;
       
   136     }
       
   137 
       
   138     private static FixedNode findBegin(FixedNode node) {
       
   139         FixedNode current = node;
       
   140         while (true) {
       
   141             assert current != null;
       
   142             Node predecessor = current.predecessor();
       
   143             if (current instanceof AbstractBeginNode) {
       
   144                 if (predecessor == null) {
       
   145                     break;
       
   146                 } else if (predecessor.successors().count() != 1) {
       
   147                     assert predecessor instanceof ControlSplitNode : "a FixedNode with multiple successors needs to be a ControlSplitNode: " + current + " / " + predecessor;
       
   148                     break;
       
   149                 }
       
   150             } else if (predecessor == null) {
       
   151                 current = null;
       
   152                 break;
       
   153             }
       
   154             current = (FixedNode) predecessor;
       
   155         }
       
   156         return current;
       
   157     }
       
   158 }