GetTime.c 4.73 KB
Newer Older
1
2
3
4
5
6
7
8
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team 2005
 *
 * Machine-dependent time measurement functions
 *
 * ---------------------------------------------------------------------------*/

9
10
11
// Not POSIX, due to use of ru_majflt in getPageFaults()
// #include "PosixSource.h"

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "Rts.h"
#include "GetTime.h"

#ifdef HAVE_TIME_H
# include <time.h>
#endif

#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif

#if HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif

#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif

mrchebas@gmail.com's avatar
mrchebas@gmail.com committed
35
36
37
38
#ifdef USE_PAPI
# include <papi.h>
#endif

39
40
41
42
#if ! ((defined(HAVE_GETRUSAGE) && !irix_HOST_OS) || defined(HAVE_TIMES))
#error No implementation for getProcessCPUTime() available.
#endif

43
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_GETRUSAGE) && !irix_HOST_OS
44
45
46
47
48
// we'll implement getProcessCPUTime() and getProcessElapsedTime()
// separately, using getrusage() and gettimeofday() respectively

Ticks getProcessCPUTime(void)
{
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#if !defined(BE_CONSERVATIVE) && defined(HAVE_CLOCK_GETTIME) && defined (_SC_CPUTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) && defined(HAVE_SYSCONF)
    static int checked_sysconf = 0;
    static int sysconf_result = 0;

    if (!checked_sysconf) {
        sysconf_result = sysconf(_SC_CPUTIME);
        checked_sysconf = 1;
    }
    if (sysconf_result != -1) {
        struct timespec ts;
        int res;
        res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
        if (res == 0) {
            return ((Ticks)ts.tv_sec * TICKS_PER_SECOND +
                    ((Ticks)ts.tv_nsec * TICKS_PER_SECOND) / 1000000000);
        }
    }
#endif

    // fallback to getrusage
    {
        struct rusage t;
        getrusage(RUSAGE_SELF, &t);
        return ((Ticks)t.ru_utime.tv_sec * TICKS_PER_SECOND +
                ((Ticks)t.ru_utime.tv_usec * TICKS_PER_SECOND)/1000000);
    }
75
76
77
78
79
80
}

Ticks getProcessElapsedTime(void)
{
    struct timeval tv;
    gettimeofday(&tv, (struct timezone *) NULL);
81
    return ((Ticks)tv.tv_sec * TICKS_PER_SECOND +
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
	    ((Ticks)tv.tv_usec * TICKS_PER_SECOND)/1000000);
}

void getProcessTimes(Ticks *user, Ticks *elapsed)
{
    *user    = getProcessCPUTime();
    *elapsed = getProcessElapsedTime();
}

#elif defined(HAVE_TIMES)

// we'll use the old times() API.

Ticks getProcessCPUTime(void)
{
mrchebas@gmail.com's avatar
mrchebas@gmail.com committed
97
98
99
100
101
102
103
#if !defined(THREADED_RTS) && USE_PAPI
    long long usec;
    if ((usec = PAPI_get_virt_usec()) < 0) {
	barf("PAPI_get_virt_usec: %lld", usec);
    }
    return ((usec * TICKS_PER_SECOND) / 1000000);
#else
104
105
106
    Ticks user, elapsed;
    getProcessTimes(&user,&elapsed);
    return user;
mrchebas@gmail.com's avatar
mrchebas@gmail.com committed
107
#endif
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
}

Ticks getProcessElapsedTime(void)
{
    Ticks user, elapsed;
    getProcessTimes(&user,&elapsed);
    return elapsed;
}

void getProcessTimes(Ticks *user, Ticks *elapsed)
{
    static nat ClockFreq = 0;

    if (ClockFreq == 0) {
#if defined(HAVE_SYSCONF)
	long ticks;
	ticks = sysconf(_SC_CLK_TCK);
	if ( ticks == -1 ) {
126
	    sysErrorBelch("sysconf");
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
	    stg_exit(EXIT_FAILURE);
	}
	ClockFreq = ticks;
#elif defined(CLK_TCK)		/* defined by POSIX */
	ClockFreq = CLK_TCK;
#elif defined(HZ)
	ClockFreq = HZ;
#elif defined(CLOCKS_PER_SEC)
	ClockFreq = CLOCKS_PER_SEC;
#else
	errorBelch("can't get clock resolution");
	stg_exit(EXIT_FAILURE);
#endif
    }

    struct tms t;
    clock_t r = times(&t);
    *user = (((Ticks)t.tms_utime * TICKS_PER_SECOND) / ClockFreq);
    *elapsed = (((Ticks)r * TICKS_PER_SECOND) / ClockFreq);
}

#endif // HAVE_TIMES

Ticks getThreadCPUTime(void)
{
mrchebas@gmail.com's avatar
mrchebas@gmail.com committed
152
153
154
155
156
157
158
#if USE_PAPI
    long long usec;
    if ((usec = PAPI_get_virt_usec()) < 0) {
	barf("PAPI_get_virt_usec: %lld", usec);
    }
    return ((usec * TICKS_PER_SECOND) / 1000000);

Simon Marlow's avatar
Simon Marlow committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#elif !defined(BE_CONSERVATIVE) && defined(HAVE_CLOCK_GETTIME) && defined (_SC_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_SYSCONF)
    {
        static int checked_sysconf = 0;
        static int sysconf_result = 0;
        
        if (!checked_sysconf) {
            sysconf_result = sysconf(_SC_THREAD_CPUTIME);
            checked_sysconf = 1;
        }
        if (sysconf_result != -1) {
            // clock_gettime() gives us per-thread CPU time.  It isn't
            // reliable on Linux, but it's the best we have.
            struct timespec ts;
            int res;
            res = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
            if (res == 0) {
                return ((Ticks)ts.tv_sec * TICKS_PER_SECOND +
                        ((Ticks)ts.tv_nsec * TICKS_PER_SECOND) / 1000000000);
            }
178
        }
Ian Lynagh's avatar
Ian Lynagh committed
179
    }
180
#endif
Ian Lynagh's avatar
Ian Lynagh committed
181
    return getProcessCPUTime();
182
183
184
185
186
}

nat
getPageFaults(void)
{
187
#if !defined(HAVE_GETRUSAGE) || irix_HOST_OS || haiku_HOST_OS
188
189
190
191
192
193
194
195
    return 0;
#else
    struct rusage t;
    getrusage(RUSAGE_SELF, &t);
    return(t.ru_majflt);
#endif
}