From 90155ad42725edd059c67198bb60165471aea83f Mon Sep 17 00:00:00 2001 From: Gabriel Einsdorf Date: Mon, 3 Sep 2018 11:39:48 +0200 Subject: [PATCH 1/2] Add StopWatch utility from imglib2-cache --- src/main/java/net/imglib2/util/StopWatch.java | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/main/java/net/imglib2/util/StopWatch.java diff --git a/src/main/java/net/imglib2/util/StopWatch.java b/src/main/java/net/imglib2/util/StopWatch.java new file mode 100644 index 0000000000..7c4534a7c3 --- /dev/null +++ b/src/main/java/net/imglib2/util/StopWatch.java @@ -0,0 +1,104 @@ +/* + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2016 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * + * 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 HOLDERS 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. + * #L% + */ +package net.imglib2.util; + +/** + * Utility class to measure time differences in nano-seconds, based on + * {@link System#nanoTime()}. It compensates glitches in + * {@link System#nanoTime()}, such that the stop time can never be earlier than + * the start time. (For example, see + * stackoverflow) + * + * @author Tobias Pietzsch + */ +public class StopWatch { + private long time; + + private long total; + + private long started; + + private boolean running; + + /** + * Construct new {@link StopWatch}. It is not running initially. Call + * {@link #start()} to start timing. + */ + public StopWatch() { + time = System.nanoTime(); + total = 0; + started = 0; + running = false; + } + + private long safeNanos() { + final long t = System.nanoTime(); + if (t > time) + time = t; + return time; + } + + /** + * Start the clock. + */ + public synchronized void start() { + if (running) + stop(); + started = safeNanos(); + running = true; + } + + /** + * Stop the clock. + */ + public synchronized void stop() { + if (running) + total += safeNanos() - started; + running = false; + } + + /** + * Get the total time the clock was running, in nano-seconds. Note that the + * clock can be started and stopped multiple times, accumulating the time + * intervals it was running in between. + * + * @return the total time the clock was running, in nano-seconds. + */ + public synchronized long nanoTime() { + if (running) + return total + safeNanos() - started; + else + return total; + } +} From d7efd5842a752eb630566315a583f0d768a5ab0e Mon Sep 17 00:00:00 2001 From: Matthias Arzt Date: Thu, 6 Sep 2018 14:57:56 +0200 Subject: [PATCH 2/2] StopWatch: add some useful methods Creating a stop watch with "new StopWatch()" is not very expressive: * StopWatch.createAndStart() * StopWatch.createStopped() needs less explanation, and avoids confusion. How many nanoseconds is one second? I'm always confused and therefor added the very useful method seconds(). Having a toString method is useful, to quickly print the StopWatch time on the console during debugging. --- src/main/java/net/imglib2/util/StopWatch.java | 61 +++++++++++++++++- .../java/net/imglib2/util/StopWatchTest.java | 62 +++++++++++++++++++ 2 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/test/java/net/imglib2/util/StopWatchTest.java diff --git a/src/main/java/net/imglib2/util/StopWatch.java b/src/main/java/net/imglib2/util/StopWatch.java index 7c4534a7c3..94683965c8 100644 --- a/src/main/java/net/imglib2/util/StopWatch.java +++ b/src/main/java/net/imglib2/util/StopWatch.java @@ -33,6 +33,8 @@ */ package net.imglib2.util; +import java.text.DecimalFormat; + /** * Utility class to measure time differences in nano-seconds, based on * {@link System#nanoTime()}. It compensates glitches in @@ -43,6 +45,7 @@ * @author Tobias Pietzsch */ public class StopWatch { + private long time; private long total; @@ -52,16 +55,34 @@ public class StopWatch { private boolean running; /** - * Construct new {@link StopWatch}. It is not running initially. Call - * {@link #start()} to start timing. + * Use {@link #createStopped()} or {@link #createAndStart()} to create a StopWatch. + * This constructor will also create a StopWatch, just like {@link #createStopped()}, + * but the more expressively named factory methods are preferred. */ - public StopWatch() { + private StopWatch() { time = System.nanoTime(); total = 0; started = 0; running = false; } + /** + * Construct new {@link StopWatch}. It is not running initially. Call + * {@link #start()} to start timing. + */ + public static StopWatch createStopped() { + return new StopWatch(); + } + + /** + * Construct and start a new {@link StopWatch}. + */ + public static StopWatch createAndStart() { + StopWatch sw = new StopWatch(); + sw.start(); + return sw; + } + private long safeNanos() { final long t = System.nanoTime(); if (t > time) @@ -101,4 +122,38 @@ public synchronized long nanoTime() { else return total; } + + /** + * Get the total time the clock was running in seconds. Note that the + * clock can be started and stopped multiple times, accumulating the time + * intervals it was running in between. + */ + public double seconds() { + return nanoTime() * 1e-9; + } + + /** + * Get the total time the clock was running as string. Note that the + * clock can be started and stopped multiple times, accumulating the time + * intervals it was running in between. + */ + @Override + public String toString() + { + return secondsToString( seconds() ); + } + + private static DecimalFormat format = new DecimalFormat("#0.000"); + + public static String secondsToString( double seconds ) + { + double abs = Math.abs( seconds ); + if ( abs < 1e-6 ) + return format.format( seconds * 1e9 ) + " ns"; + if ( abs < 1e-3 ) + return format.format( seconds * 1e6 ) + " \u00b5s"; + if ( abs < 1 ) + return format.format( seconds * 1e3 )+ " ms"; + return format.format( seconds ) + " s"; + } } diff --git a/src/test/java/net/imglib2/util/StopWatchTest.java b/src/test/java/net/imglib2/util/StopWatchTest.java new file mode 100644 index 0000000000..2dc8063b48 --- /dev/null +++ b/src/test/java/net/imglib2/util/StopWatchTest.java @@ -0,0 +1,62 @@ +package net.imglib2.util; + +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class StopWatchTest +{ + @Ignore // NB: This is not a test. But it's a short demo how StopWatch could be used during debugging. + @Test + public void demo() throws InterruptedException + { + StopWatch sw = StopWatch.createAndStart(); + Thread.sleep( 42 ); + System.out.println( sw ); + } + + @Ignore // NB: Time measurement depends on side effects. The test might sometimes fail. Better ignore to avoid confusion. + @Test + public void testCreateAndStart() throws InterruptedException + { + StopWatch sw = StopWatch.createAndStart(); + Thread.sleep( 42 ); + long nanoTime = sw.nanoTime(); + assertEquals( 42e6, nanoTime, 1e6); + } + + @Ignore // NB: Time measurement depends on side effects. The test might sometimes fail. Better ignore it to avoid confusion. + @Test + public void testStartStop() throws InterruptedException + { + StopWatch sw = StopWatch.createStopped(); + Thread.sleep( 10 ); + sw.start(); + Thread.sleep( 10 ); + sw.stop(); + Thread.sleep( 10 ); + long nanoTime = sw.nanoTime(); + assertEquals( 10e6, nanoTime, 1e6); + } + + @Ignore // NB: Time measurement depends on side effects. The test might sometimes fail. Better ignore it to avoid confusion. + @Test + public void testSeconds() throws InterruptedException + { + StopWatch sw = StopWatch.createAndStart(); + Thread.sleep( 42 ); + double time = sw.seconds(); + assertEquals( 0.042, time, 0.010); + } + + @Test + public void testSecondsToString() { + assertEquals("42.000 s", StopWatch.secondsToString(42)); + assertEquals("42.000 ms", StopWatch.secondsToString(42e-3)); + assertEquals("42.000 \u00b5s", StopWatch.secondsToString(42e-6)); + assertEquals("42.000 ns", StopWatch.secondsToString(42e-9)); + assertEquals("-42.000 ms", StopWatch.secondsToString(-42e-3)); + assertEquals("42.000 s", StopWatch.secondsToString(42.00000000001)); + } +}