Comments on data type families
[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     struct rusage t;
50     getrusage(RUSAGE_SELF, &t);
51     return ((Ticks)t.ru_utime.tv_sec * TICKS_PER_SECOND +
52             ((Ticks)t.ru_utime.tv_usec * TICKS_PER_SECOND)/1000000);
53 }
54
55 Ticks getProcessElapsedTime(void)
56 {
57     struct timeval tv;
58     gettimeofday(&tv, (struct timezone *) NULL);
59     return ((Ticks)tv.tv_sec * TICKS_PER_SECOND +
60             ((Ticks)tv.tv_usec * TICKS_PER_SECOND)/1000000);
61 }
62
63 void getProcessTimes(Ticks *user, Ticks *elapsed)
64 {
65     *user    = getProcessCPUTime();
66     *elapsed = getProcessElapsedTime();
67 }
68
69 #elif defined(HAVE_TIMES)
70
71 // we'll use the old times() API.
72
73 Ticks getProcessCPUTime(void)
74 {
75 #if !defined(THREADED_RTS) && USE_PAPI
76     long long usec;
77     if ((usec = PAPI_get_virt_usec()) < 0) {
78         barf("PAPI_get_virt_usec: %lld", usec);
79     }
80     return ((usec * TICKS_PER_SECOND) / 1000000);
81 #else
82     Ticks user, elapsed;
83     getProcessTimes(&user,&elapsed);
84     return user;
85 #endif
86 }
87
88 Ticks getProcessElapsedTime(void)
89 {
90     Ticks user, elapsed;
91     getProcessTimes(&user,&elapsed);
92     return elapsed;
93 }
94
95 void getProcessTimes(Ticks *user, Ticks *elapsed)
96 {
97     static nat ClockFreq = 0;
98
99     if (ClockFreq == 0) {
100 #if defined(HAVE_SYSCONF)
101         long ticks;
102         ticks = sysconf(_SC_CLK_TCK);
103         if ( ticks == -1 ) {
104             sysErrorBelch("sysconf");
105             stg_exit(EXIT_FAILURE);
106         }
107         ClockFreq = ticks;
108 #elif defined(CLK_TCK)          /* defined by POSIX */
109         ClockFreq = CLK_TCK;
110 #elif defined(HZ)
111         ClockFreq = HZ;
112 #elif defined(CLOCKS_PER_SEC)
113         ClockFreq = CLOCKS_PER_SEC;
114 #else
115         errorBelch("can't get clock resolution");
116         stg_exit(EXIT_FAILURE);
117 #endif
118     }
119
120     struct tms t;
121     clock_t r = times(&t);
122     *user = (((Ticks)t.tms_utime * TICKS_PER_SECOND) / ClockFreq);
123     *elapsed = (((Ticks)r * TICKS_PER_SECOND) / ClockFreq);
124 }
125
126 #endif // HAVE_TIMES
127
128 Ticks getThreadCPUTime(void)
129 {
130 #if USE_PAPI
131     long long usec;
132     if ((usec = PAPI_get_virt_usec()) < 0) {
133         barf("PAPI_get_virt_usec: %lld", usec);
134     }
135     return ((usec * TICKS_PER_SECOND) / 1000000);
136
137 #elif !defined(BE_CONSERVATIVE) && defined(HAVE_CLOCK_GETTIME) && defined (_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_SYSCONF)
138     if (sysconf(_POSIX_THREAD_CPUTIME) != -1) {
139         // clock_gettime() gives us per-thread CPU time.  It isn't
140         // reliable on Linux, but it's the best we have.
141         struct timespec ts;
142         int res;
143         res = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
144         if (res == 0) {
145             return ((Ticks)ts.tv_sec * TICKS_PER_SECOND +
146                     ((Ticks)ts.tv_nsec * TICKS_PER_SECOND) / 1000000000);
147         }
148     }
149 #endif
150     return getProcessCPUTime();
151 }
152
153 nat
154 getPageFaults(void)
155 {
156 #if !defined(HAVE_GETRUSAGE) || irix_HOST_OS || haiku_HOST_OS
157     return 0;
158 #else
159     struct rusage t;
160     getrusage(RUSAGE_SELF, &t);
161     return(t.ru_majflt);
162 #endif
163 }
164