Addition of PAPI to 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
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(HAVE_CLOCK_GETTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
138 // clock_gettime() gives us per-thread CPU time. It isn't
139 // reliable on Linux, but it's the best we have.
140 struct timespec ts;
141 int res;
142 res = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
143 if (res == 0) {
144 return ((Ticks)ts.tv_sec * TICKS_PER_SECOND +
145 ((Ticks)ts.tv_nsec * TICKS_PER_SECOND) / 1000000000);
146 }
147 #endif
148 return getProcessCPUTime();
149 }
150
151 nat
152 getPageFaults(void)
153 {
154 #if !defined(HAVE_GETRUSAGE) || irix_HOST_OS
155 return 0;
156 #else
157 struct rusage t;
158 getrusage(RUSAGE_SELF, &t);
159 return(t.ru_majflt);
160 #endif
161 }
162