From: <am...@us...> - 2006-03-19 23:09:03
|
Revision: 95 Author: amooy Date: 2006-03-19 15:08:44 -0800 (Sun, 19 Mar 2006) ViewCVS: http://svn.sourceforge.net/sensor/?rev=95&view=rev Log Message: ----------- Reimplemented the reset() functionality. The runtime now has a reset() method and statistics do not. Resetting a TimerData now gets rid of all child instances. Performance improvements to TimerData implementation by moving calculation of standard deviation and average to the refreshStatistics method. Renamed test classes to be consistent with the classes they test Misc cleanups Modified Paths: -------------- trunk/sensor-core/src/java/net/sf/sensor/SensorStatistics.java trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerRuntime.java trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerStatistics.java trunk/sensor-core/src/java/net/sf/sensor/timer/FilteredTimerStatistics.java trunk/sensor-core/src/java/net/sf/sensor/timer/TimerData.java trunk/sensor-core/src/java/net/sf/sensor/timer/TimerRuntime.java trunk/sensor-core/src/java/net/sf/sensor/timer/TimerService.java trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatistics.java trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatisticsFilter.java trunk/sensor-core/test/java/net/sf/sensor/timer/DefaultTimerRuntimeTest.java trunk/sensor-core/test/java/net/sf/sensor/timer/FilteredTimerStatisticsTest.java trunk/sensor-core/test/java/net/sf/sensor/timer/TimerDataTest.java Added Paths: ----------- trunk/sensor-core/test/java/net/sf/sensor/timer/SimplePerformanceTest.java Modified: trunk/sensor-core/src/java/net/sf/sensor/SensorStatistics.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/SensorStatistics.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/SensorStatistics.java 2006-03-19 23:08:44 UTC (rev 95) @@ -18,7 +18,10 @@ import java.util.Set; + /** + * SensorStatistics unifies the read-only statistics views for all types of sensors. + * It contains the properties that are shared accross all types of sensors. * * @author Age Mooy */ @@ -41,9 +44,4 @@ */ public void refresh(); - /** - * Resets the statistics to their default values. - */ - public void reset(); - } Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerRuntime.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerRuntime.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerRuntime.java 2006-03-19 23:08:44 UTC (rev 95) @@ -63,10 +63,22 @@ rootTimerData = new TimerData(DEFAULT_ROOT_TIMER_LABEL); timerDataCallStack = new TimerDataCallStack(rootTimerData); } + + // ========================================================================== + // TimerService impementation + // ========================================================================== + /** + * @see net.sf.sensor.timer.TimerService#getTimerStatistics() + */ + public List getTimerStatistics() { + return rootTimerData.getStatistics().getChildren(); + } + + // ========================================================================== - // Timer API + // TimerRuntime implementation // ========================================================================== /** @@ -87,16 +99,19 @@ return timer; } - - // ========================================================================== - // TimerStatistics API - // ========================================================================== - /** - * @see net.sf.sensor.timer.TimerRuntime#getTimerStatistics() + * @see net.sf.sensor.timer.TimerRuntime#reset() */ - public List getTimerStatistics() { - return rootTimerData.getStatistics().getChildren(); + public synchronized void reset() { + // remove all children from the root timerdata + // NOTE: this decouples all existing and/or running Timer instances from the runtime... is this what we want ? + rootTimerData.reset(); + + // todo reinitialize the call stack ? + // since the above action decoupled all existing timers from this runtime, there are + // no side effects on the call stack. The running threads will finish their jobs and + // the leftover decoupled TimerDats will get their last updates but noone will see + // the results. New calls to start/stop on existing timer instances will work just fine. } Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerStatistics.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerStatistics.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/DefaultTimerStatistics.java 2006-03-19 23:08:44 UTC (rev 95) @@ -26,6 +26,7 @@ * representing the timing values as they were when the {@link #refresh()} * method was last called. * + * @see TimerStatistics * @author Age Mooy */ public class DefaultTimerStatistics implements TimerStatistics { @@ -118,16 +119,7 @@ timerData.refreshStatistics(); } - /** - * @see net.sf.sensor.timer.TimerStatistics#reset() - */ - public void reset() { - timerData.reset(); - // refresh ourselves - timerData.refreshStatistics(); - } - // ========================================================================== // Refreshing of statistics // ========================================================================== Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/FilteredTimerStatistics.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/FilteredTimerStatistics.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/FilteredTimerStatistics.java 2006-03-19 23:08:44 UTC (rev 95) @@ -66,15 +66,6 @@ filteredChildren = filter.filter(delegate.getChildren()); } - - /** - * @see TimerStatistics#reset() - */ - public void reset() { - delegate.reset(); - - filteredChildren = new ArrayList(); - } /** * @see TimerStatistics#hasChildren() Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/TimerData.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/TimerData.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/TimerData.java 2006-03-19 23:08:44 UTC (rev 95) @@ -58,8 +58,8 @@ /** A Set<String> of labels associated with this instance. */ private Set labels = new LinkedHashSet(); - /** Lazy-initialized read-only view on this instance. */ - private DefaultTimerStatistics timerStatistics; + /** Read-only view on this instance. */ + private DefaultTimerStatistics timerStatistics = new DefaultTimerStatistics(this);; // ========================================================================== @@ -154,8 +154,6 @@ /** * Resets all statistics data and all registered child instances. - * - * @todo should we remove the children or reset thier values ??? */ synchronized void reset() { numberOfHits = 0L; @@ -170,10 +168,19 @@ timeOfFirstUpdate = 0L; timeOfLastUpdate = 0L; - // reset all children + // reset all existing children so that any open direct references to child instances + // get reset before they are cut lose from their parent. for (Iterator i = children.values().iterator(); i.hasNext();) { ((TimerData) i.next()).reset(); } + + // now we get rid of our children and our collected labels. + children = new LinkedHashMap(); + labels = new LinkedHashSet(); + + // last, we make sure our view is updated. This is to make sure + // statelfull clients like a JMX console get notified of changes. + refreshStatistics(); } @@ -244,10 +251,11 @@ * @param timeTaken the time (in milliseconds) it took to execute the code that was being measured. */ synchronized void updateFromTimer(long timeTaken) { + // todo pass the start time from the Timer so we can use it to update the first/last time fields and save a call to System.currenttimemillis + // update the internal statistics numberOfHits++; totalTime = totalTime + timeTaken; - averageTime = totalTime / numberOfHits; sumOfSquaresOfTimes = sumOfSquaresOfTimes + (timeTaken * timeTaken); // the time of the last update is always the last call to this method. @@ -267,11 +275,8 @@ } } - // calculate the standard deviation - long nMinus1 = (numberOfHits <= 1) ? 1 : numberOfHits - 1; // avoid 0 divides - long numerator = sumOfSquaresOfTimes - ((totalTime * totalTime) / numberOfHits); - - standardDeviation = (long) java.lang.Math.sqrt(numerator / nMinus1); + // calculation of standard deviation was moved to the refreshStatistics method + // to optimize the performance of this method. } /** @@ -279,10 +284,6 @@ * @return a hierarchical statistical view of this instance of TimerData. */ TimerStatistics getStatistics() { - if (timerStatistics == null) { - timerStatistics = new DefaultTimerStatistics(this); - } - // refresh the statistics refreshStatistics(); @@ -299,6 +300,18 @@ * could lead to inconsistent data. */ synchronized void refreshStatistics() { + // calculate the standard deviation if necessary + if (numberOfHits > 0) { + // calculate the average time + averageTime = totalTime / numberOfHits; + + // calculate the standard deviation + long nMinus1 = (numberOfHits <= 1) ? 1 : numberOfHits - 1; // avoid 0 divides + long numerator = sumOfSquaresOfTimes - ((totalTime * totalTime) / numberOfHits); + + standardDeviation = (long) java.lang.Math.sqrt(numerator / nMinus1); + } + timerStatistics.refreshFromData( numberOfHits, totalTime, @@ -313,6 +326,14 @@ } /** + * Create a new List filled with the TimerStatistics views of all currently + * registered children. + * + * We can't use a simple List wrapper here because we really do want a snaphot + * (ie a view on the situation as it was when this method was called) as opposed + * to a wrapper list, which would reflect the contents of the list at the moment + * of iteration or item access. + * * @return a new List<TimerStatistics> containing an instance of * TimerStatistics for each currently registered child. */ Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/TimerRuntime.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/TimerRuntime.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/TimerRuntime.java 2006-03-19 23:08:44 UTC (rev 95) @@ -18,12 +18,15 @@ /** - * The entry point for all timer-related functionality. + * Main entry point to the timing runtime system that supports timer creation + * and resetting plus the read-only statistics functionality offered by the + * {@link TimerService super-interface}. + * <p> * An instance of TimerRuntime can produce {@link Timer Timers}, keeps track of * internal timer data and call stacks, and offers views on this data through * instances of {@link TimerStatistics}. * - * @see TimerService + * @see TimerService for read-only acces to the timer runtime system. * * @author Age Mooy */ @@ -47,5 +50,10 @@ * @return the started {@link Timer} instance. */ public Timer getTimer(String id, String label); + + /** + * Resets all timing data gathered by this instance and starts with a clean slate. + */ + public void reset(); } Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/TimerService.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/TimerService.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/TimerService.java 2006-03-19 23:08:44 UTC (rev 95) @@ -21,8 +21,10 @@ /** * This interface is meant to provide the most limited read-only view on the - * timer subsystem. + * timer runtime system by only allowing access to timer statistics. * + * @see TimerRuntime for full access to the timer runtime system. + * * @author Age Mooy */ public interface TimerService { Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatistics.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatistics.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatistics.java 2006-03-19 23:08:44 UTC (rev 95) @@ -24,8 +24,14 @@ /** + * TimerStatistics is the refreshable read-only snapshot view on the TimerData + * internals. It is directly linked one-to-one with its source TimerData (an + * internal class that keeps track of the actual data associated with a Timer) + * and can be refreshed from that source by calling the {@link #refresh()} method. + * TimerStatistics is a hierarchical tree-like data structure that can contain + * child instances which reflect events that were timed within the scope of the + * parent timer. * - * * @author Age Mooy */ public interface TimerStatistics extends SensorStatistics { @@ -41,28 +47,29 @@ public Set getLabels(); /** - * Refreshes this instances and all its children. + * Refreshes this instance and all its children from the associated source TimerData. * * @see net.sf.sensor.SensorStatistics#refresh() */ public void refresh(); /** - * @see net.sf.sensor.SensorStatistics#reset() - */ - public void reset(); - - /** * Returns true if this instance has one or more child instances. * @return true if this instance has one or more child instances. */ public boolean hasChildren(); /** + * Returns a List<TimerStatistics> of all the child instances. * @return a List<TimerStatistics> of all the child instances. */ public List getChildren(); + + // ========================================================================== + // Statistical properties + // ========================================================================== + /** * Returns the number of hits counted until the last call to {@link #refresh()}. * @return the number of hits counted until the last call to {@link #refresh()}. @@ -117,6 +124,11 @@ */ public Date getTimeOfLastUpdate(); + + // ========================================================================== + // Developer-centric util methods + // ========================================================================== + /** * For testing correct tree-structure behaviour. * @return a String representing the tree path from the root node to this node, Modified: trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatisticsFilter.java =================================================================== --- trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatisticsFilter.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/src/java/net/sf/sensor/timer/TimerStatisticsFilter.java 2006-03-19 23:08:44 UTC (rev 95) @@ -33,7 +33,7 @@ * list. * <p> * The TimerStatisticsFilter will wrap each TimerStatistics in an instance of - * FilteredTimerStatistics which has a reference to the filter so it can call + * {@link FilteredTimerStatistics} which has a reference to the filter so it can call * the filter on its nested children list to create a filtered list. * * @author Age Mooy Modified: trunk/sensor-core/test/java/net/sf/sensor/timer/DefaultTimerRuntimeTest.java =================================================================== --- trunk/sensor-core/test/java/net/sf/sensor/timer/DefaultTimerRuntimeTest.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/test/java/net/sf/sensor/timer/DefaultTimerRuntimeTest.java 2006-03-19 23:08:44 UTC (rev 95) @@ -123,4 +123,43 @@ assertTrue(statisticsB.getTotalTime() > statisticsC.getTotalTime()); } + /** Tests a call to reset while a timer is still running. */ + public void testResetWithRunningTimer() { + TimerRuntime runtime = new DefaultTimerRuntime(); + Timer timerA = runtime.getTimer("A", "label"); + + // call the timer twice so we have a numberOfHits == 2 + timerA.start(); + timerA.stop(); + timerA.start(); + timerA.stop(); + + List statistics = runtime.getTimerStatistics(); + + assertEquals(1, statistics.size()); + assertEquals(2, ((TimerStatistics) statistics.get(0)).getNumberOfHits()); + + timerA.start(); + + runtime.reset(); + + statistics = runtime.getTimerStatistics(); + + assertEquals(0, statistics.size()); + + timerA.stop(); + + statistics = runtime.getTimerStatistics(); + + assertEquals(0, statistics.size()); + + timerA.start(); + timerA.stop(); + + statistics = runtime.getTimerStatistics(); + + assertEquals(1, statistics.size()); + assertEquals(1, ((TimerStatistics) statistics.get(0)).getNumberOfHits()); + } + } Modified: trunk/sensor-core/test/java/net/sf/sensor/timer/FilteredTimerStatisticsTest.java =================================================================== --- trunk/sensor-core/test/java/net/sf/sensor/timer/FilteredTimerStatisticsTest.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/test/java/net/sf/sensor/timer/FilteredTimerStatisticsTest.java 2006-03-19 23:08:44 UTC (rev 95) @@ -77,9 +77,6 @@ mockDelegate.getTreePath(); mockDelegate.toString(); - // calls made by the reset() method. - mockDelegate.reset(); - // calls made by the refresh method mockDelegate.refresh(); @@ -111,12 +108,6 @@ filtered.getTimeOfLastUpdate(); filtered.getTreePath(); filtered.toString(); - - filtered.reset(); - - assertFalse(filtered.hasChildren()); - assertEquals(0, filtered.getChildren().size()); - filtered.refresh(); } Added: trunk/sensor-core/test/java/net/sf/sensor/timer/SimplePerformanceTest.java =================================================================== --- trunk/sensor-core/test/java/net/sf/sensor/timer/SimplePerformanceTest.java (rev 0) +++ trunk/sensor-core/test/java/net/sf/sensor/timer/SimplePerformanceTest.java 2006-03-19 23:08:44 UTC (rev 95) @@ -0,0 +1,72 @@ +/* + * Copyright 2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.sensor.timer; + +import java.util.List; + +import junit.framework.TestCase; + +/** + * + * + * @author Age Mooy + */ +public class SimplePerformanceTest extends TestCase { + private TimerRuntime runtime; + private Timer parentTimer; + private Timer timer; + + + /** + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + runtime = new DefaultTimerRuntime(); + parentTimer = runtime.getTimer("parent timer"); + timer = runtime.getTimer("test timer"); + } + + /** + * + */ + public void testStartStopPerformance() { + parentTimer.start(); + + for (int i = 0; i < 1000000; i++) { + timer.start(); + timer.stop(); + } + + parentTimer.stop(); + + List statistics = runtime.getTimerStatistics(); + + assertNotNull(statistics); + assertEquals(1, statistics.size()); + + TimerStatistics stats = (TimerStatistics) statistics.get(0); + + System.out.println("Total time (parent timer): " + stats.getTotalTime() + " ms."); + + stats = (TimerStatistics) stats.getChildren().get(0); + + System.out.println("Number of hits (test timer): " + stats.getNumberOfHits() + "."); + System.out.println("Total time (test timer) : " + stats.getTotalTime() + " ms."); + System.out.println("Average time (test timer) : " + stats.getAverageTime() + " ms."); + } + +} Modified: trunk/sensor-core/test/java/net/sf/sensor/timer/TimerDataTest.java =================================================================== --- trunk/sensor-core/test/java/net/sf/sensor/timer/TimerDataTest.java 2006-03-19 22:09:13 UTC (rev 94) +++ trunk/sensor-core/test/java/net/sf/sensor/timer/TimerDataTest.java 2006-03-19 23:08:44 UTC (rev 95) @@ -86,6 +86,15 @@ assertNotNull(children); assertFalse(children.hasNext()); + + timerData.reset(); + + assertFalse(timerData.hasChildren()); + + children = timerData.getChildren(); + + assertNotNull(children); + assertFalse(children.hasNext()); } /** @@ -139,6 +148,9 @@ long timestampAfterUpdate = System.currentTimeMillis(); + // call the refresh method to force the calculation of the average time and the standard deviation + timerData.refreshStatistics(); + assertEquals(1L, timerData.getNumberOfHits()); assertEquals(10L, timerData.getTotalTime()); assertEquals(10L, timerData.getAverageTime()); @@ -171,6 +183,9 @@ timestampAfterUpdate = System.currentTimeMillis(); + // call the refresh method to force the calculation of the average time and the standard deviation + timerData.refreshStatistics(); + assertEquals(2L, timerData.getNumberOfHits()); assertEquals(60L, timerData.getTotalTime()); assertEquals(30L, timerData.getAverageTime()); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |