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