Move getMonotonicUSec from base to the RTS.
[ghc.git] / rts / posix / GetTime.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team 2005
4 *
5 * Machine-dependent time measurement functions
6 *
7 * ---------------------------------------------------------------------------*/
8
9 // Not POSIX, due to use of ru_majflt in getPageFaults()
10 // #include "PosixSource.h"
11
12 #include "Rts.h"
13 #include "GetTime.h"
14 #include "Clock.h"
15
16 #if HAVE_SYS_RESOURCE_H
17 # include <sys/resource.h>
18 #endif
19
20 #ifdef HAVE_SYS_TIMES_H
21 # include <sys/times.h>
22 #endif
23
24 #ifdef USE_PAPI
25 # include <papi.h>
26 #endif
27
28 #if ! ((defined(HAVE_GETRUSAGE) && !irix_HOST_OS) || defined(HAVE_TIMES))
29 #error No implementation for getProcessCPUTime() available.
30 #endif
31
32 #if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_GETRUSAGE) && !irix_HOST_OS
33 // we'll implement getProcessCPUTime() and getProcessElapsedTime()
34 // separately, using getrusage() and gettimeofday() respectively
35
36 #ifdef darwin_HOST_OS
37 static double timer_scaling_factor_ns = 0.0;
38 #endif
39
40 void initializeTimer()
41 {
42 #ifdef darwin_HOST_OS
43 mach_timebase_info_data_t info;
44 (void) mach_timebase_info(&info);
45 timer_scaling_factor_ns = (double)info.numer / (double)info.denom * 1e9;
46 #endif
47 }
48
49 Time getProcessCPUTime(void)
50 {
51 #if !defined(BE_CONSERVATIVE) && defined(HAVE_CLOCK_GETTIME) && defined (_SC_CPUTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) && defined(HAVE_SYSCONF)
52 static int checked_sysconf = 0;
53 static int sysconf_result = 0;
54
55 if (!checked_sysconf) {
56 sysconf_result = sysconf(_SC_CPUTIME);
57 checked_sysconf = 1;
58 }
59 if (sysconf_result != -1) {
60 struct timespec ts;
61 int res;
62 res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
63 if (res == 0) {
64 return SecondsToTime(ts.tv_sec) + NSToTime(ts.tv_nsec);
65 } else {
66 sysErrorBelch("clock_gettime");
67 stg_exit(EXIT_FAILURE);
68 }
69 }
70 #endif
71
72 // fallback to getrusage
73 {
74 struct rusage t;
75 getrusage(RUSAGE_SELF, &t);
76 return SecondsToTime(t.ru_utime.tv_sec) + USToTime(t.ru_utime.tv_usec);
77 }
78 }
79
80 StgWord64 getMonotonicNSec(void)
81 {
82 #ifdef HAVE_CLOCK_GETTIME
83 struct timespec ts;
84
85 clock_gettime(CLOCK_ID, &ts);
86 return (StgWord64)ts.tv_sec * 1000000000 +
87 (StgWord64)ts.tv_nsec;
88 #elif defined(darwin_HOST_OS)
89 uint64_t time = mach_absolute_time();
90 return (double)time * timer_scaling_factor_ns;
91 #else
92 struct timeval tv;
93
94 gettimeofday(&tv, (struct timezone *) NULL);
95 return (StgWord64)tv.tv_sec * 1000000000 +
96 (StgWord64)tv.tv_usec * 1000;
97 #endif
98 }
99
100 Time getProcessElapsedTime(void)
101 {
102 return NSToTime(getMonotonicNSec());
103 }
104
105 void getProcessTimes(Time *user, Time *elapsed)
106 {
107 *user = getProcessCPUTime();
108 *elapsed = getProcessElapsedTime();
109 }
110
111 #elif defined(HAVE_TIMES)
112
113 // we'll use the old times() API.
114
115 Time getProcessCPUTime(void)
116 {
117 #if !defined(THREADED_RTS) && USE_PAPI
118 long long usec;
119 if ((usec = PAPI_get_virt_usec()) < 0) {
120 barf("PAPI_get_virt_usec: %lld", usec);
121 }
122 return USToTime(usec);
123 #else
124 Time user, elapsed;
125 getProcessTimes(&user,&elapsed);
126 return user;
127 #endif
128 }
129
130 Time getProcessElapsedTime(void)
131 {
132 Time user, elapsed;
133 getProcessTimes(&user,&elapsed);
134 return elapsed;
135 }
136
137 void getProcessTimes(Time *user, Time *elapsed)
138 {
139 static nat ClockFreq = 0;
140
141 if (ClockFreq == 0) {
142 #if defined(HAVE_SYSCONF)
143 long ticks;
144 ticks = sysconf(_SC_CLK_TCK);
145 if ( ticks == -1 ) {
146 sysErrorBelch("sysconf");
147 stg_exit(EXIT_FAILURE);
148 }
149 ClockFreq = ticks;
150 #elif defined(CLK_TCK) /* defined by POSIX */
151 ClockFreq = CLK_TCK;
152 #elif defined(HZ)
153 ClockFreq = HZ;
154 #elif defined(CLOCKS_PER_SEC)
155 ClockFreq = CLOCKS_PER_SEC;
156 #else
157 errorBelch("can't get clock resolution");
158 stg_exit(EXIT_FAILURE);
159 #endif
160 }
161
162 struct tms t;
163 clock_t r = times(&t);
164 *user = SecondsToTime(t.tms_utime) / ClockFreq;
165 *elapsed = SecondsToTime(r) / ClockFreq;
166 }
167
168 #endif // HAVE_TIMES
169
170 Time getThreadCPUTime(void)
171 {
172 #if USE_PAPI
173 long long usec;
174 if ((usec = PAPI_get_virt_usec()) < 0) {
175 barf("PAPI_get_virt_usec: %lld", usec);
176 }
177 return USToTime(usec);
178
179 #elif !defined(BE_CONSERVATIVE) && defined(HAVE_CLOCK_GETTIME) && defined (_SC_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_SYSCONF)
180 {
181 static int checked_sysconf = 0;
182 static int sysconf_result = 0;
183
184 if (!checked_sysconf) {
185 sysconf_result = sysconf(_SC_THREAD_CPUTIME);
186 checked_sysconf = 1;
187 }
188 if (sysconf_result != -1) {
189 // clock_gettime() gives us per-thread CPU time. It isn't
190 // reliable on Linux, but it's the best we have.
191 struct timespec ts;
192 int res;
193 res = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
194 if (res == 0) {
195 return SecondsToTime(ts.tv_sec) + NSToTime(ts.tv_nsec);
196 }
197 }
198 }
199 #endif
200 return getProcessCPUTime();
201 }
202
203 void getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec)
204 {
205 #if defined(HAVE_GETTIMEOFDAY)
206 struct timeval tv;
207 gettimeofday(&tv, (struct timezone *) NULL);
208 *sec = tv.tv_sec;
209 *nsec = tv.tv_usec * 1000;
210 #else
211 /* Sigh, fall back to second resolution. */
212 time_t t;
213 time(&t);
214 *sec = t;
215 *nsec = 0;
216 #endif
217 }
218
219 nat
220 getPageFaults(void)
221 {
222 #if !defined(HAVE_GETRUSAGE) || irix_HOST_OS || haiku_HOST_OS
223 return 0;
224 #else
225 struct rusage t;
226 getrusage(RUSAGE_SELF, &t);
227 return(t.ru_majflt);
228 #endif
229 }
230