1 #include <sys/time.h>
2
3 #include <errno.h>
4 #include <time.h>
5
6 #include "warnp.h"
7
8 #include "monoclock.h"
9
10 /* Determine which clock(s) to use. */
11 #ifndef POSIXFAIL_CLOCK_GETTIME
12 #ifdef CLOCK_MONOTONIC
13 #define USE_MONOTONIC
14 #endif
15 #ifndef POSIXFAIL_CLOCK_REALTIME
16 #define USE_REALTIME
17 #endif
18 #endif
19
20 /**
21 * monoclock_get(tv):
22 * Store the current time in ${tv}. If CLOCK_MONOTONIC is available, use
23 * that clock; if CLOCK_MONOTONIC is unavailable, use CLOCK_REALTIME (if
24 * available) or gettimeofday(2).
25 */
26 int
monoclock_get(struct timeval * tv)27 monoclock_get(struct timeval * tv)
28 {
29 #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
30 struct timespec tp;
31 #endif
32
33 #ifdef USE_MONOTONIC
34 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
35 tv->tv_sec = tp.tv_sec;
36 tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
37 } else if ((errno != ENOSYS) && (errno != EINVAL)) {
38 warnp("clock_gettime(CLOCK_MONOTONIC)");
39 goto err0;
40 } else
41 #endif
42 #ifdef USE_REALTIME
43 if (clock_gettime(CLOCK_REALTIME, &tp) == 0) {
44 tv->tv_sec = tp.tv_sec;
45 tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
46 } else {
47 warnp("clock_gettime(CLOCK_REALTIME)");
48 goto err0;
49 }
50 #else
51 if (gettimeofday(tv, NULL)) {
52 warnp("gettimeofday");
53 goto err0;
54 }
55 #endif
56
57 /* Success! */
58 return (0);
59
60 err0:
61 /* Failure! */
62 return (-1);
63 }
64
65 /**
66 * monoclock_get_cputime(tv):
67 * Store in ${tv} the duration the process has been running if
68 * CLOCK_PROCESS_CPUTIME_ID is available; fall back to monoclock_get()
69 * otherwise.
70 */
71 int
monoclock_get_cputime(struct timeval * tv)72 monoclock_get_cputime(struct timeval * tv)
73 {
74 /* Use CLOCK_PROCESS_CPUTIME_ID if available. */
75 #ifdef CLOCK_PROCESS_CPUTIME_ID
76 struct timespec tp;
77
78 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) == 0) {
79 tv->tv_sec = tp.tv_sec;
80 tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
81 } else if ((errno != ENOSYS) && (errno != EINVAL)) {
82 warnp("clock_gettime(CLOCK_PROCESS_CPUTIME_ID)");
83 goto err0;
84 } else
85 #endif
86 /* Fall back to monoclock_get(). */
87 if (monoclock_get(tv))
88 goto err0;
89
90 /* Success! */
91 return (0);
92
93 err0:
94 /* Failure! */
95 return (-1);
96 }
97
98 /**
99 * monoclock_getres(resd):
100 * Store an upper limit on timer granularity in ${resd}. If CLOCK_MONOTONIC is
101 * available, use that clock; if CLOCK_MONOTONIC is unavailable, use
102 * CLOCK_REALTIME (if available) or gettimeofday(2). For this value to be
103 * meaningful, we assume that clock_getres(x) succeeds iff clock_gettime(x)
104 * succeeds.
105 */
106 int
monoclock_getres(double * resd)107 monoclock_getres(double * resd)
108 {
109 #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
110 struct timespec res;
111 #endif
112
113 #ifdef USE_MONOTONIC
114 if (clock_getres(CLOCK_MONOTONIC, &res) == 0) {
115 /* Convert clock resolution to a double. */
116 *resd = (double)res.tv_sec + (double)res.tv_nsec * 0.000000001;
117 } else if ((errno != ENOSYS) && (errno != EINVAL)) {
118 warnp("clock_getres(CLOCK_MONOTONIC)");
119 goto err0;
120 } else
121 #endif
122 #ifdef USE_REALTIME
123 if (clock_getres(CLOCK_REALTIME, &res) == 0) {
124 /* Convert clock resolution to a double. */
125 *resd = (double)res.tv_sec + (double)res.tv_nsec * 0.000000001;
126 } else {
127 warnp("clock_getres(CLOCK_REALTIME)");
128 goto err0;
129 }
130 #else
131 /*
132 * We'll be using gettimeofday(). There is no standard way of getting
133 * the resolution of this clock, but it seems safe to assume that it
134 * ticks at a minimum rate of CLOCKS_PER_SEC Hz (even though that is
135 * defined in relation to the measurement of processor time usage, not
136 * wallclock time); on non-broken systems we'll be relying on
137 * clock_gettime and clock_getres anyway.
138 */
139 *resd = 1.0 / CLOCKS_PER_SEC;
140 #endif
141
142 /* Success! */
143 return (0);
144
145 #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
146 err0:
147 /* Failure! */
148 return (-1);
149 #endif
150 }
151