/* * 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); } }