merge upstream HEAD
[ghc-hetmet.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
15 #ifdef HAVE_TIME_H
16 # include <time.h>
17 #endif
18
19 #ifdef HAVE_SYS_TIME_H
20 # include <sys/time.h>
21 #endif
22
23 #if HAVE_SYS_RESOURCE_H
24 # include <sys/resource.h>
25 #endif
26
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30
31 #ifdef HAVE_SYS_TIMES_H
32 # include <sys/times.h>
33 #endif
34
35 #ifdef USE_PAPI
36 # include <papi.h>
37 #endif
38
39 #if ! ((defined(HAVE_GETRUSAGE) && !irix_HOST_OS) || defined(HAVE_TIMES))
40 #error No implementation for getProcessCPUTime() available.
41 #endif
42
43 #if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_GETRUSAGE) && !irix_HOST_OS
44 // we'll implement getProcessCPUTime() and getProcessElapsedTime()
45 // separately, using getrusage() and gettimeofday() respectively
46
47 Ticks getProcessCPUTime(void)
48 {
49 #if !defined(BE_CONSERVATIVE) && defined(HAVE_CLOCK_GETTIME) && defined (_SC_CPUTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) && defined(HAVE_SYSCONF)
50     static int checked_sysconf = 0;
51     static int sysconf_result = 0;
52
53     if (!checked_sysconf) {
54         sysconf_result = sysconf(_SC_CPUTIME);
55         checked_sysconf = 1;
56     }
57     if (sysconf_result != -1) {
58         struct timespec ts;
59         int res;
60         res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
61         if (res == 0) {
62             return ((Ticks)ts.tv_sec * TICKS_PER_SECOND +
63                     ((Ticks)ts.tv_nsec * TICKS_PER_SECOND) / 1000000000);
64         }
65     }
66 #endif
67
68     // fallback to getrusage
69     {
70         struct rusage t;
71         getrusage(RUSAGE_SELF, &t);
72         return ((Ticks)t.ru_utime.tv_sec * TICKS_PER_SECOND +
73                 ((Ticks)t.ru_utime.tv_usec * TICKS_PER_SECOND)/1000000);
74     }
75 }
76
77 Ticks getProcessElapsedTime(void)
78 {
79     struct timeval tv;
80     gettimeofday(&tv, (struct timezone *) NULL);
81     return ((Ticks)tv.tv_sec * TICKS_PER_SECOND +
82             ((Ticks)tv.tv_usec * TICKS_PER_SECOND)/1000000);
83 }
84
85 void getProcessTimes(Ticks *user, Ticks *elapsed)
86 {
87     *user    = getProcessCPUTime();
88     *elapsed = getProcessElapsedTime();
89 }
90
91 #elif defined(HAVE_TIMES)
92
93 // we'll use the old times() API.
94
95 Ticks getProcessCPUTime(void)
96 {
97 #if !defined(THREADED_RTS) && USE_PAPI
98     long long usec;
99     if ((usec = PAPI_get_virt_usec()) < 0) {
100         barf("PAPI_get_virt_usec: %lld", usec);
101     }
102     return ((usec * TICKS_PER_SECOND) / 1000000);
103 #else
104     Ticks user, elapsed;
105     getProcessTimes(&user,&elapsed);
106     return user;
107 #endif
108 }
109
110 Ticks getProcessElapsedTime(void)
111 {
112     Ticks user, elapsed;
113     getProcessTimes(&user,&elapsed);
114     return elapsed;
115 }
116
117 void getProcessTimes(Ticks *user, Ticks *elapsed)
118 {
119     static nat ClockFreq = 0;
120
121     if (ClockFreq == 0) {
122 #if defined(HAVE_SYSCONF)
123         long ticks;
124         ticks = sysconf(_SC_CLK_TCK);
125         if ( ticks == -1 ) {
126             sysErrorBelch("sysconf");
127             stg_exit(EXIT_FAILURE);
128         }
129         ClockFreq = ticks;
130 #elif defined(CLK_TCK)          /* defined by POSIX */
131         ClockFreq = CLK_TCK;
132 #elif defined(HZ)
133         ClockFreq = HZ;
134 #elif defined(CLOCKS_PER_SEC)
135         ClockFreq = CLOCKS_PER_SEC;
136 #else
137         errorBelch("can't get clock resolution");
138         stg_exit(EXIT_FAILURE);
139 #endif
140     }
141
142     struct tms t;
143     clock_t r = times(&t);
144     *user = (((Ticks)t.tms_utime * TICKS_PER_SECOND) / ClockFreq);
145     *elapsed = (((Ticks)r * TICKS_PER_SECOND) / ClockFreq);
146 }
147
148 #endif // HAVE_TIMES
149
150 Ticks getThreadCPUTime(void)
151 {
152 #if USE_PAPI
153     long long usec;
154     if ((usec = PAPI_get_virt_usec()) < 0) {
155         barf("PAPI_get_virt_usec: %lld", usec);
156     }
157     return ((usec * TICKS_PER_SECOND) / 1000000);
158
159 #elif !defined(BE_CONSERVATIVE) && defined(HAVE_CLOCK_GETTIME) && defined (_SC_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_SYSCONF)
160     {
161         static int checked_sysconf = 0;
162         static int sysconf_result = 0;
163         
164         if (!checked_sysconf) {
165             sysconf_result = sysconf(_SC_THREAD_CPUTIME);
166             checked_sysconf = 1;
167         }
168         if (sysconf_result != -1) {
169             // clock_gettime() gives us per-thread CPU time.  It isn't
170             // reliable on Linux, but it's the best we have.
171             struct timespec ts;
172             int res;
173             res = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
174             if (res == 0) {
175                 return ((Ticks)ts.tv_sec * TICKS_PER_SECOND +
176                         ((Ticks)ts.tv_nsec * TICKS_PER_SECOND) / 1000000000);
177             }
178         }
179     }
180 #endif
181     return getProcessCPUTime();
182 }
183
184 nat
185 getPageFaults(void)
186 {
187 #if !defined(HAVE_GETRUSAGE) || irix_HOST_OS || haiku_HOST_OS
188     return 0;
189 #else
190     struct rusage t;
191     getrusage(RUSAGE_SELF, &t);
192     return(t.ru_majflt);
193 #endif
194 }
195