Skip to content

Commit

Permalink
Merge pull request #228 from gab1one/add-stopwatch
Browse files Browse the repository at this point in the history
Add StopWatch utility from imglib2-cache
  • Loading branch information
tpietzsch authored Sep 9, 2018
2 parents 4095c1e + d7efd58 commit 1b35dc9
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 0 deletions.
159 changes: 159 additions & 0 deletions src/main/java/net/imglib2/util/StopWatch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* #%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;

import java.text.DecimalFormat;

/**
* 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
* <a href="http://stackoverflow.com/a/8854104">stackoverflow</a>)
*
* @author Tobias Pietzsch
*/
public class StopWatch {

private long time;

private long total;

private long started;

private boolean running;

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

/**
* 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";
}
}
62 changes: 62 additions & 0 deletions src/test/java/net/imglib2/util/StopWatchTest.java
Original file line number Diff line number Diff line change
@@ -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));
}
}

0 comments on commit 1b35dc9

Please sign in to comment.