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