Enable new warning for fragile/incorrect CPP #if usage
[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 #if ! (defined(HAVE_GETRUSAGE) || defined(HAVE_TIMES))
25 #error No implementation for getProcessCPUTime() available.
26 #endif
27
28 #if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_GETRUSAGE)
29 // we'll implement getProcessCPUTime() and getProcessElapsedTime()
30 // separately, using getrusage() and gettimeofday() respectively
31
32 #if !defined(HAVE_CLOCK_GETTIME) && defined(darwin_HOST_OS)
33 static uint64_t timer_scaling_factor_numer = 0;
34 static uint64_t timer_scaling_factor_denom = 0;
35 #endif
36
37 void initializeTimer()
38 {
39 #if !defined(HAVE_CLOCK_GETTIME) && defined(darwin_HOST_OS)
40 mach_timebase_info_data_t info;
41 (void) mach_timebase_info(&info);
42 timer_scaling_factor_numer = (uint64_t)info.numer;
43 timer_scaling_factor_denom = (uint64_t)info.denom;
44 #endif
45 }
46
47 Time getProcessCPUTime(void)
48 {
49 #if !defined(BE_CONSERVATIVE) && \
50 defined(HAVE_CLOCK_GETTIME) && \
51 defined(_SC_CPUTIME) && \
52 defined(CLOCK_PROCESS_CPUTIME_ID) && \
53 defined(HAVE_SYSCONF)
54 static int checked_sysconf = 0;
55 static int sysconf_result = 0;
56
57 if (!checked_sysconf) {
58 sysconf_result = sysconf(_SC_CPUTIME);
59 checked_sysconf = 1;
60 }
61 if (sysconf_result != -1) {
62 struct timespec ts;
63 int res;
64 res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
65 if (res == 0) {
66 return SecondsToTime(ts.tv_sec) + NSToTime(ts.tv_nsec);
67 } else {
68 sysErrorBelch("clock_gettime");
69 stg_exit(EXIT_FAILURE);
70 }
71 }
72 #endif
73
74 // fallback to getrusage
75 {
76 struct rusage t;
77 getrusage(RUSAGE_SELF, &t);
78 return SecondsToTime(t.ru_utime.tv_sec) + USToTime(t.ru_utime.tv_usec);
79 }
80 }
81
82 StgWord64 getMonotonicNSec(void)
83 {
84 #if defined(HAVE_CLOCK_GETTIME)
85 struct timespec ts;
86 int res;
87
88 res = clock_gettime(CLOCK_ID, &ts);
89 if (res != 0) {
90 sysErrorBelch("clock_gettime");
91 stg_exit(EXIT_FAILURE);
92 }
93 return (StgWord64)ts.tv_sec * 1000000000 +
94 (StgWord64)ts.tv_nsec;
95
96 #elif defined(darwin_HOST_OS)
97
98 uint64_t time = mach_absolute_time();
99 return (time * timer_scaling_factor_numer) / timer_scaling_factor_denom;
100
101 #else // use gettimeofday()
102
103 struct timeval tv;
104
105 gettimeofday(&tv, (struct timezone *) NULL);
106 return (StgWord64)tv.tv_sec * 1000000000 +
107 (StgWord64)tv.tv_usec * 1000;
108
109 #endif
110 }
111
112 Time getProcessElapsedTime(void)
113 {
114 return NSToTime(getMonotonicNSec());
115 }
116
117 void getProcessTimes(Time *user, Time *elapsed)
118 {
119 *user = getProcessCPUTime();
120 *elapsed = getProcessElapsedTime();
121 }
122
123 #elif defined(HAVE_TIMES)
124
125 // we'll use the old times() API.
126
127 Time getProcessCPUTime(void)
128 {
129 Time user, elapsed;
130 getProcessTimes(&user,&elapsed);
131 return user;
132 }
133
134 Time getProcessElapsedTime(void)
135 {
136 Time user, elapsed;
137 getProcessTimes(&user,&elapsed);
138 return elapsed;
139 }
140
141 void getProcessTimes(Time *user, Time *elapsed)
142 {
143 static uint32_t ClockFreq = 0;
144
145 if (ClockFreq == 0) {
146 #if defined(HAVE_SYSCONF)
147 long ticks;
148 ticks = sysconf(_SC_CLK_TCK);
149 if ( ticks == -1 ) {
150 sysErrorBelch("sysconf");
151 stg_exit(EXIT_FAILURE);
152 }
153 ClockFreq = ticks;
154 #elif defined(CLK_TCK) /* defined by POSIX */
155 ClockFreq = CLK_TCK;
156 #elif defined(HZ)
157 ClockFreq = HZ;
158 #elif defined(CLOCKS_PER_SEC)
159 ClockFreq = CLOCKS_PER_SEC;
160 #else
161 errorBelch("can't get clock resolution");
162 stg_exit(EXIT_FAILURE);
163 #endif
164 }
165
166 struct tms t;
167 clock_t r = times(&t);
168 *user = SecondsToTime(t.tms_utime) / ClockFreq;
169 *elapsed = SecondsToTime(r) / ClockFreq;
170 }
171
172 #endif // HAVE_TIMES
173
174 void getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec)
175 {
176 #if defined(HAVE_GETTIMEOFDAY)
177 struct timeval tv;
178 gettimeofday(&tv, (struct timezone *) NULL);
179 *sec = tv.tv_sec;
180 *nsec = tv.tv_usec * 1000;
181 #else
182 /* Sigh, fall back to second resolution. */
183 time_t t;
184 time(&t);
185 *sec = t;
186 *nsec = 0;
187 #endif
188 }
189
190 W_
191 getPageFaults(void)
192 {
193 #if !defined(HAVE_GETRUSAGE) || defined(haiku_HOST_OS)
194 return 0;
195 #else
196 struct rusage t;
197 getrusage(RUSAGE_SELF, &t);
198 return(t.ru_majflt);
199 #endif
200 }