1 /*
   2  * Copyright (c) 2012, 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.replacements;
  24 
  25 //JaCoCo Exclude
  26 
  27 import java.io.PrintStream;
  28 import java.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.List;
  31 
  32 /**
  33  * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering
  34  * snippet specific metrics.
  35  */
  36 public class SnippetCounter implements Comparable<SnippetCounter> {
  37     /**
  38      * A group of related counters.
  39      */
  40     public static class Group {
  41 
  42         final String name;
  43         final List<SnippetCounter> counters;
  44 
  45         public Group(String name) {
  46             this.name = name;
  47             this.counters = new ArrayList<>();
  48         }
  49 
  50         @Override
  51         public synchronized String toString() {
  52             Collections.sort(counters);
  53 
  54             long total = 0;
  55             int maxNameLen = 0;
  56             for (SnippetCounter c : counters) {
  57                 total += c.value;
  58                 maxNameLen = Math.max(c.name.length(), maxNameLen);
  59             }
  60 
  61             StringBuilder buf = new StringBuilder(String.format("Counters: %s%n", name));
  62 
  63             String formatString = "  %" + maxNameLen + "s: %6.2f%%%," + (String.format("%,d", total).length() + 2) + "d  // %s%n";
  64             for (SnippetCounter c : counters) {
  65                 double percent = total == 0D ? 0D : ((double) (c.value * 100)) / total;
  66                 buf.append(String.format(formatString, c.name, percent, c.value, c.description));
  67             }
  68             buf.append(String.format(formatString, "TOTAL", 100.0D, total, ""));
  69 
  70             return buf.toString();
  71         }
  72     }
  73 
  74     /**
  75      * Sorts counters in descending order of their {@linkplain #value() values}.
  76      */
  77     @Override
  78     public int compareTo(SnippetCounter o) {
  79         if (value > o.value) {
  80             return -1;
  81         } else if (o.value < value) {
  82             return 1;
  83         }
  84         return 0;
  85     }
  86 
  87     private static final List<Group> groups = new ArrayList<>();
  88 
  89     private final Group group;
  90     private final int index;
  91     private final String name;
  92     private final String description;
  93     private long value;
  94 
  95     /**
  96      * Creates a counter.
  97      *
  98      * @param group the group to which the counter belongs. If this is null, the newly created
  99      *            counter is disabled and {@linkplain #inc() incrementing} is a no-op.
 100      * @param name the name of the counter
 101      * @param description a brief comment describing the metric represented by the counter
 102      */
 103     public SnippetCounter(Group group, String name, String description) {
 104         this.group = group;
 105         this.name = name;
 106         this.description = description;
 107         if (group != null) {
 108             List<SnippetCounter> counters = group.counters;
 109             this.index = counters.size();
 110             counters.add(this);
 111             if (index == 0) {
 112                 groups.add(group);
 113             }
 114         } else {
 115             this.index = -1;
 116         }
 117     }
 118 
 119     /**
 120      * Increments the value of this counter. This method can only be used in a snippet on a
 121      * compile-time constant {@link SnippetCounter} object.
 122      */
 123     public void inc() {
 124         if (group != null) {
 125             SnippetCounterNode.increment(this);
 126         }
 127     }
 128 
 129     /**
 130      * Increments the value of this counter. This method can only be used in a snippet on a
 131      * compile-time constant {@link SnippetCounter} object.
 132      */
 133     public void add(int increment) {
 134         if (group != null) {
 135             SnippetCounterNode.add(this, increment);
 136         }
 137     }
 138 
 139     /**
 140      * Gets the value of this counter.
 141      */
 142     public long value() {
 143         return value;
 144     }
 145 
 146     @Override
 147     public String toString() {
 148         if (group != null) {
 149             return "SnippetCounter-" + group.name + ":" + name;
 150         }
 151         return super.toString();
 152     }
 153 
 154     /**
 155      * Prints all the counter groups to a given stream.
 156      */
 157     public static void printGroups(PrintStream out) {
 158         for (Group group : groups) {
 159             out.println(group);
 160         }
 161     }
 162 }