/*
* 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.nodes.spi;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_100;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_15;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_20;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_30;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_40;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_80;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_10;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_100;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_15;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_200;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_50;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_6;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_80;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeSize;
import org.graalvm.compiler.nodes.CallTargetNode;
import org.graalvm.compiler.nodes.Invoke;
import org.graalvm.compiler.nodes.LoopEndNode;
import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
import org.graalvm.compiler.nodes.extended.SwitchNode;
import org.graalvm.compiler.nodes.java.AccessFieldNode;
import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
/*
* Certain node costs can not, based on the meta information encoded in the node properties,
* be computed before a real node is instantiated. E.g. the type of a call in Java heavily
* influences the cost of an invocation and thus must be decided dynamically.
*/
public abstract class DefaultNodeCostProvider implements NodeCostProvider {
@Override
public final int getEstimatedCodeSize(Node n) {
return size(n).estimatedCodeSize;
}
@Override
public final int getEstimatedCPUCycles(Node n) {
return cycles(n).estimatedCPUCycles;
}
@Override
public NodeSize size(Node n) {
if (n instanceof Invoke) {
/*
* Code size for the invoke itself is a very weak approximation.
*/
Invoke ivk = (Invoke) n;
CallTargetNode mct = ivk.callTarget();
switch (mct.invokeKind()) {
case Interface:
return SIZE_50;
case Special:
case Static:
return SIZE_2;
case Virtual:
return SIZE_4;
default:
break;
}
} else if (n instanceof CommitAllocationNode) {
CommitAllocationNode commit = (CommitAllocationNode) n;
/*
* very weak approximation, current problem is node size is an enum and we cannot
* dynamically instantiate a new case like nrOfAllocs*allocationCodeSize
*/
int nrOfAllocs = commit.getVirtualObjects().size();
if (nrOfAllocs < 5) {
return SIZE_80;
} else if (nrOfAllocs < 10) {
return SIZE_100;
} else {
return SIZE_200;
}
} else if (n instanceof AccessFieldNode) {
if (((AccessFieldNode) n).field().isVolatile()) {
// membar size is added
return SIZE_10;
}
} else if (n instanceof LoopEndNode) {
if (((LoopEndNode) n).canSafepoint()) {
return SIZE_6;
}
} else if (n instanceof SwitchNode) {
SwitchNode x = (SwitchNode) n;
int keyCount = x.keyCount();
if (keyCount == 0) {
return SIZE_1;
} else {
if (keyCount == 1) {
// if
return SIZE_2;
} else if (x instanceof IntegerSwitchNode && x.isSorted()) {
// good heuristic
return SIZE_15;
} else {
// not so good
return SIZE_30;
}
}
}
return n.getNodeClass().size();
}
@Override
public NodeCycles cycles(Node n) {
if (n instanceof Invoke) {
Invoke ivk = (Invoke) n;
CallTargetNode mct = ivk.callTarget();
switch (mct.invokeKind()) {
case Interface:
return CYCLES_100;
case Special:
case Static:
return CYCLES_2;
case Virtual:
return CYCLES_4;
default:
break;
}
} else if (n instanceof CommitAllocationNode) {
CommitAllocationNode commit = (CommitAllocationNode) n;
/*
* very weak approximation, current problem is node cycles is an enum and we cannot
* dynamically instantiate a new case like nrOfAllocs*allocationCost
*/
int nrOfAllocs = commit.getVirtualObjects().size();
if (nrOfAllocs < 5) {
return CYCLES_20;
} else if (nrOfAllocs < 10) {
return CYCLES_40;
} else {
return CYCLES_80;
}
} else if (n instanceof AccessFieldNode) {
if (((AccessFieldNode) n).field().isVolatile()) {
// membar cycles is added
return CYCLES_30;
}
} else if (n instanceof SwitchNode) {
SwitchNode x = (SwitchNode) n;
int keyCount = x.keyCount();
if (keyCount == 0) {
return CYCLES_1;
} else {
if (keyCount == 1) {
// if
return CYCLES_2;
} else if (x instanceof IntegerSwitchNode && x.isSorted()) {
// good heuristic
return CYCLES_15;
} else {
// not so good
return CYCLES_30;
}
}
}
return n.getNodeClass().cycles();
}
}