[project @ 1999-05-03 13:22:29 by sof]
[ghc-hetmet.git] / ghc / lib / std / cbits / getCPUTime.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: getCPUTime.c,v 1.5 1999/05/03 13:22:29 sof Exp $
5  *
6  * getCPUTime Runtime Support
7  */
8
9 #ifndef _AIX
10 #define NON_POSIX_SOURCE /*needed for solaris2 only?*/
11 #endif
12
13 /* how is this to work given we have not read platform.h yet? */
14 #ifdef hpux_TARGET_OS
15 #define _INCLUDE_HPUX_SOURCE
16 #endif
17
18 #include "Rts.h"
19
20 #ifdef HAVE_SYS_TYPES_H
21 #include <sys/types.h>
22 #endif
23
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #ifndef mingw32_TARGET_OS
29 # ifdef HAVE_SYS_TIMES_H
30 #  include <sys/times.h>
31 # endif
32 #endif
33
34 #ifdef HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #endif
37
38 #if !defined(mingw32_TARGET_OS) && !defined(irix_TARGET_OS)
39 # if defined(HAVE_SYS_RESOURCE_H)
40 #  include <sys/resource.h>
41 # endif
42 #endif
43
44 #ifdef HAVE_SYS_TIMEB_H
45 #include <sys/timeb.h>
46 #endif
47
48 #ifdef hpux_TARGET_OS
49 #include <sys/syscall.h>
50 #define getrusage(a, b)  syscall(SYS_GETRUSAGE, a, b)
51 #define HAVE_GETRUSAGE
52 #endif
53
54 #ifdef HAVE_WINDOWS_H
55 # include <windows.h>
56 #endif
57
58 StgInt 
59 clockTicks ()
60 {
61  return (
62 #if defined(CLK_TCK)
63     CLK_TCK
64 #else
65     sysconf(_SC_CLK_TCK)
66 #endif
67     ); 
68 }
69
70 /* 
71  * Our caller wants a pointer to four StgInts,
72  * user seconds, user nanoseconds, system seconds, system nanoseconds.
73  * Yes, the timerval has unsigned components, but nanoseconds take only
74  * 30 bits, and our CPU usage would have to be over 68 years for the 
75  * seconds to overflow 31 bits.
76  */
77
78 #ifndef _WIN32
79 StgByteArray
80 getCPUTime(StgByteArray cpuStruct)
81 {
82     StgInt *cpu=(StgInt *)cpuStruct;
83
84 /* getrusage() is right royal pain to deal with when targetting multiple
85    versions of Solaris, since some versions supply it in libc (2.3 and 2.5),
86    while 2.4 has got it in libucb (I wouldn't be too surprised if it was back
87    again in libucb in 2.6..)
88
89    Avoid the problem by resorting to times() instead.
90 */
91 #if defined(HAVE_GETRUSAGE) && ! irix_TARGET_OS && ! solaris2_TARGET_OS
92     struct rusage t;
93
94     getrusage(RUSAGE_SELF, &t);
95     cpu[0] = t.ru_utime.tv_sec;
96     cpu[1] = 1000 * t.ru_utime.tv_usec;
97     cpu[2] = t.ru_stime.tv_sec;
98     cpu[3] = 1000 * t.ru_stime.tv_usec;
99
100 #else
101 # if defined(HAVE_TIMES)
102     struct tms t;
103 #  if defined(CLK_TCK)
104 #   define ticks CLK_TCK
105 #  else
106     long ticks;
107     ticks = sysconf(_SC_CLK_TCK);
108 #  endif
109
110     times(&t);
111     cpu[0] = t.tms_utime / ticks;
112     cpu[1] = (t.tms_utime - cpu[0] * ticks) * (1000000000 / ticks);
113     cpu[2] = t.tms_stime / ticks;
114     cpu[3] = (t.tms_stime - cpu[2] * ticks) * (1000000000 / ticks);
115
116 # else
117     return NULL;
118 # endif
119 #endif
120     return (StgByteArray) cpuStruct;
121 }
122
123 #else
124
125 #ifdef _WIN32
126 /* 100ns units per sec, really */
127 #define NS_PER_SEC 10000000LL
128 #define FT2usecs(ll,ft)    \
129     (ll)=(ft).dwHighDateTime; \
130     (ll) <<= 32;              \
131     (ll) |= (ft).dwLowDateTime;
132
133 #endif
134
135 /* cygwin32 or mingw32 version */
136 StgByteArray
137 getCPUTime(StgByteArray cpuStruct)
138 {
139     FILETIME creationTime, exitTime, kernelTime, userTime;
140     StgInt *cpu=(StgInt *)cpuStruct;
141     unsigned long long uT, kT;
142  
143     /* ToDo: pin down elapsed times to just the OS thread(s) that
144        are evaluating/managing Haskell code.
145     */
146     if (!GetProcessTimes (GetCurrentProcess(), &creationTime,
147                           &exitTime, &kernelTime, &userTime)) {
148         /* Probably on a Win95 box..*/
149         cpu[0]=0;
150         cpu[1]=0;
151         cpu[2]=0;
152         cpu[3]=0;
153         return (StgByteArray)cpu;
154     }
155
156     FT2usecs(uT, userTime);
157     FT2usecs(kT, kernelTime);
158     
159     cpu[0] = (unsigned int)(uT / NS_PER_SEC);
160     cpu[1] = (unsigned int)(uT * 100);
161     cpu[0] = (unsigned int)(kT / NS_PER_SEC);
162     cpu[1] = (unsigned int)(kT * 100);
163     return (StgByteArray)cpu;
164 }
165
166 #endif /* _WIN32 */