Prefer #if defined to #ifdef
[ghc.git] / rts / win32 / GetTime.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team 2005
4 *
5 * Machine-dependent time measurement functions
6 *
7 * ---------------------------------------------------------------------------*/
8
9 #include "Rts.h"
10 #include "GetTime.h"
11
12 #include <windows.h>
13
14 #if defined(HAVE_TIME_H)
15 # include <time.h>
16 #endif
17
18 /* Convert FILETIMEs into secs */
19
20 static inline Time
21 fileTimeToRtsTime(FILETIME ft)
22 {
23 Time t;
24 t = ((Time)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
25 t = NSToTime(t * 100);
26 /* FILETIMES are in units of 100ns */
27 return t;
28 }
29
30 void
31 getProcessTimes(Time *user, Time *elapsed)
32 {
33 *user = getProcessCPUTime();
34 *elapsed = getProcessElapsedTime();
35 }
36
37 Time
38 getProcessCPUTime(void)
39 {
40 FILETIME creationTime, exitTime, userTime, kernelTime = {0,0};
41
42 if (!GetProcessTimes(GetCurrentProcess(), &creationTime,
43 &exitTime, &kernelTime, &userTime)) {
44 return 0;
45 }
46
47 return fileTimeToRtsTime(userTime);
48 }
49
50 // Number of ticks per second used by the QueryPerformanceFrequency
51 // implementation, represented by a 64-bit union type.
52 static LARGE_INTEGER qpc_frequency = {.QuadPart = 0};
53
54 // Initialize qpc_frequency. This function should be called before any call to
55 // getMonotonicNSec. If QPC is not supported on this system, qpc_frequency is
56 // set to 0.
57 void initializeTimer()
58 {
59 BOOL qpc_supported = QueryPerformanceFrequency(&qpc_frequency);
60 if (!qpc_supported)
61 {
62 qpc_frequency.QuadPart = 0;
63 }
64 }
65
66 HsWord64
67 getMonotonicNSec()
68 {
69 if (qpc_frequency.QuadPart)
70 {
71 // system_time is a 64-bit union type used to represent the
72 // tick count returned by QueryPerformanceCounter
73 LARGE_INTEGER system_time;
74
75 // get the tick count.
76 QueryPerformanceCounter(&system_time);
77
78 // compute elapsed seconds as double
79 double secs = (double)system_time.QuadPart /
80 (double)qpc_frequency.QuadPart;
81
82 // return elapsed time in nanoseconds
83 return (HsWord64)(secs * 1e9);
84 }
85 else // fallback to GetTickCount
86 {
87 // NOTE: GetTickCount is a 32-bit millisecond value, so it wraps around
88 // every 49 days.
89 DWORD count = GetTickCount();
90
91 // getTickCount is in milliseconds, so multiply it by 1000000 to get
92 // nanoseconds.
93 return (HsWord64)count * 1000000;
94 }
95 }
96
97 Time
98 getProcessElapsedTime(void)
99 {
100 return NSToTime(getMonotonicNSec());
101 }
102
103 void
104 getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec)
105 {
106 /* Windows has a bunch of time APIs but none that directly give
107 us unix epoch time, so we have to do a little dance. */
108
109 SYSTEMTIME systime;
110 FILETIME filetime;
111 ULARGE_INTEGER unixtime;
112
113 /* Windows SYSTEMTIME is a big struct with fields for
114 year, month, day, hour, minute, second, millisecond. */
115 GetSystemTime(&systime);
116 /* Windows FILETIME timestamps use an epoch-based time,
117 using a 64bit unsigned word. The time is measured in
118 units of 100 nanoseconds since an epoch of 1601. */
119 SystemTimeToFileTime(&systime, &filetime);
120
121 /* FILETIME isn't directly a 64bit word, but a struct with
122 a pair of 32bit words, so we have to convert via a
123 ULARGE_INTEGER struct which is a handy union type */
124 unixtime.LowPart = filetime.dwLowDateTime;
125 unixtime.HighPart = filetime.dwHighDateTime;
126
127 /* We have to do an epoch conversion, since FILETIME uses 1601
128 while we want unix epoch of 1970. In case you were wondering,
129 there were 11,644,473,600 seconds between 1601 and 1970, then
130 multiply by 10^7 for units of 100 nanoseconds. */
131 unixtime.QuadPart = unixtime.QuadPart - 116444736000000000ull;
132
133 /* For the seconds part we use integer division by 10^7 */
134 *sec = unixtime.QuadPart / 10000000ull;
135
136 /* The remainder from integer division by 10^7 gives us
137 the sub-second component in units of 100 nanoseconds.
138 So for nanoseconds we just multiply by 100.
139 Note that nanoseconds always fits in a 32bit word */
140 *nsec = ((unsigned long)(unixtime.QuadPart % 10000000ull)) * 100ul;
141 }
142
143 W_
144 getPageFaults(void)
145 {
146 /* ToDo (on NT): better, get this via the performance data
147 that's stored in the registry. */
148 return 0;
149 }