Fix ~2000 second profiling time wrapping bug
[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 #if ! ((defined(HAVE_GETRUSAGE) && !irix_HOST_OS) || defined(HAVE_TIMES))
36 #error No implementation for getProcessCPUTime() available.
37 #endif
38
39 #if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_GETRUSAGE) && !irix_HOST_OS
40 // we'll implement getProcessCPUTime() and getProcessElapsedTime()
41 // separately, using getrusage() and gettimeofday() respectively
42
43 Ticks getProcessCPUTime(void)
44 {
45     struct rusage t;
46     getrusage(RUSAGE_SELF, &t);
47     return ((Ticks)t.ru_utime.tv_sec * TICKS_PER_SECOND + 
48             ((Ticks)t.ru_utime.tv_usec * TICKS_PER_SECOND)/1000000);
49 }
50
51 Ticks getProcessElapsedTime(void)
52 {
53     struct timeval tv;
54     gettimeofday(&tv, (struct timezone *) NULL);
55     return ((Ticks)tv.tv_sec * TICKS_PER_SECOND +
56             ((Ticks)tv.tv_usec * TICKS_PER_SECOND)/1000000);
57 }
58
59 void getProcessTimes(Ticks *user, Ticks *elapsed)
60 {
61     *user    = getProcessCPUTime();
62     *elapsed = getProcessElapsedTime();
63 }
64
65 #elif defined(HAVE_TIMES)
66
67 // we'll use the old times() API.
68
69 Ticks getProcessCPUTime(void)
70 {
71     Ticks user, elapsed;
72     getProcessTimes(&user,&elapsed);
73     return user;
74 }
75
76 Ticks getProcessElapsedTime(void)
77 {
78     Ticks user, elapsed;
79     getProcessTimes(&user,&elapsed);
80     return elapsed;
81 }
82
83 void getProcessTimes(Ticks *user, Ticks *elapsed)
84 {
85     static nat ClockFreq = 0;
86
87     if (ClockFreq == 0) {
88 #if defined(HAVE_SYSCONF)
89         long ticks;
90         ticks = sysconf(_SC_CLK_TCK);
91         if ( ticks == -1 ) {
92             sysErrorBelch("sysconf");
93             stg_exit(EXIT_FAILURE);
94         }
95         ClockFreq = ticks;
96 #elif defined(CLK_TCK)          /* defined by POSIX */
97         ClockFreq = CLK_TCK;
98 #elif defined(HZ)
99         ClockFreq = HZ;
100 #elif defined(CLOCKS_PER_SEC)
101         ClockFreq = CLOCKS_PER_SEC;
102 #else
103         errorBelch("can't get clock resolution");
104         stg_exit(EXIT_FAILURE);
105 #endif
106     }
107
108     struct tms t;
109     clock_t r = times(&t);
110     *user = (((Ticks)t.tms_utime * TICKS_PER_SECOND) / ClockFreq);
111     *elapsed = (((Ticks)r * TICKS_PER_SECOND) / ClockFreq);
112 }
113
114 #endif // HAVE_TIMES
115
116 Ticks getThreadCPUTime(void)
117 {
118 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
119     // clock_gettime() gives us per-thread CPU time.  It isn't
120     // reliable on Linux, but it's the best we have.
121     struct timespec ts;
122     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
123     return ((Ticks)ts.tv_sec * TICKS_PER_SECOND + 
124             ((Ticks)ts.tv_nsec * TICKS_PER_SECOND) / 1000000000);
125 #else
126     return getProcessCPUTime();
127 #endif
128 }
129
130 nat
131 getPageFaults(void)
132 {
133 #if !defined(HAVE_GETRUSAGE) || irix_HOST_OS
134     return 0;
135 #else
136     struct rusage t;
137     getrusage(RUSAGE_SELF, &t);
138     return(t.ru_majflt);
139 #endif
140 }
141