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