1 /**
2  * Stopwatch module.
3  * 
4  * Windows uses QueryPerformanceFrequency and QueryPerformanceCounter.
5  * Posix platforms use clock_gettime (CLOCK_MONOTONIC).
6  */
7 module stopwatch;
8 
9 version (Windows)
10 {
11     import core.sys.windows.windows;
12     private __gshared long __freq;
13 }
14 else version (Posix)
15 {
16     import core.sys.posix.time :
17         CLOCK_MONOTONIC, timespec, clock_getres, clock_gettime;
18     private enum CLOCK_TYPE = CLOCK_MONOTONIC;
19     private enum TIME_NS = 1.0e12;	// ns, used with clock_gettime
20     private enum TIME_US = 1.0e9;	// µs, used with clock_gettime
21     private enum TIME_MS = 1.0e6;	// ms, used with clock_gettime
22     private enum BASE    = TIME_US; // base time
23     private __gshared timespec __freq;
24 }
25 
26 struct stopwatch_t
27 {
28     version (Windows)
29     {
30         private alias time_t = long;
31     }
32     else version (Posix)
33     {
34         private alias time_t = timespec;
35     }
36     
37     private time_t time0, time1;
38     bool running;
39     
40     static void setup()
41     {
42         version (Windows)
43         {
44             LARGE_INTEGER l = void;
45             QueryPerformanceFrequency(&l);
46             __freq = l.QuadPart;
47         }
48         else version (Posix)
49         {
50             clock_getres(CLOCK_TYPE, &__freq);
51         }
52         //TODO: Take time delta to call os functions
53     }
54     
55     void start()
56     {
57         version (Windows)
58         {
59             LARGE_INTEGER l = void;
60             QueryPerformanceCounter(&l);
61             time0 = l.QuadPart;
62         }
63         else version (Posix)
64         {
65             clock_gettime(CLOCK_TYPE, &time0);
66         }
67         
68         running = true;
69     }
70     
71     void stop()
72     {
73         version (Windows)
74         {
75             LARGE_INTEGER l = void;
76             QueryPerformanceCounter(&l);
77             time1 = l.QuadPart;
78         }
79         else version (Posix)
80         {
81             clock_gettime(CLOCK_TYPE, &time1);
82         }
83         running = false;
84     }
85     
86     void reset()
87     {
88         time0 = time1 = time_t.init;
89     }
90     
91     float ms()
92     {
93         version (Windows)
94         {
95             return ((time1 - time0) * 1000.0f) / __freq;
96         }
97         else version (Posix)
98         {
99             return cast(float)
100                 ((BASE * (time1.tv_sec - time0.tv_sec))
101                 + time1.tv_nsec - time0.tv_nsec) / 1_000_000f;
102         }
103     }
104     
105     float us()
106     {
107         version (Windows)
108         {
109             return (time1 - time0) / __freq;
110         }
111         else version (Posix)
112         {
113             return cast(float)
114                 ((BASE * (time1.tv_sec - time0.tv_sec))
115                 + time1.tv_nsec - time0.tv_nsec) / 1_000f;
116         }
117     }
118 }