1 /*
   2  * Copyright (c) 2013, 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.nodes.debug;
  26 
  27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
  28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
  29 
  30 import org.graalvm.compiler.core.common.type.StampFactory;
  31 import org.graalvm.compiler.debug.GraalError;
  32 import org.graalvm.compiler.graph.NodeClass;
  33 import org.graalvm.compiler.lir.LIRInstruction;
  34 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
  35 import org.graalvm.compiler.nodeinfo.NodeInfo;
  36 import org.graalvm.compiler.nodes.ConstantNode;
  37 import org.graalvm.compiler.nodes.FixedNode;
  38 import org.graalvm.compiler.nodes.FixedWithNextNode;
  39 import org.graalvm.compiler.nodes.StructuredGraph;
  40 import org.graalvm.compiler.nodes.ValueNode;
  41 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  42 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  43 
  44 /**
  45  * This node can be used to add a counter to the code that will estimate the dynamic number of calls
  46  * by adding an increment to the compiled code. This should of course only be used for
  47  * debugging/testing purposes.
  48  *
  49  * A unique counter will be created for each unique name passed to the constructor. Depending on the
  50  * value of withContext, the name of the root method is added to the counter's name.
  51  */
  52 //@formatter:off
  53 @NodeInfo(size = SIZE_IGNORED,
  54           sizeRationale = "Node is a debugging node that should not be used in production.",
  55           cycles = CYCLES_IGNORED,
  56           cyclesRationale = "Node is a debugging node that should not be used in production.")
  57 //@formatter:on
  58 public class DynamicCounterNode extends FixedWithNextNode implements LIRLowerable {
  59 
  60     public static final NodeClass<DynamicCounterNode> TYPE = NodeClass.create(DynamicCounterNode.class);
  61     @Input ValueNode increment;
  62 
  63     protected final String group;
  64     protected final String name;
  65     protected final boolean withContext;
  66 
  67     public DynamicCounterNode(String group, String name, ValueNode increment, boolean withContext) {
  68         this(TYPE, group, name, increment, withContext);
  69     }
  70 
  71     protected DynamicCounterNode(NodeClass<? extends DynamicCounterNode> c, String group, String name, ValueNode increment, boolean withContext) {
  72         super(c, StampFactory.forVoid());
  73         this.group = group;
  74         this.name = name;
  75         this.increment = increment;
  76         this.withContext = withContext;
  77     }
  78 
  79     public ValueNode getIncrement() {
  80         return increment;
  81     }
  82 
  83     public String getName() {
  84         return name;
  85     }
  86 
  87     public String getGroup() {
  88         return group;
  89     }
  90 
  91     public boolean isWithContext() {
  92         return withContext;
  93     }
  94 
  95     public static void addCounterBefore(String group, String name, long increment, boolean withContext, FixedNode position) {
  96         StructuredGraph graph = position.graph();
  97         graph.addBeforeFixed(position, position.graph().add(new DynamicCounterNode(group, name, ConstantNode.forLong(increment, position.graph()), withContext)));
  98     }
  99 
 100     @NodeIntrinsic
 101     public static native void counter(@ConstantNodeParameter String group, @ConstantNodeParameter String name, long increment, @ConstantNodeParameter boolean addContext);
 102 
 103     @Override
 104     public void generate(NodeLIRBuilderTool generator) {
 105         LIRGeneratorTool lirGen = generator.getLIRGeneratorTool();
 106         String nameWithContext;
 107         if (isWithContext()) {
 108             nameWithContext = getName() + " @ ";
 109             if (graph().method() != null) {
 110                 StackTraceElement stackTraceElement = graph().method().asStackTraceElement(0);
 111                 if (stackTraceElement != null) {
 112                     nameWithContext += " " + stackTraceElement.toString();
 113                 } else {
 114                     nameWithContext += graph().method().format("%h.%n");
 115                 }
 116             }
 117             if (graph().name != null) {
 118                 nameWithContext += " (" + graph().name + ")";
 119             }
 120 
 121         } else {
 122             nameWithContext = getName();
 123         }
 124         LIRInstruction counterOp = lirGen.createBenchmarkCounter(nameWithContext, getGroup(), generator.operand(increment));
 125         if (counterOp != null) {
 126             lirGen.append(counterOp);
 127         } else {
 128             throw GraalError.unimplemented("Benchmark counters not enabled or not implemented by the back end.");
 129         }
 130     }
 131 
 132 }