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