1 /*============================================================================
2 * Program timing information
3 *============================================================================*/
4
5 /*
6 This file is part of Code_Saturne, a general-purpose CFD tool.
7
8 Copyright (C) 1998-2021 EDF S.A.
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22 Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 /*----------------------------------------------------------------------------*/
26
27 #include "ecs_def.h"
28
29 /*-----------------------------------------------------------------------------*/
30
31 /*
32 * Standard C library headers
33 */
34
35 #include <time.h>
36
37 #if defined (HAVE_GETTIMEOFDAY)
38 #include <sys/time.h>
39 #endif
40
41 #if defined (HAVE_GETRUSAGE)
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <unistd.h>
45 #elif defined(_POSIX_SOURCE)
46 #include <sys/times.h>
47 #include <unistd.h>
48 #endif
49
50 /*
51 * Optional library and ECS headers
52 */
53
54 #include "ecs_def.h"
55 #include "ecs_timer.h"
56
57 /*-----------------------------------------------------------------------------*/
58
59 BEGIN_C_DECLS
60
61 /*-----------------------------------------------------------------------------
62 * Local type definitions
63 *-----------------------------------------------------------------------------*/
64
65 /*-----------------------------------------------------------------------------
66 * Local function prototypes
67 *-----------------------------------------------------------------------------*/
68
69 /*-----------------------------------------------------------------------------
70 * Local static variable definitions
71 *-----------------------------------------------------------------------------*/
72
73 static _Bool _ecs_timer_initialized = false;
74
75 /* Wall-clock time */
76
77 #if defined (HAVE_GETTIMEOFDAY)
78 static struct timeval _ecs_timer_wtime_tv_start;
79 #else
80 static time_t _ecs_timer_wtime_start;
81 #endif
82
83 /* CPU time */
84
85 #if defined (HAVE_GETRUSAGE)
86 #elif defined(_POSIX_SOURCE)
87 static time_t _ecs_timer_unit = 0;
88 #else
89 static clock_t _ecs_timer_clock_start;
90 #endif
91
92 /*-----------------------------------------------------------------------------
93 * Local function definitions
94 *-----------------------------------------------------------------------------*/
95
96 static void
_ecs_timer_initialize(void)97 _ecs_timer_initialize(void)
98 {
99 #if defined (HAVE_GETTIMEOFDAY)
100 (void)gettimeofday(&_ecs_timer_wtime_tv_start, NULL);
101 #else
102 (void)time(&_ecs_timer_wtime_start);
103 #endif
104
105 #if defined (HAVE_GETRUSAGE)
106 #elif defined(_POSIX_SOURCE)
107 _ecs_timer_unit = (double)sysconf(_SC_CLK_TCK);
108 #else
109 _ecs_timer_clock_start = clock();
110 #endif
111
112 _ecs_timer_initialized = true;
113 }
114
115 /*============================================================================
116 * Public function definitions
117 *============================================================================*/
118
119 /*!
120 * \brief Return Wall clock time
121 *
122 * \return elapsed time from first call of a function of the ecs_timer_...()
123 * series, or -1 if unable to compute.
124 */
125
126 double
ecs_timer_wtime(void)127 ecs_timer_wtime(void)
128 {
129 double this_wtime = -1.;
130
131 /* Ensure initialization */
132
133 if (_ecs_timer_initialized == false)
134 _ecs_timer_initialize();
135
136 /* Compute elapsed time */
137
138 #if defined (HAVE_GETTIMEOFDAY)
139
140 {
141 struct timeval wtime_tv_current;
142
143 if (gettimeofday(&wtime_tv_current, NULL) == 0) {
144
145 /* Perform carry for later subtraction */
146 if (_ecs_timer_wtime_tv_start.tv_usec > wtime_tv_current.tv_usec) {
147 int nsec = (_ecs_timer_wtime_tv_start.tv_usec - wtime_tv_current.tv_usec)
148 / 1000000 + 1;
149 wtime_tv_current.tv_usec += 1000000 * nsec;
150 wtime_tv_current.tv_sec -= nsec;
151 }
152 if ( wtime_tv_current.tv_usec - _ecs_timer_wtime_tv_start.tv_usec
153 > 1000000) {
154 int nsec = (wtime_tv_current.tv_usec - _ecs_timer_wtime_tv_start.tv_usec)
155 / 1000000;
156 wtime_tv_current.tv_usec -= 1000000 * nsec;
157 wtime_tv_current.tv_sec += nsec;
158 }
159
160 this_wtime = ( wtime_tv_current.tv_sec
161 - _ecs_timer_wtime_tv_start.tv_sec)
162 + ( wtime_tv_current.tv_usec
163 - _ecs_timer_wtime_tv_start.tv_usec) * 1.e-6 ;
164
165 }
166
167 }
168
169 #else
170
171 {
172 time_t wtime_current;
173
174 if (time(&wtime_current) != (time_t)-1)
175 this_wtime = difftime(wtime_current, _ecs_timer_wtime_start);
176 }
177
178 #endif
179
180 return this_wtime;
181 }
182
183 /*!
184 * \brief Return CPU time.
185 *
186 * Note that in the rare case that only the minimal C library clock()
187 * method is available (see ecs_timer_cpu_time_method()), at least one of
188 * the ecs_timer_...() functions (possibly this one) must be called
189 * upon program start for this function to be used. In addition,
190 * in this case, time may "loop" back to 0 every multiple of
191 * 2^size_t / CLOCKS_PER_SEC seconds.
192 *
193 * \return current CPU time usage, or -1 if unable to compute.
194 */
195
196 double
ecs_timer_cpu_time(void)197 ecs_timer_cpu_time(void)
198 {
199 double cpu_time = -1.;
200
201 /* Ensure initialization */
202
203 if (_ecs_timer_initialized == 0)
204 _ecs_timer_initialize();
205
206 /* Compute CPU time */
207
208 #if defined (HAVE_GETRUSAGE)
209
210 {
211 struct rusage usage;
212
213 if (getrusage(RUSAGE_SELF, &usage) == 0) {
214 cpu_time = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec
215 + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) * 1.e-6;
216 }
217 }
218
219 #elif defined(_POSIX_SOURCE)
220
221 {
222 static struct tms ptimer;
223
224 if (_ecs_timer_unit != -1 && times(&ptimer) != -1) {
225 cpu_time = ((double)(ptimer.tms_utime + ptimer.tms_stime))
226 / _ecs_timer_unit;
227 }
228
229 }
230
231 #else /* Use minimal C library function */
232
233 if (_ecs_timer_clock_start != -1) {
234
235 static clock_t clock_current;
236
237 clock_current = clock();
238 if (clock_current != (clock_t)-1)
239 cpu_time
240 = ((double)(clock_current - _ecs_timer_clock_start)) / CLOCKS_PER_SEC;
241
242 }
243
244 #endif
245
246 return cpu_time;
247 }
248
249 /*!
250 * \brief Return separate user and system CPU times.
251 *
252 * Note that in the rare case that only the minimal C library clock()
253 * method is available, this function will return -1 values.
254 *
255 * \param [out] user_time current user CPU usage.
256 * \param [out] system_time current system CPU usage.
257 */
258
259 void
ecs_timer_cpu_times(double * user_time,double * system_time)260 ecs_timer_cpu_times(double *user_time,
261 double *system_time)
262 {
263 /* Ensure initialization */
264
265 if (_ecs_timer_initialized == 0)
266 _ecs_timer_initialize();
267
268 *user_time = -1.;
269 *system_time = -1.;
270
271 /* Compute CPU time */
272
273 #if defined (HAVE_GETRUSAGE)
274
275 {
276 struct rusage usage;
277
278 if (getrusage(RUSAGE_SELF, &usage) == 0) {
279 *user_time = usage.ru_utime.tv_sec + usage.ru_utime.tv_usec * 1.e-6;
280 *system_time = usage.ru_stime.tv_sec + usage.ru_stime.tv_usec * 1.e-6;
281 }
282 }
283
284 #elif defined(_POSIX_SOURCE)
285
286 {
287 static struct tms ptimer;
288
289 if (_ecs_timer_unit != -1 && times(&ptimer) != -1) {
290 *user_time = ((double)ptimer.tms_utime) / _ecs_timer_unit;
291 *system_time = ((double)ptimer.tms_stime) / _ecs_timer_unit;
292 }
293
294 }
295
296 #endif
297 }
298
299 /*-----------------------------------------------------------------------------*/
300
301 END_C_DECLS
302