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