/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.server; /** * This class defines a data type that will be used to hold real-time stat data * for a particular statistic in a particular job. Note that this class is not * designed to be threadsafe, so any operations on it should be properly * synchronized by the callers. * * * @author Neil A. Wilson */ public class RealTimeJobStatList { // Indicates whether we need to average the data before making it available // externally. private boolean averageData; // The data associated with this stat list. private double[] intervalData; // A backup array that will be used if we need to shift data out of the // current data array. private double[] newData; // The interval number for the first interval currently held in this list. private int firstInterval; // The interval number for the last interval currently held in this list. private int lastInterval; // The current size of this list. private int listSize; // The maximum number of intervals that should be held in this list. private int maxIntervals; // The number of threads that have reported data for each interval. private int numReporters[]; // A backup array that will be used if we need to shift data out of the // current reporter array. private int newReporters[]; // The name of the statistic which which this data is associated. private String statName; /** * Creates a new real-time job stat list. * * @param statName The name of the statistic with which this data is * associated. * @param maxIntervals The maximum number of collection intervals that * will be maintained for this statistic. */ public RealTimeJobStatList(String statName, int maxIntervals) { this.statName = statName; this.maxIntervals = maxIntervals; intervalData = new double[maxIntervals]; newData = new double[maxIntervals]; numReporters = new int[maxIntervals]; newReporters = new int[maxIntervals]; averageData = false; firstInterval = -1; lastInterval = -1; listSize = 0; } /** * Retrieves the name of the statistic with which this data is associated. * * @return The name of the statistic with which this data is associated. */ public String getStatName() { return statName; } /** * Retrieves the interval number of the first interval currently held in this * stat list. * * @return The interval number of the first interval currently held in this * stat list. */ public int getFirstInterval() { return firstInterval; } /** * Retrieves the interval number of the last interval currently held in this * stat list. * * @return The interval number of the last interval currently held in this * stat list. */ public int getLastInterval() { return lastInterval; } /** * Retrieves a copy of the data currently held in this stat list. * * @return A copy of the data currently held in this stat list. */ public double[] getStatData() { double[] dataCopy = new double[listSize]; int[] reporterCopy = new int[listSize]; System.arraycopy(intervalData, 0, dataCopy, 0, listSize); System.arraycopy(numReporters, 0, reporterCopy, 0, listSize); if (averageData) { for (int i=0; i < dataCopy.length; i++) { dataCopy[i] = dataCopy[i] / reporterCopy[i]; } } return dataCopy; } /** * Adds the provided value to the data for the given interval in the list. * * @param intervalNumber The interval number in which the update is to be * made. * @param value The value to add to the data for that interval. * @param averageData Indicates whether the data associated with this * statistic should be averaged. */ public void addValue(int intervalNumber, double value, boolean averageData) { this.averageData = averageData; if (listSize == 0) { // This is the first element in the list. firstInterval = intervalNumber; lastInterval = intervalNumber; listSize = 1; intervalData[0] = value; numReporters[0] = 1; } else if (intervalNumber < firstInterval) { // Oops. This is data that has already been flushed from the list. // Ignore it. return; } else if (intervalNumber > lastInterval) { // This is data beyond the end of the list. Figure out how to handle it. if (intervalNumber == (lastInterval + 1)) { // We need to add one more element to the list. if (listSize < maxIntervals) { // This is OK -- we already have room for the element. intervalData[listSize] = value; numReporters[listSize] = 1; lastInterval = intervalNumber; listSize++; } else { // We need to shift everything over one slot to make room for the // new value. Do that with a separate array. System.arraycopy(intervalData, 1, newData, 0, (maxIntervals-1)); newData[listSize-1] = value; System.arraycopy(numReporters, 1, newReporters, 0, (maxIntervals-1)); newReporters[listSize-1] = 1; intervalData = newData; numReporters = newReporters; firstInterval++; lastInterval = intervalNumber; } } else { // This is well beyond the end of the list. Ignore it. return; } } else { // This is data in the middle of the list. We can handle that. int offset = intervalNumber - firstInterval; intervalData[offset] += value; numReporters[offset]++; } } }