Fix build on sparc64-linux-gnu.
[official-gcc.git] / libphobos / src / std / datetime / stopwatch.d
blob48e025bba0e91eefcba64b6ea716ef20141c9f17
1 // Written in the D programming language
3 /++
4 Module containing some basic benchmarking and timing functionality.
6 For convenience, this module publicly imports $(MREF core,time).
8 $(RED Unlike the other modules in std.datetime, this module is not currently
9 publicly imported in std.datetime.package, because the old
10 versions of this functionality which use
11 $(REF TickDuration,core,time) are in std.datetime.package and would
12 conflict with the symbols in this module. After the old symbols have
13 gone through the deprecation cycle and have been removed, then this
14 module will be publicly imported in std.datetime.package.)
16 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
17 Authors: Jonathan M Davis and Kato Shoichi
18 Source: $(PHOBOSSRC std/datetime/_stopwatch.d)
20 module std.datetime.stopwatch;
22 public import core.time;
23 import std.typecons : Flag;
25 /++
26 Used by StopWatch to indicate whether it should start immediately upon
27 construction.
29 If set to $(D AutoStart.no), then the StopWatch is not started when it is
30 constructed.
32 Otherwise, if set to $(D AutoStart.yes), then the StopWatch is started when
33 it is constructed.
35 alias AutoStart = Flag!"autoStart";
38 /++
39 StopWatch is used to measure time just like one would do with a physical
40 stopwatch, including stopping, restarting, and/or resetting it.
42 $(REF MonoTime,core,time) is used to hold the time, and it uses the system's
43 monotonic clock, which is high precision and never counts backwards (unlike
44 the wall clock time, which $(I can) count backwards, which is why
45 $(REF SysTime,std,datetime,systime) should not be used for timing).
47 Note that the precision of StopWatch differs from system to system. It is
48 impossible for it to be the same for all systems, since the precision of the
49 system clock and other system-dependent and situation-dependent factors
50 (such as the overhead of a context switch between threads) varies from system
51 to system and can affect StopWatch's accuracy.
53 struct StopWatch
55 public:
57 ///
58 @system nothrow @nogc unittest
60 import core.thread : Thread;
62 auto sw = StopWatch(AutoStart.yes);
64 Duration t1 = sw.peek();
65 Thread.sleep(usecs(1));
66 Duration t2 = sw.peek();
67 assert(t2 > t1);
69 Thread.sleep(usecs(1));
70 sw.stop();
72 Duration t3 = sw.peek();
73 assert(t3 > t2);
74 Duration t4 = sw.peek();
75 assert(t3 == t4);
77 sw.start();
78 Thread.sleep(usecs(1));
80 Duration t5 = sw.peek();
81 assert(t5 > t4);
83 // If stopping or resetting the StopWatch is not required, then
84 // MonoTime can easily be used by itself without StopWatch.
85 auto before = MonoTime.currTime;
86 // do stuff...
87 auto timeElapsed = MonoTime.currTime - before;
90 /++
91 Constructs a StopWatch. Whether it starts immediately depends on the
92 $(LREF AutoStart) argument.
94 If $(D StopWatch.init) is used, then the constructed StopWatch isn't
95 running (and can't be, since no constructor ran).
97 this(AutoStart autostart) @safe nothrow @nogc
99 if (autostart)
100 start();
104 @system nothrow @nogc unittest
106 import core.thread : Thread;
109 auto sw = StopWatch(AutoStart.yes);
110 assert(sw.running);
111 Thread.sleep(usecs(1));
112 assert(sw.peek() > Duration.zero);
115 auto sw = StopWatch(AutoStart.no);
116 assert(!sw.running);
117 Thread.sleep(usecs(1));
118 assert(sw.peek() == Duration.zero);
121 StopWatch sw;
122 assert(!sw.running);
123 Thread.sleep(usecs(1));
124 assert(sw.peek() == Duration.zero);
127 assert(StopWatch.init == StopWatch(AutoStart.no));
128 assert(StopWatch.init != StopWatch(AutoStart.yes));
133 Resets the StopWatch.
135 The StopWatch can be reset while it's running, and resetting it while
136 it's running will not cause it to stop.
138 void reset() @safe nothrow @nogc
140 if (_running)
141 _timeStarted = MonoTime.currTime;
142 _ticksElapsed = 0;
146 @system nothrow @nogc unittest
148 import core.thread : Thread;
150 auto sw = StopWatch(AutoStart.yes);
151 Thread.sleep(usecs(1));
152 sw.stop();
153 assert(sw.peek() > Duration.zero);
154 sw.reset();
155 assert(sw.peek() == Duration.zero);
158 @system nothrow @nogc unittest
160 import core.thread : Thread;
162 auto sw = StopWatch(AutoStart.yes);
163 Thread.sleep(msecs(1));
164 assert(sw.peek() > msecs(1));
165 immutable before = MonoTime.currTime;
167 // Just in case the system clock is slow enough or the system is fast
168 // enough for the call to MonoTime.currTime inside of reset to get
169 // the same that we just got by calling MonoTime.currTime.
170 Thread.sleep(usecs(1));
172 sw.reset();
173 assert(sw.peek() < msecs(1));
174 assert(sw._timeStarted > before);
175 assert(sw._timeStarted <= MonoTime.currTime);
180 Starts the StopWatch.
182 start should not be called if the StopWatch is already running.
184 void start() @safe nothrow @nogc
185 in { assert(!_running, "start was called when the StopWatch was already running."); }
186 body
188 _running = true;
189 _timeStarted = MonoTime.currTime;
193 @system nothrow @nogc unittest
195 import core.thread : Thread;
197 StopWatch sw;
198 assert(!sw.running);
199 assert(sw.peek() == Duration.zero);
200 sw.start();
201 assert(sw.running);
202 Thread.sleep(usecs(1));
203 assert(sw.peek() > Duration.zero);
208 Stops the StopWatch.
210 stop should not be called if the StopWatch is not running.
212 void stop() @safe nothrow @nogc
213 in { assert(_running, "stop was called when the StopWatch was not running."); }
214 body
216 _running = false;
217 _ticksElapsed += MonoTime.currTime.ticks - _timeStarted.ticks;
221 @system nothrow @nogc unittest
223 import core.thread : Thread;
225 auto sw = StopWatch(AutoStart.yes);
226 assert(sw.running);
227 Thread.sleep(usecs(1));
228 immutable t1 = sw.peek();
229 assert(t1 > Duration.zero);
231 sw.stop();
232 assert(!sw.running);
233 immutable t2 = sw.peek();
234 assert(t2 >= t1);
235 immutable t3 = sw.peek();
236 assert(t2 == t3);
241 Peek at the amount of time that the the StopWatch has been running.
243 This does not include any time during which the StopWatch was stopped but
244 does include $(I all) of the time that it was running and not just the
245 time since it was started last.
247 Calling $(LREF reset) will reset this to $(D Duration.zero).
249 Duration peek() @safe const nothrow @nogc
251 enum hnsecsPerSecond = convert!("seconds", "hnsecs")(1);
252 immutable hnsecsMeasured = convClockFreq(_ticksElapsed, MonoTime.ticksPerSecond, hnsecsPerSecond);
253 return _running ? MonoTime.currTime - _timeStarted + hnsecs(hnsecsMeasured)
254 : hnsecs(hnsecsMeasured);
258 @system nothrow @nogc unittest
260 import core.thread : Thread;
262 auto sw = StopWatch(AutoStart.no);
263 assert(sw.peek() == Duration.zero);
264 sw.start();
266 Thread.sleep(usecs(1));
267 assert(sw.peek() >= usecs(1));
269 Thread.sleep(usecs(1));
270 assert(sw.peek() >= usecs(2));
272 sw.stop();
273 immutable stopped = sw.peek();
274 Thread.sleep(usecs(1));
275 assert(sw.peek() == stopped);
277 sw.start();
278 Thread.sleep(usecs(1));
279 assert(sw.peek() > stopped);
282 @safe nothrow @nogc unittest
284 assert(StopWatch.init.peek() == Duration.zero);
289 Sets the total time which the StopWatch has been running (i.e. what peek
290 returns).
292 The StopWatch does not have to be stopped for setTimeElapsed to be
293 called, nor will calling it cause the StopWatch to stop.
295 void setTimeElapsed(Duration timeElapsed) @safe nothrow @nogc
297 enum hnsecsPerSecond = convert!("seconds", "hnsecs")(1);
298 _ticksElapsed = convClockFreq(timeElapsed.total!"hnsecs", hnsecsPerSecond, MonoTime.ticksPerSecond);
299 _timeStarted = MonoTime.currTime;
303 @system nothrow @nogc unittest
305 import core.thread : Thread;
307 StopWatch sw;
308 sw.setTimeElapsed(hours(1));
310 // As discussed in MonoTime's documentation, converting between
311 // Duration and ticks is not exact, though it will be close.
312 // How exact it is depends on the frequency/resolution of the
313 // system's monotonic clock.
314 assert(abs(sw.peek() - hours(1)) < usecs(1));
316 sw.start();
317 Thread.sleep(usecs(1));
318 assert(sw.peek() > hours(1) + usecs(1));
323 Returns whether this StopWatch is currently running.
325 @property bool running() @safe const pure nothrow @nogc
327 return _running;
331 @safe nothrow @nogc unittest
333 StopWatch sw;
334 assert(!sw.running);
335 sw.start();
336 assert(sw.running);
337 sw.stop();
338 assert(!sw.running);
342 private:
344 // We track the ticks for the elapsed time rather than a Duration so that we
345 // don't lose any precision.
347 bool _running = false; // Whether the StopWatch is currently running
348 MonoTime _timeStarted; // The time the StopWatch started measuring (i.e. when it was started or reset).
349 long _ticksElapsed; // Total time that the StopWatch ran before it was stopped last.
354 Benchmarks code for speed assessment and comparison.
356 Params:
357 fun = aliases of callable objects (e.g. function names). Each callable
358 object should take no arguments.
359 n = The number of times each function is to be executed.
361 Returns:
362 The amount of time (as a $(REF Duration,core,time)) that it took to call
363 each function $(D n) times. The first value is the length of time that
364 it took to call $(D fun[0]) $(D n) times. The second value is the length
365 of time it took to call $(D fun[1]) $(D n) times. Etc.
367 Duration[fun.length] benchmark(fun...)(uint n)
369 Duration[fun.length] result;
370 auto sw = StopWatch(AutoStart.yes);
372 foreach (i, unused; fun)
374 sw.reset();
375 foreach (_; 0 .. n)
376 fun[i]();
377 result[i] = sw.peek();
380 return result;
384 @safe unittest
386 import std.conv : to;
388 int a;
389 void f0() {}
390 void f1() { auto b = a; }
391 void f2() { auto b = to!string(a); }
392 auto r = benchmark!(f0, f1, f2)(10_000);
393 Duration f0Result = r[0]; // time f0 took to run 10,000 times
394 Duration f1Result = r[1]; // time f1 took to run 10,000 times
395 Duration f2Result = r[2]; // time f2 took to run 10,000 times
398 @safe nothrow unittest
400 import std.conv : to;
402 int a;
403 void f0() nothrow {}
404 void f1() nothrow { auto b = to!string(a); }
405 auto r = benchmark!(f0, f1)(1000);
406 version (GNU)
407 assert(r[0] >= Duration.zero);
408 else
409 assert(r[0] > Duration.zero);
410 assert(r[1] > Duration.zero);
411 assert(r[1] > r[0]);
412 assert(r[0] < seconds(1));
413 assert(r[1] < seconds(1));
416 @safe nothrow @nogc unittest
418 int f0Count;
419 int f1Count;
420 int f2Count;
421 void f0() nothrow @nogc { ++f0Count; }
422 void f1() nothrow @nogc { ++f1Count; }
423 void f2() nothrow @nogc { ++f2Count; }
424 auto r = benchmark!(f0, f1, f2)(552);
425 assert(f0Count == 552);
426 assert(f1Count == 552);
427 assert(f2Count == 552);