Update Trac ticket URLs to point to GitLab
[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 // TODO: Remove this code path, it cannot be taken because
88 // `QueryPerformanceFrequency` cannot fail on Windows >= XP
89 // and GHC no longer supports Windows <= XP.
90 // See https://gitlab.haskell.org/ghc/ghc/issues/14233
91
92 // NOTE: GetTickCount is a 32-bit millisecond value, so it wraps around
93 // every 49 days.
94 DWORD count = GetTickCount();
95
96 // getTickCount is in milliseconds, so multiply it by 1000000 to get
97 // nanoseconds.
98 return (HsWord64)count * 1000000;
99 }
100 }
101
102 Time
103 getProcessElapsedTime(void)
104 {
105 return NSToTime(getMonotonicNSec());
106 }
107
108 void
109 getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec)
110 {
111 /* Windows has a bunch of time APIs but none that directly give
112 us unix epoch time, so we have to do a little dance. */
113
114 SYSTEMTIME systime;
115 FILETIME filetime;
116 ULARGE_INTEGER unixtime;
117
118 /* Windows SYSTEMTIME is a big struct with fields for
119 year, month, day, hour, minute, second, millisecond. */
120 GetSystemTime(&systime);
121 /* Windows FILETIME timestamps use an epoch-based time,
122 using a 64bit unsigned word. The time is measured in
123 units of 100 nanoseconds since an epoch of 1601. */
124 SystemTimeToFileTime(&systime, &filetime);
125
126 /* FILETIME isn't directly a 64bit word, but a struct with
127 a pair of 32bit words, so we have to convert via a
128 ULARGE_INTEGER struct which is a handy union type */
129 unixtime.LowPart = filetime.dwLowDateTime;
130 unixtime.HighPart = filetime.dwHighDateTime;
131
132 /* We have to do an epoch conversion, since FILETIME uses 1601
133 while we want unix epoch of 1970. In case you were wondering,
134 there were 11,644,473,600 seconds between 1601 and 1970, then
135 multiply by 10^7 for units of 100 nanoseconds. */
136 unixtime.QuadPart = unixtime.QuadPart - 116444736000000000ull;
137
138 /* For the seconds part we use integer division by 10^7 */
139 *sec = unixtime.QuadPart / 10000000ull;
140
141 /* The remainder from integer division by 10^7 gives us
142 the sub-second component in units of 100 nanoseconds.
143 So for nanoseconds we just multiply by 100.
144 Note that nanoseconds always fits in a 32bit word */
145 *nsec = ((unsigned long)(unixtime.QuadPart % 10000000ull)) * 100ul;
146 }
147
148 W_
149 getPageFaults(void)
150 {
151 /* ToDo (on NT): better, get this via the performance data
152 that's stored in the registry. */
153 return 0;
154 }