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.mmtk.utility.statistics;
014    
015    import org.mmtk.utility.Log;
016    
017    import org.mmtk.vm.VM;
018    
019    import org.vmmagic.pragma.*;
020    
021    /**
022     * This abstract class implements a simple counter (counting some
023     * integer (long) value for each phase).
024     */
025    @Uninterruptible
026    public abstract class LongCounter extends Counter {
027    
028      /****************************************************************************
029       *
030       * Instance variables
031       */
032    
033      /**
034       *
035       */
036      private final long[] count;
037    
038      private long startValue = 0;
039      protected long totalCount = 0;
040      private boolean running = false;
041    
042      /****************************************************************************
043       *
044       * Initialization
045       */
046    
047      /**
048       * Constructor
049       *
050       * @param name The name to be associated with this counter
051       */
052      LongCounter(String name) {
053        this(name, true, false);
054      }
055    
056      /**
057       * Constructor
058       *
059       * @param name The name to be associated with this counter
060       * @param start True if this counter is to be implicitly started
061       * when <code>startAll()</code> is called (otherwise the counter
062       * must be explicitly started).
063       */
064      LongCounter(String name, boolean start) {
065        this(name, start, false);
066      }
067    
068      /**
069       * Constructor
070       *
071       * @param name The name to be associated with this counter
072       * @param start True if this counter is to be implicitly started
073       * when <code>startAll()</code> is called (otherwise the counter
074       * must be explicitly started).
075       * @param mergephases True if this counter does not separately
076       * report GC and Mutator phases.
077       */
078      LongCounter(String name, boolean start, boolean mergephases) {
079        super(name, start, mergephases);
080        count = new long[Stats.MAX_PHASES];
081      }
082    
083      /****************************************************************************
084       *
085       * Counter-specific methods
086       */
087    
088      /**
089       *
090       */
091      protected abstract long getCurrentValue();
092    
093      /****************************************************************************
094       *
095       * Generic counter control methods: start, stop, print etc
096       */
097    
098      /**
099       * {@inheritDoc}
100       */
101      @Override
102      public void start() {
103        if (!Stats.gatheringStats) return;
104        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!running);
105        running = true;
106        startValue = getCurrentValue();
107      }
108    
109      @Override
110      public void stop() {
111        if (!Stats.gatheringStats) return;
112        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(running);
113        running = false;
114        long delta = getCurrentValue() - startValue;
115        count[Stats.phase] += delta;
116        totalCount += delta;
117      }
118    
119      /**
120       * The phase has changed (from GC to mutator or mutator to GC).
121       * Take action with respect to the last phase if necessary.
122       * <b>Do nothing in this case.</b>
123       *
124       * @param oldPhase The last phase
125       */
126      @Override
127      protected void phaseChange(int oldPhase) {
128        if (running) {
129          long now = getCurrentValue();
130          long delta = now - startValue;
131          count[oldPhase] += delta;
132          totalCount += delta;
133          startValue = now;
134        }
135      }
136    
137      /**
138       * {@inheritDoc}
139       * Print '0' for {@code false}, '1' for {@code true}.
140       */
141      @Override
142      protected final void printCount(int phase) {
143        if (VM.VERIFY_ASSERTIONS && mergePhases())
144          if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((phase | 1) == (phase + 1));
145        if (mergePhases())
146          printValue(count[phase] + count[phase + 1]);
147        else
148          printValue(count[phase]);
149      }
150    
151      @Override
152      public final void printTotal() {
153        printValue(totalCount);
154      }
155    
156    
157      /**
158       * Get the total as at the lasts phase
159       *
160       * @return The total as at the last phase
161       */
162      long getLastTotal() {
163        return totalCount;
164      }
165    
166      @Override
167      protected final void printTotal(boolean mutator) {
168        long total = 0;
169        for (int p = (mutator) ? 0 : 1; p <= Stats.phase; p += 2) {
170          total += count[p];
171        }
172        printValue(total);
173      }
174    
175      @Override
176      protected final void printMin(boolean mutator) {
177        int p = (mutator) ? 0 : 1;
178        long min = count[p];
179        for (; p < Stats.phase; p += 2) {
180          if (count[p] < min) min = count[p];
181        }
182        printValue(min);
183      }
184    
185      @Override
186      protected final void printMax(boolean mutator) {
187        int p = (mutator) ? 0 : 1;
188        long max = count[p];
189        for (; p < Stats.phase; p += 2) {
190          if (count[p] > max) max = count[p];
191        }
192        printValue(max);
193      }
194    
195      /**
196       * Print the given value
197       *
198       * @param value The value to be printed
199       */
200      void printValue(long value) {
201        Log.write(value);
202      }
203    }