1760c2415Smrg /* Wrappers for platform timing functions.
2*0bfacb9bSmrg    Copyright (C) 2003-2020 Free Software Foundation, Inc.
3760c2415Smrg 
4760c2415Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5760c2415Smrg 
6760c2415Smrg Libgfortran is free software; you can redistribute it and/or
7760c2415Smrg modify it under the terms of the GNU General Public
8760c2415Smrg License as published by the Free Software Foundation; either
9760c2415Smrg version 3 of the License, or (at your option) any later version.
10760c2415Smrg 
11760c2415Smrg Libgfortran is distributed in the hope that it will be useful,
12760c2415Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13760c2415Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14760c2415Smrg GNU General Public License for more details.
15760c2415Smrg 
16760c2415Smrg Under Section 7 of GPL version 3, you are granted additional
17760c2415Smrg permissions described in the GCC Runtime Library Exception, version
18760c2415Smrg 3.1, as published by the Free Software Foundation.
19760c2415Smrg 
20760c2415Smrg You should have received a copy of the GNU General Public License and
21760c2415Smrg a copy of the GCC Runtime Library Exception along with this program;
22760c2415Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23760c2415Smrg <http://www.gnu.org/licenses/>.  */
24760c2415Smrg 
25760c2415Smrg #ifndef LIBGFORTRAN_TIME_H
26760c2415Smrg #define LIBGFORTRAN_TIME_H
27760c2415Smrg 
28760c2415Smrg #ifdef HAVE_UNISTD_H
29760c2415Smrg #include <unistd.h>
30760c2415Smrg #endif
31760c2415Smrg 
32760c2415Smrg #include <errno.h>
33760c2415Smrg 
34760c2415Smrg /* The time related intrinsics (DTIME, ETIME, CPU_TIME) to "compare
35760c2415Smrg    different algorithms on the same computer or discover which parts
36760c2415Smrg    are the most expensive", need a way to get the CPU time with the
37760c2415Smrg    finest resolution possible. We can only be accurate up to
38760c2415Smrg    microseconds.
39760c2415Smrg 
40760c2415Smrg    As usual with UNIX systems, unfortunately no single way is
41760c2415Smrg    available for all systems.  */
42760c2415Smrg 
43760c2415Smrg #ifdef HAVE_SYS_TIME_H
44760c2415Smrg #include <sys/time.h>
45760c2415Smrg #endif
46760c2415Smrg 
47760c2415Smrg #include <time.h>
48760c2415Smrg 
49760c2415Smrg #ifdef HAVE_SYS_TYPES_H
50760c2415Smrg      #include <sys/types.h>
51760c2415Smrg #endif
52760c2415Smrg 
53760c2415Smrg /* The most accurate way to get the CPU time is getrusage (). */
54760c2415Smrg #if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H)
55760c2415Smrg #  include <sys/resource.h>
56760c2415Smrg #endif  /* HAVE_GETRUSAGE && HAVE_SYS_RESOURCE_H  */
57760c2415Smrg 
58760c2415Smrg /* The most accurate way to get the CPU time is getrusage ().
59760c2415Smrg    If we have times(), that's good enough, too.  */
60760c2415Smrg #if !defined (HAVE_GETRUSAGE) || !defined (HAVE_SYS_RESOURCE_H)
61760c2415Smrg /* For times(), we _must_ know the number of clock ticks per second.  */
62760c2415Smrg #  if defined (HAVE_TIMES) && (defined (HZ) || defined (_SC_CLK_TCK) || defined (CLK_TCK))
63760c2415Smrg #    ifdef HAVE_SYS_PARAM_H
64760c2415Smrg #      include <sys/param.h>
65760c2415Smrg #    endif
66760c2415Smrg #    if defined (HAVE_SYS_TIMES_H)
67760c2415Smrg #      include <sys/times.h>
68760c2415Smrg #    endif
69760c2415Smrg #    ifndef HZ
70760c2415Smrg #      if defined _SC_CLK_TCK
71760c2415Smrg #        define HZ  sysconf(_SC_CLK_TCK)
72760c2415Smrg #      else
73760c2415Smrg #        define HZ  CLK_TCK
74760c2415Smrg #      endif
75760c2415Smrg #    endif
76760c2415Smrg #  endif  /* HAVE_TIMES etc.  */
77760c2415Smrg #endif  /* !HAVE_GETRUSAGE || !HAVE_SYS_RESOURCE_H  */
78760c2415Smrg 
79760c2415Smrg 
80760c2415Smrg /* If the re-entrant version of localtime is not available, provide a
81760c2415Smrg    fallback implementation.  On some targets where the _r version is
82760c2415Smrg    not available, localtime uses thread-local storage so it's
83760c2415Smrg    threadsafe.  */
84760c2415Smrg 
85760c2415Smrg #ifndef HAVE_LOCALTIME_R
86760c2415Smrg /* If _POSIX is defined localtime_r gets defined by mingw-w64 headers.  */
87760c2415Smrg #ifdef localtime_r
88760c2415Smrg #undef localtime_r
89760c2415Smrg #endif
90760c2415Smrg 
91760c2415Smrg static inline struct tm *
localtime_r(const time_t * timep,struct tm * result)92760c2415Smrg localtime_r (const time_t * timep, struct tm * result)
93760c2415Smrg {
94760c2415Smrg   *result = *localtime (timep);
95760c2415Smrg   return result;
96760c2415Smrg }
97760c2415Smrg #endif
98760c2415Smrg 
99760c2415Smrg 
100760c2415Smrg /* Helper function for the actual implementation of the DTIME, ETIME and
101760c2415Smrg    CPU_TIME intrinsics.  Returns 0 for success or -1 if no
102760c2415Smrg    CPU time could be computed.  */
103760c2415Smrg 
104760c2415Smrg #if defined(__MINGW32__)
105760c2415Smrg 
106760c2415Smrg #define WIN32_LEAN_AND_MEAN
107760c2415Smrg #include <windows.h>
108760c2415Smrg 
109760c2415Smrg static inline int
gf_cputime(long * user_sec,long * user_usec,long * system_sec,long * system_usec)110760c2415Smrg gf_cputime (long *user_sec, long *user_usec, long *system_sec, long *system_usec)
111760c2415Smrg {
112760c2415Smrg   union {
113760c2415Smrg     FILETIME ft;
114760c2415Smrg     unsigned long long ulltime;
115760c2415Smrg   } kernel_time,  user_time;
116760c2415Smrg 
117760c2415Smrg   FILETIME unused1, unused2;
118760c2415Smrg 
119760c2415Smrg   /* No support for Win9x.  The high order bit of the DWORD
120760c2415Smrg      returned by GetVersion is 0 for NT and higher. */
121760c2415Smrg   if (GetVersion () >= 0x80000000)
122760c2415Smrg     {
123760c2415Smrg       *user_sec = *system_sec = 0;
124760c2415Smrg       *user_usec = *system_usec = 0;
125760c2415Smrg       return -1;
126760c2415Smrg     }
127760c2415Smrg 
128760c2415Smrg   /* The FILETIME structs filled in by GetProcessTimes represent
129760c2415Smrg      time in 100 nanosecond units. */
130760c2415Smrg   GetProcessTimes (GetCurrentProcess (), &unused1, &unused2,
131760c2415Smrg               	   &kernel_time.ft, &user_time.ft);
132760c2415Smrg 
133760c2415Smrg   *user_sec = user_time.ulltime / 10000000;
134760c2415Smrg   *user_usec = (user_time.ulltime % 10000000) / 10;
135760c2415Smrg 
136760c2415Smrg   *system_sec = kernel_time.ulltime / 10000000;
137760c2415Smrg   *system_usec = (kernel_time.ulltime % 10000000) / 10;
138760c2415Smrg   return 0;
139760c2415Smrg }
140760c2415Smrg 
141760c2415Smrg #else
142760c2415Smrg 
143760c2415Smrg static inline int
gf_cputime(long * user_sec,long * user_usec,long * system_sec,long * system_usec)144760c2415Smrg gf_cputime (long *user_sec, long *user_usec, long *system_sec, long *system_usec)
145760c2415Smrg {
146760c2415Smrg #if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H)
147760c2415Smrg   struct rusage usage;
148760c2415Smrg   int err;
149760c2415Smrg   err = getrusage (RUSAGE_SELF, &usage);
150760c2415Smrg 
151760c2415Smrg   *user_sec = usage.ru_utime.tv_sec;
152760c2415Smrg   *user_usec = usage.ru_utime.tv_usec;
153760c2415Smrg   *system_sec = usage.ru_stime.tv_sec;
154760c2415Smrg   *system_usec = usage.ru_stime.tv_usec;
155760c2415Smrg   return err;
156760c2415Smrg 
157760c2415Smrg #elif defined HAVE_TIMES
158760c2415Smrg   struct tms buf;
159760c2415Smrg   clock_t err;
160760c2415Smrg   err = times (&buf);
161760c2415Smrg   long hz = HZ;
162760c2415Smrg   *user_sec = buf.tms_utime / hz;
163760c2415Smrg   *user_usec = (buf.tms_utime % hz) * (1000000. / hz);
164760c2415Smrg   *system_sec = buf.tms_stime / hz;
165760c2415Smrg   *system_usec = (buf.tms_stime % hz) * (1000000. / hz);
166760c2415Smrg   if ((err == (clock_t) -1) && errno != 0)
167760c2415Smrg     return -1;
168760c2415Smrg   return 0;
169760c2415Smrg 
170760c2415Smrg #elif defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_PROCESS_CPUTIME_ID) \
171760c2415Smrg 				      || defined(CLOCK_THREAD_CPUTIME_ID))
172760c2415Smrg   /* Newer versions of VxWorks have CLOCK_THREAD_CPUTIME_ID giving
173760c2415Smrg      per-thread CPU time.  CLOCK_PROCESS_CPUTIME_ID would be better
174760c2415Smrg      but is not available.  */
175760c2415Smrg #ifndef CLOCK_PROCESS_CPUTIME_ID
176760c2415Smrg #define CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID
177760c2415Smrg #endif
178760c2415Smrg   struct timespec ts;
179760c2415Smrg   int err = clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts);
180760c2415Smrg   *user_sec = ts.tv_sec;
181760c2415Smrg   *user_usec = ts.tv_nsec / 1000;
182760c2415Smrg   *system_sec = *system_usec = 0;
183760c2415Smrg   return err;
184760c2415Smrg 
185760c2415Smrg #else
186760c2415Smrg   clock_t c = clock ();
187760c2415Smrg   *user_sec = c / CLOCKS_PER_SEC;
188760c2415Smrg   *user_usec = (c % CLOCKS_PER_SEC) * (1000000. / CLOCKS_PER_SEC);
189760c2415Smrg   *system_sec = *system_usec = 0;
190760c2415Smrg   if (c == (clock_t) -1)
191760c2415Smrg     return -1;
192760c2415Smrg   return 0;
193760c2415Smrg 
194760c2415Smrg #endif
195760c2415Smrg }
196760c2415Smrg 
197760c2415Smrg #endif
198760c2415Smrg 
199760c2415Smrg 
200760c2415Smrg /* Realtime clock with microsecond resolution, falling back to other
201760c2415Smrg    functions if the target does not support gettimeofday().
202760c2415Smrg 
203760c2415Smrg    Arguments:
204760c2415Smrg    secs     - OUTPUT, seconds
205760c2415Smrg    usecs    - OUTPUT, microseconds
206760c2415Smrg 
207760c2415Smrg    The OUTPUT arguments shall represent the number of seconds and
208760c2415Smrg    microseconds since the Epoch.
209760c2415Smrg 
210760c2415Smrg    Return value: 0 for success, -1 for error. In case of error, errno
211760c2415Smrg    is set.
212760c2415Smrg */
213760c2415Smrg static inline int
gf_gettime(time_t * secs,long * usecs)214760c2415Smrg gf_gettime (time_t * secs, long * usecs)
215760c2415Smrg {
216760c2415Smrg #ifdef HAVE_GETTIMEOFDAY
217760c2415Smrg   struct timeval tv;
218760c2415Smrg   int err;
219760c2415Smrg   err = gettimeofday (&tv, NULL);
220760c2415Smrg   *secs = tv.tv_sec;
221760c2415Smrg   *usecs = tv.tv_usec;
222760c2415Smrg   return err;
223760c2415Smrg #elif defined(HAVE_CLOCK_GETTIME)
224760c2415Smrg   struct timespec ts;
225760c2415Smrg   int err = clock_gettime (CLOCK_REALTIME, &ts);
226760c2415Smrg   *secs = ts.tv_sec;
227760c2415Smrg   *usecs = ts.tv_nsec / 1000;
228760c2415Smrg   return err;
229760c2415Smrg #else
230760c2415Smrg   time_t t = time (NULL);
231760c2415Smrg   *secs = t;
232760c2415Smrg   *usecs = 0;
233760c2415Smrg   if (t == ((time_t)-1))
234760c2415Smrg     return -1;
235760c2415Smrg   return 0;
236760c2415Smrg #endif
237760c2415Smrg }
238760c2415Smrg 
239760c2415Smrg 
240760c2415Smrg #endif /* LIBGFORTRAN_TIME_H */
241