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.nodes.spi;
  24 
  25 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
  26 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
  27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
  28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  29 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
  30 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
  31 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
  32 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_40;
  33 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
  34 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
  35 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
  36 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
  37 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_15;
  38 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  39 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_200;
  40 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
  41 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
  42 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
  43 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
  44 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_80;
  45 
  46 import org.graalvm.compiler.graph.Node;
  47 import org.graalvm.compiler.nodeinfo.NodeCycles;
  48 import org.graalvm.compiler.nodeinfo.NodeSize;
  49 import org.graalvm.compiler.nodes.CallTargetNode;
  50 import org.graalvm.compiler.nodes.Invoke;
  51 import org.graalvm.compiler.nodes.LoopEndNode;
  52 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
  53 import org.graalvm.compiler.nodes.extended.SwitchNode;
  54 import org.graalvm.compiler.nodes.java.AccessFieldNode;
  55 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
  56 
  57 /*
  58  * Certain node costs can not, based on the meta information encoded in the node properties,
  59  * be computed before a real node is instantiated. E.g. the type of a call in Java heavily
  60  * influences the cost of an invocation and thus must be decided dynamically.
  61  */
  62 public abstract class DefaultNodeCostProvider implements NodeCostProvider {
  63 
  64     @Override
  65     public final int getEstimatedCodeSize(Node n) {
  66         return size(n).estimatedCodeSize;
  67     }
  68 
  69     @Override
  70     public final int getEstimatedCPUCycles(Node n) {
  71         return cycles(n).estimatedCPUCycles;
  72     }
  73 
  74     @Override
  75     public NodeSize size(Node n) {
  76         if (n instanceof Invoke) {
  77             /*
  78              * Code size for the invoke itself is a very weak approximation.
  79              */
  80             Invoke ivk = (Invoke) n;
  81             CallTargetNode mct = ivk.callTarget();
  82             switch (mct.invokeKind()) {
  83                 case Interface:
  84                     return SIZE_50;
  85                 case Special:
  86                 case Static:
  87                     return SIZE_2;
  88                 case Virtual:
  89                     return SIZE_4;
  90                 default:
  91                     break;
  92             }
  93         } else if (n instanceof CommitAllocationNode) {
  94             CommitAllocationNode commit = (CommitAllocationNode) n;
  95             /*
  96              * very weak approximation, current problem is node size is an enum and we cannot
  97              * dynamically instantiate a new case like nrOfAllocs*allocationCodeSize
  98              */
  99             int nrOfAllocs = commit.getVirtualObjects().size();
 100             if (nrOfAllocs < 5) {
 101                 return SIZE_80;
 102             } else if (nrOfAllocs < 10) {
 103                 return SIZE_100;
 104             } else {
 105                 return SIZE_200;
 106             }
 107         } else if (n instanceof AccessFieldNode) {
 108             if (((AccessFieldNode) n).field().isVolatile()) {
 109                 // membar size is added
 110                 return SIZE_10;
 111             }
 112         } else if (n instanceof LoopEndNode) {
 113             if (((LoopEndNode) n).canSafepoint()) {
 114                 return SIZE_6;
 115             }
 116         } else if (n instanceof SwitchNode) {
 117             SwitchNode x = (SwitchNode) n;
 118             int keyCount = x.keyCount();
 119             if (keyCount == 0) {
 120                 return SIZE_1;
 121             } else {
 122                 if (keyCount == 1) {
 123                     // if
 124                     return SIZE_2;
 125                 } else if (x instanceof IntegerSwitchNode && x.isSorted()) {
 126                     // good heuristic
 127                     return SIZE_15;
 128                 } else {
 129                     // not so good
 130                     return SIZE_30;
 131                 }
 132             }
 133         }
 134 
 135         return n.getNodeClass().size();
 136     }
 137 
 138     @Override
 139     public NodeCycles cycles(Node n) {
 140         if (n instanceof Invoke) {
 141             Invoke ivk = (Invoke) n;
 142             CallTargetNode mct = ivk.callTarget();
 143             switch (mct.invokeKind()) {
 144                 case Interface:
 145                     return CYCLES_100;
 146                 case Special:
 147                 case Static:
 148                     return CYCLES_2;
 149                 case Virtual:
 150                     return CYCLES_4;
 151                 default:
 152                     break;
 153             }
 154         } else if (n instanceof CommitAllocationNode) {
 155             CommitAllocationNode commit = (CommitAllocationNode) n;
 156             /*
 157              * very weak approximation, current problem is node cycles is an enum and we cannot
 158              * dynamically instantiate a new case like nrOfAllocs*allocationCost
 159              */
 160             int nrOfAllocs = commit.getVirtualObjects().size();
 161             if (nrOfAllocs < 5) {
 162                 return CYCLES_20;
 163             } else if (nrOfAllocs < 10) {
 164                 return CYCLES_40;
 165             } else {
 166                 return CYCLES_80;
 167             }
 168         } else if (n instanceof AccessFieldNode) {
 169             if (((AccessFieldNode) n).field().isVolatile()) {
 170                 // membar cycles is added
 171                 return CYCLES_30;
 172             }
 173         } else if (n instanceof SwitchNode) {
 174             SwitchNode x = (SwitchNode) n;
 175             int keyCount = x.keyCount();
 176             if (keyCount == 0) {
 177                 return CYCLES_1;
 178             } else {
 179                 if (keyCount == 1) {
 180                     // if
 181                     return CYCLES_2;
 182                 } else if (x instanceof IntegerSwitchNode && x.isSorted()) {
 183                     // good heuristic
 184                     return CYCLES_15;
 185                 } else {
 186                     // not so good
 187                     return CYCLES_30;
 188                 }
 189             }
 190         }
 191 
 192         return n.getNodeClass().cycles();
 193     }
 194 
 195 }