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