/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* StatsGenerator.java
* Created: Oct 7, 2002 at 2:55:33 PM
* By: Raymond Cypher
*/
package org.openquark.cal.machine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* This is the StatsGenerator interface
*
* This class collects statistics generated by the machine
* during run-time.
* Typically these are statistics about machine behaviour/performance.
* An instance of StatsGenerator can be registered with a CALExecutor.
* When the CALExecutor has finished running a CAL program the StatsGenerator
* instance will hold a collection of StatsObject instances. The StatsObject
* instances will reflect the statistics that the specific CALExecutor
* instance was configured to generate.
* Creation: Oct 7, 2002 at 2:55:32 PM
* @author Raymond Cypher
*/
public final class StatsGenerator {
private List<StatsObject> statistics = new ArrayList<StatsObject> ();
private List<StatsObject> cachedRuns = new ArrayList<StatsObject> ();
/**
* Find the StatsObject corresponding to the given ProfileObj and update it.
* If there is no matching StatsObject get the ProfileObj to create one.
* @param info
*/
public final void i_instrument (ProfileObj info) {
for (final StatsObject stats : statistics) {
if (info.updateStats(stats) != null) {
// We've updated the corresponding StatsObject and can return.
return;
}
}
// There was no corresponding StatsObject so we need to get the
// ProfileObj to create one.
statistics.add(info.updateStats(null));
}
/**
* The underlying collection cannot be modified through the returned list- this is for traversal purposes only.
* @return a list of StatsObject
*/
public List<StatsObject> getStatistics() {
return Collections.unmodifiableList(statistics);
}
/**
* Clear any state in the StatsGenerator.
*
*/
public final void reset () {
statistics = new ArrayList<StatsObject> ();
cachedRuns = new ArrayList<StatsObject>();
}
/**
* Store any generated statistics for future
* summarization. This is how a client accumulates
* statistics across multiple runs.
*/
public final void cacheRun () {
cachedRuns.addAll(statistics);
statistics = new ArrayList<StatsObject>();
}
/**
* Summarize any cached statistics.
* @return List
*/
public final List<StatsObject> summarizeCachedRuns () {
List<StatsObject> summaryList = new ArrayList<StatsObject>();
StatsGenerator.StatsObject[] runs = new StatsGenerator.StatsObject[cachedRuns.size()];
for (int i = 0; i < cachedRuns.size(); ++i) {
runs[i] = cachedRuns.get(i);
}
boolean f = true;
while (f) {
f = false;
for (int i = 0; i < runs.length; ++i) {
if (runs[i] == null) {
continue;
}
// We've found something that needs summarizing.
// Get all the other stats objects of the same type.
StatsObject si = runs[i];
runs[i] = null;
List<StatsObject> toSum = new ArrayList<StatsObject>();
toSum.add(si);
for (int j = i+1; j < runs.length; ++j) {
StatsObject sn = runs[j];
if (sn != null && sn.getClass() == si.getClass()) {
runs[j] = null;
toSum.add (sn);
}
}
summaryList.add(si.summarize(toSum));
f = true;
break;
}
}
return summaryList;
}
/**
* This is the interface for the statistics objects that the StatsGenerator
* holds on to. There will be one StatsObject for each type of statistic
* being generated.
* When the
*
* @author rcypher
*/
public interface StatsObject {
/**
* Generate a short message describing these statistics.
* @return String
*/
public String generateShortMessage();
/**
* Generate a long message describing these statistics.
* @return String
*/
public String generateLongMessage();
/**
* Summarize the list of stats objects.
* The objects in the list will be of the same type
* as the executing instance.
* This method is called when a set of StatsObjects has
* been accumulated across several runs.
* @param runs
* @return StatsObject.
*/
public StatsObject summarize(List<StatsObject> runs);
}
/**
* An extension of StatsObject specifically for statistics that involve
* collecting performance information across multiple runs.
* @author rcypher
*/
public static abstract class PerformanceStatsObject implements StatsObject {
abstract public long getAverageRunTime();
abstract public long getMedianRunTime();
abstract public double getStdDeviation();
abstract public int getNRuns() ;
abstract public long[] getRunTimes();
/** gets the minimum execution run time from all the samples taken */
public long getMinTime() {
long min = Long.MAX_VALUE;
long[] times = getRunTimes();
for (final long time : times) {
if (time < min) {
min = time;
}
}
return min;
}
}
/**
* This is the interface for objects which the runtimes use
* to communicate statistics info to the StatsGenerator.
*
* @author rcypher
*/
public interface ProfileObj {
/**
* Update the supplied statistics object.
* If the StatsObject is of incorrect type return null.
* If the StatsObject is null create a new one.
* @param stats
* @return StatsObject
*/
public StatsObject updateStats (StatsObject stats);
}
}