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.mmtk.utility.statistics;
014
015import org.mmtk.utility.Log;
016
017import org.mmtk.vm.VM;
018
019import 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
026public 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   * @return the current value of this counter
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}