Skip to content

Commit 1b35dc9

Browse files
authored
Merge pull request #228 from gab1one/add-stopwatch
Add StopWatch utility from imglib2-cache
2 parents 4095c1e + d7efd58 commit 1b35dc9

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* #%L
3+
* ImgLib2: a general-purpose, multidimensional image processing library.
4+
* %%
5+
* Copyright (C) 2009 - 2016 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
6+
* John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
7+
* Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
8+
* Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
9+
* Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
10+
* Jean-Yves Tinevez and Michael Zinsmaier.
11+
* %%
12+
* Redistribution and use in source and binary forms, with or without
13+
* modification, are permitted provided that the following conditions are met:
14+
*
15+
* 1. Redistributions of source code must retain the above copyright notice,
16+
* this list of conditions and the following disclaimer.
17+
* 2. Redistributions in binary form must reproduce the above copyright notice,
18+
* this list of conditions and the following disclaimer in the documentation
19+
* and/or other materials provided with the distribution.
20+
*
21+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
25+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+
* POSSIBILITY OF SUCH DAMAGE.
32+
* #L%
33+
*/
34+
package net.imglib2.util;
35+
36+
import java.text.DecimalFormat;
37+
38+
/**
39+
* Utility class to measure time differences in nano-seconds, based on
40+
* {@link System#nanoTime()}. It compensates glitches in
41+
* {@link System#nanoTime()}, such that the stop time can never be earlier than
42+
* the start time. (For example, see
43+
* <a href="http://stackoverflow.com/a/8854104">stackoverflow</a>)
44+
*
45+
* @author Tobias Pietzsch
46+
*/
47+
public class StopWatch {
48+
49+
private long time;
50+
51+
private long total;
52+
53+
private long started;
54+
55+
private boolean running;
56+
57+
/**
58+
* Use {@link #createStopped()} or {@link #createAndStart()} to create a StopWatch.
59+
* This constructor will also create a StopWatch, just like {@link #createStopped()},
60+
* but the more expressively named factory methods are preferred.
61+
*/
62+
private StopWatch() {
63+
time = System.nanoTime();
64+
total = 0;
65+
started = 0;
66+
running = false;
67+
}
68+
69+
/**
70+
* Construct new {@link StopWatch}. It is not running initially. Call
71+
* {@link #start()} to start timing.
72+
*/
73+
public static StopWatch createStopped() {
74+
return new StopWatch();
75+
}
76+
77+
/**
78+
* Construct and start a new {@link StopWatch}.
79+
*/
80+
public static StopWatch createAndStart() {
81+
StopWatch sw = new StopWatch();
82+
sw.start();
83+
return sw;
84+
}
85+
86+
private long safeNanos() {
87+
final long t = System.nanoTime();
88+
if (t > time)
89+
time = t;
90+
return time;
91+
}
92+
93+
/**
94+
* Start the clock.
95+
*/
96+
public synchronized void start() {
97+
if (running)
98+
stop();
99+
started = safeNanos();
100+
running = true;
101+
}
102+
103+
/**
104+
* Stop the clock.
105+
*/
106+
public synchronized void stop() {
107+
if (running)
108+
total += safeNanos() - started;
109+
running = false;
110+
}
111+
112+
/**
113+
* Get the total time the clock was running, in nano-seconds. Note that the
114+
* clock can be started and stopped multiple times, accumulating the time
115+
* intervals it was running in between.
116+
*
117+
* @return the total time the clock was running, in nano-seconds.
118+
*/
119+
public synchronized long nanoTime() {
120+
if (running)
121+
return total + safeNanos() - started;
122+
else
123+
return total;
124+
}
125+
126+
/**
127+
* Get the total time the clock was running in seconds. Note that the
128+
* clock can be started and stopped multiple times, accumulating the time
129+
* intervals it was running in between.
130+
*/
131+
public double seconds() {
132+
return nanoTime() * 1e-9;
133+
}
134+
135+
/**
136+
* Get the total time the clock was running as string. Note that the
137+
* clock can be started and stopped multiple times, accumulating the time
138+
* intervals it was running in between.
139+
*/
140+
@Override
141+
public String toString()
142+
{
143+
return secondsToString( seconds() );
144+
}
145+
146+
private static DecimalFormat format = new DecimalFormat("#0.000");
147+
148+
public static String secondsToString( double seconds )
149+
{
150+
double abs = Math.abs( seconds );
151+
if ( abs < 1e-6 )
152+
return format.format( seconds * 1e9 ) + " ns";
153+
if ( abs < 1e-3 )
154+
return format.format( seconds * 1e6 ) + " \u00b5s";
155+
if ( abs < 1 )
156+
return format.format( seconds * 1e3 )+ " ms";
157+
return format.format( seconds ) + " s";
158+
}
159+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package net.imglib2.util;
2+
3+
import org.junit.Ignore;
4+
import org.junit.Test;
5+
6+
import static org.junit.Assert.assertEquals;
7+
8+
public class StopWatchTest
9+
{
10+
@Ignore // NB: This is not a test. But it's a short demo how StopWatch could be used during debugging.
11+
@Test
12+
public void demo() throws InterruptedException
13+
{
14+
StopWatch sw = StopWatch.createAndStart();
15+
Thread.sleep( 42 );
16+
System.out.println( sw );
17+
}
18+
19+
@Ignore // NB: Time measurement depends on side effects. The test might sometimes fail. Better ignore to avoid confusion.
20+
@Test
21+
public void testCreateAndStart() throws InterruptedException
22+
{
23+
StopWatch sw = StopWatch.createAndStart();
24+
Thread.sleep( 42 );
25+
long nanoTime = sw.nanoTime();
26+
assertEquals( 42e6, nanoTime, 1e6);
27+
}
28+
29+
@Ignore // NB: Time measurement depends on side effects. The test might sometimes fail. Better ignore it to avoid confusion.
30+
@Test
31+
public void testStartStop() throws InterruptedException
32+
{
33+
StopWatch sw = StopWatch.createStopped();
34+
Thread.sleep( 10 );
35+
sw.start();
36+
Thread.sleep( 10 );
37+
sw.stop();
38+
Thread.sleep( 10 );
39+
long nanoTime = sw.nanoTime();
40+
assertEquals( 10e6, nanoTime, 1e6);
41+
}
42+
43+
@Ignore // NB: Time measurement depends on side effects. The test might sometimes fail. Better ignore it to avoid confusion.
44+
@Test
45+
public void testSeconds() throws InterruptedException
46+
{
47+
StopWatch sw = StopWatch.createAndStart();
48+
Thread.sleep( 42 );
49+
double time = sw.seconds();
50+
assertEquals( 0.042, time, 0.010);
51+
}
52+
53+
@Test
54+
public void testSecondsToString() {
55+
assertEquals("42.000 s", StopWatch.secondsToString(42));
56+
assertEquals("42.000 ms", StopWatch.secondsToString(42e-3));
57+
assertEquals("42.000 \u00b5s", StopWatch.secondsToString(42e-6));
58+
assertEquals("42.000 ns", StopWatch.secondsToString(42e-9));
59+
assertEquals("-42.000 ms", StopWatch.secondsToString(-42e-3));
60+
assertEquals("42.000 s", StopWatch.secondsToString(42.00000000001));
61+
}
62+
}

0 commit comments

Comments
 (0)