001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.adaptive.measurements.instrumentation;
014
015 import java.util.Hashtable;
016 import org.jikesrvm.VM;
017 import org.jikesrvm.adaptive.measurements.Reportable;
018 import org.jikesrvm.compilers.opt.InstrumentedEventCounterManager;
019 import org.jikesrvm.compilers.opt.ir.Instruction;
020
021 /**
022 * StringEventCounterData.java
023 *
024 * A generic data object that maps strings to counters. The key
025 * method is "Instruction getCounterInstructionForEvent(String)"
026 * which, given a string, returns a counter instruction that
027 * increments the corresponding counter for that string.
028 */
029 public class StringEventCounterData extends ManagedCounterData implements Reportable {
030
031 static final boolean DEBUG = false;
032
033 /**
034 * Constructor
035 *
036 * @param manager The manager that will provide the counter space
037 **/
038 StringEventCounterData(InstrumentedEventCounterManager manager, String name) {
039 // Call superclass constructor
040 super(manager);
041
042 dataName = name;
043 }
044
045 /**
046 * Given a string, find or create the counter associated and return
047 * and instruction to increment that counter.
048 *
049 * @param event The name of the event
050 * @return An instruction to increment the count associated with the event.
051 */
052 public Instruction getCounterInstructionForEvent(String event) {
053 return getCounterInstructionForEvent(event, 1.0);
054 }
055
056 /**
057 * Given a string, find or create the counter associated and return
058 * and instruction to increment that counter.
059 *
060 * @param event The name of the event
061 * @param incrementValue The value to add to counter
062 * @return An instruction that will update the count associated with the event.
063 */
064 public Instruction getCounterInstructionForEvent(String event, double incrementValue) {
065
066 // Get (or create) the counter for this string and return it.
067 int counterIdx = getOrCreateCounterIndexForString(event);
068
069 return createEventCounterInstruction(counterIdx, incrementValue);
070 }
071
072 /**
073 * Convert a double to string with maximum precision.
074 * @param num double to convert
075 */
076 protected static String doubleToString(double num) {
077 long whole = (long) num;
078 if (whole == Long.MAX_VALUE || whole == Long.MIN_VALUE) {
079 return Double.toString(whole);
080 }
081 double fract = Math.abs(num - (double) whole);
082 String res = Long.toString(whole);
083 if (fract != 0.0) {
084 String f2s = Double.toString(fract + 1.0);
085 res += f2s.substring(1);
086 }
087 return res;
088 }
089
090 /**
091 * Part of Reportable interface
092 * Print a report at the end of execution
093 */
094 public void report() {
095 // Turn off future instrumentation to avoid hanging during
096 // iteration
097 Instrumentation.disableInstrumentation();
098
099 VM.sysWrite("Printing " + dataName + ":\n");
100 VM.sysWrite("--------------------------------------------------\n");
101 double total = 0;
102 for (String stringName : stringToCounterMap.keySet()) {
103 int counterIdx = getCounterIndexForString(stringName);
104 double counterVal = getCounter(counterIdx);
105 VM.sysWrite(doubleToString(counterVal) + " " + stringName + "\n");
106 total += counterVal;
107 }
108 VM.sysWrite("Total: " + doubleToString(total) + "\n");
109 }
110
111 /**
112 * For a given string, return the number of the counter associated
113 * with this string. If this string doesn't already have a counter,
114 * reserve one.
115 *
116 * @param str The string for which you want the counter number
117 * @return The counter number for this string
118
119 */
120 public int getOrCreateCounterIndexForString(String str) {
121
122 int counterIdx = getCounterIndexForString(str);
123 if (counterIdx == -1) {
124 // Use new counter
125 counterIdx = ++eventNumber;
126 // remember it, and return it
127 stringToCounterMap.put(str, eventNumber);
128 }
129
130 return counterIdx;
131 }
132
133 /**
134 * For a given string, return the number of the counter associated
135 * with this string. Ideally this number would be completely hidden
136 * from the outside world, but for efficiency it is made public.
137 *
138 * @param str The string for which you want the counter number
139 * @return The counter number for this string, or -1 if the string has no
140 counter associated with it.
141 */
142 public int getCounterIndexForString(String str) {
143
144 int counter = -1;
145 Integer counterNum = stringToCounterMap.get(str);
146 if (counterNum != null) {
147 counter = counterNum;
148 }
149
150 return counter;
151 }
152
153 /**
154 * Part of Reportable interface
155 **/
156 public void reset() {
157 for (String stringName : stringToCounterMap.keySet()) {
158 int counterIdx = getCounterIndexForString(stringName);
159 setCounter(counterIdx, 0.0);
160 }
161 }
162
163 /**
164 * Map strings to a counter location
165 */
166 protected final Hashtable<String, Integer> stringToCounterMap = new Hashtable<String, Integer>();
167
168 /**
169 * A string description of this data;
170 */
171 final String dataName;
172
173 /**
174 * Used to keep track of how many counters have been used so far.
175 */
176 int eventNumber = -1;
177
178 } // end of class
179
180