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