1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2007 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6       
7         version:        Feb 2007: Initial release
8         
9         author:         Kris
10 
11 *******************************************************************************/
12 
13 module tango.time.StopWatch;
14 
15 private import tango.core.Exception;
16 
17 /*******************************************************************************
18 
19 *******************************************************************************/
20 
21 version (Win32)
22 {
23         private extern (Windows) 
24         {
25         int QueryPerformanceCounter   (ulong *count);
26         int QueryPerformanceFrequency (ulong *frequency);
27         }
28 }
29 
30 version (Posix)
31 {
32         private import tango.stdc.posix.sys.time;
33 }
34 
35 /*******************************************************************************
36 
37         Timer for measuring small intervals, such as the duration of a 
38         subroutine or other reasonably small period.
39         ---
40         StopWatch elapsed;
41 
42         elapsed.start;
43 
44         // do something
45         // ...
46 
47         double i = elapsed.stop;
48         ---
49 
50         The measured interval is in units of seconds, using floating-
51         point to represent fractions. This approach is more flexible 
52         than integer arithmetic since it migrates trivially to more
53         capable timer hardware (there no implicit granularity to the
54         measurable intervals, except the limits of fp representation)
55 
56         StopWatch is accurate to the extent of what the underlying OS
57         supports. On linux systems, this accuracy is typically 1 us at 
58         best. Win32 is generally more precise. 
59 
60         There is some minor overhead in using StopWatch, so take that into 
61         account
62 
63 *******************************************************************************/
64 
65 public struct StopWatch
66 {
67         private ulong  started;
68         private static double multiplier = 1.0 / 1_000_000.0;
69 
70         version (Win32)
71                  private static double microsecond;
72 
73         /***********************************************************************
74                 
75                 Start the timer
76 
77         ***********************************************************************/
78         
79         void start ()
80         {
81                 started = timer;
82         }
83 
84         /***********************************************************************
85                 
86                 Stop the timer and return elapsed duration since start()
87 
88         ***********************************************************************/
89         
90         double stop ()
91         {
92                 return multiplier * (timer - started);
93         }
94 
95         /***********************************************************************
96                 
97                 Return elapsed time since the last start() as microseconds
98 
99         ***********************************************************************/
100         
101         @property ulong microsec ()
102         {
103                 version (Posix)
104                          return (timer - started);
105 
106                 version (Win32)
107                          return cast(ulong) ((timer - started) * microsecond);
108         }
109 
110         /***********************************************************************
111                 
112                 Setup timing information for later use
113 
114         ***********************************************************************/
115 
116         shared static this()
117         {
118                 version (Win32)
119                 {
120                         ulong freq;
121 
122                         QueryPerformanceFrequency (&freq);
123                         microsecond = 1_000_000.0 / freq;       
124                         multiplier = 1.0 / freq;       
125                 }
126         }
127 
128         /***********************************************************************
129                 
130                 Return the current time as an Interval
131 
132         ***********************************************************************/
133 
134         @property private static ulong timer ()
135         {
136                 version (Posix)       
137                 {
138                         timeval tv;
139                         if (gettimeofday (&tv, null))
140                             throw new PlatformException ("Timer :: linux timer is not available");
141 
142                         return (cast(ulong) tv.tv_sec * 1_000_000) + tv.tv_usec;
143                 }
144 
145                 version (Win32)
146                 {
147                         ulong now;
148 
149                         if (! QueryPerformanceCounter (&now))
150                               throw new PlatformException ("high-resolution timer is not available");
151 
152                         return now;
153                 }
154         }
155 }
156 
157 
158 /*******************************************************************************
159 
160 *******************************************************************************/
161 
162 debug (StopWatch)
163 {
164         import tango.io.Stdout;
165 
166         void main() 
167         {
168                 StopWatch t;
169                 t.start;
170 
171                 for (int i=0; i < 100_000_000; ++i)
172                     {}
173                 Stdout.format ("{:f9}", t.stop).newline;
174         }
175 }