xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/intrinsics/system_clock.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1181254a7Smrg /* Implementation of the SYSTEM_CLOCK intrinsic.
2*b1e83836Smrg    Copyright (C) 2004-2022 Free Software Foundation, Inc.
3181254a7Smrg 
4181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5181254a7Smrg 
6181254a7Smrg Libgfortran is free software; you can redistribute it and/or
7181254a7Smrg modify it under the terms of the GNU General Public
8181254a7Smrg License as published by the Free Software Foundation; either
9181254a7Smrg version 3 of the License, or (at your option) any later version.
10181254a7Smrg 
11181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
12181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14181254a7Smrg GNU General Public License for more details.
15181254a7Smrg 
16181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
17181254a7Smrg permissions described in the GCC Runtime Library Exception, version
18181254a7Smrg 3.1, as published by the Free Software Foundation.
19181254a7Smrg 
20181254a7Smrg You should have received a copy of the GNU General Public License and
21181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
22181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23181254a7Smrg <http://www.gnu.org/licenses/>.  */
24181254a7Smrg 
25181254a7Smrg #include "libgfortran.h"
26181254a7Smrg 
27181254a7Smrg #include <limits.h>
28181254a7Smrg 
29181254a7Smrg #include "time_1.h"
30181254a7Smrg 
31181254a7Smrg 
32181254a7Smrg #if !defined(__MINGW32__)
33181254a7Smrg 
34181254a7Smrg /* POSIX states that CLOCK_REALTIME must be present if clock_gettime
35181254a7Smrg    is available, others are optional.  */
36181254a7Smrg #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GETTIME_LIBRT)
37181254a7Smrg #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) \
38181254a7Smrg   && _POSIX_MONOTONIC_CLOCK >= 0
39181254a7Smrg #define GF_CLOCK_MONOTONIC CLOCK_MONOTONIC
40181254a7Smrg #else
41181254a7Smrg #define GF_CLOCK_MONOTONIC CLOCK_REALTIME
42181254a7Smrg #endif
43181254a7Smrg #endif
44181254a7Smrg 
45181254a7Smrg /* Weakref trickery for clock_gettime().  On Glibc <= 2.16,
46181254a7Smrg    clock_gettime() requires us to link in librt, which also pulls in
47181254a7Smrg    libpthread.  In order to avoid this by default, only call
48181254a7Smrg    clock_gettime() through a weak reference.  */
49181254a7Smrg #if SUPPORTS_WEAKREF && defined(HAVE_CLOCK_GETTIME_LIBRT)
50181254a7Smrg static int weak_gettime (clockid_t, struct timespec *)
51181254a7Smrg   __attribute__((__weakref__("clock_gettime")));
52181254a7Smrg #endif
53181254a7Smrg 
54181254a7Smrg 
55181254a7Smrg /* High resolution monotonic clock, falling back to the realtime clock
56181254a7Smrg    if the target does not support such a clock.
57181254a7Smrg 
58181254a7Smrg    Arguments:
59181254a7Smrg    secs     - OUTPUT, seconds
60181254a7Smrg    fracsecs - OUTPUT, fractional seconds, units given by tk argument
61181254a7Smrg    tk       - OUTPUT, clock resolution [counts/sec]
62181254a7Smrg 
63181254a7Smrg    If the target supports a monotonic clock, the OUTPUT arguments
64181254a7Smrg    represent a monotonically incrementing clock starting from some
65181254a7Smrg    unspecified time in the past.
66181254a7Smrg 
67181254a7Smrg    If a monotonic clock is not available, falls back to the realtime
68181254a7Smrg    clock which is not monotonic.
69181254a7Smrg 
70181254a7Smrg    Return value: 0 for success, -1 for error. In case of error, errno
71181254a7Smrg    is set.
72181254a7Smrg */
73181254a7Smrg static int
gf_gettime_mono(time_t * secs,long * fracsecs,long * tck)74181254a7Smrg gf_gettime_mono (time_t * secs, long * fracsecs, long * tck)
75181254a7Smrg {
76181254a7Smrg   int err;
77181254a7Smrg #ifdef HAVE_CLOCK_GETTIME
78181254a7Smrg   struct timespec ts;
79181254a7Smrg   *tck = 1000000000;
80181254a7Smrg   err = clock_gettime (GF_CLOCK_MONOTONIC, &ts);
81181254a7Smrg   *secs = ts.tv_sec;
82181254a7Smrg   *fracsecs = ts.tv_nsec;
83181254a7Smrg   return err;
84181254a7Smrg #else
85181254a7Smrg #if SUPPORTS_WEAKREF && defined(HAVE_CLOCK_GETTIME_LIBRT)
86181254a7Smrg   if (weak_gettime)
87181254a7Smrg     {
88181254a7Smrg       struct timespec ts;
89181254a7Smrg       *tck = 1000000000;
90181254a7Smrg       err = weak_gettime (GF_CLOCK_MONOTONIC, &ts);
91181254a7Smrg       *secs = ts.tv_sec;
92181254a7Smrg       *fracsecs = ts.tv_nsec;
93181254a7Smrg       return err;
94181254a7Smrg     }
95181254a7Smrg #endif
96181254a7Smrg   *tck = 1000000;
97181254a7Smrg   err = gf_gettime (secs, fracsecs);
98181254a7Smrg   return err;
99181254a7Smrg #endif
100181254a7Smrg }
101181254a7Smrg 
102181254a7Smrg #endif /* !__MINGW32__  */
103181254a7Smrg 
104181254a7Smrg extern void
105181254a7Smrg system_clock_4 (GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate,
106181254a7Smrg 		GFC_INTEGER_4 *count_max);
107181254a7Smrg export_proto(system_clock_4);
108181254a7Smrg 
109181254a7Smrg extern void
110181254a7Smrg system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate,
111181254a7Smrg 		GFC_INTEGER_8 *count_max);
112181254a7Smrg export_proto(system_clock_8);
113181254a7Smrg 
114181254a7Smrg 
115181254a7Smrg /* prefix(system_clock_4) is the INTEGER(4) version of the SYSTEM_CLOCK
116181254a7Smrg    intrinsic subroutine.  It returns the number of clock ticks for the current
117181254a7Smrg    system time, the number of ticks per second, and the maximum possible value
118181254a7Smrg    for COUNT.  */
119181254a7Smrg 
120181254a7Smrg void
system_clock_4(GFC_INTEGER_4 * count,GFC_INTEGER_4 * count_rate,GFC_INTEGER_4 * count_max)121181254a7Smrg system_clock_4 (GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate,
122181254a7Smrg 	       GFC_INTEGER_4 *count_max)
123181254a7Smrg {
124181254a7Smrg #if defined(__MINGW32__)
125181254a7Smrg   if (count)
126181254a7Smrg     {
127181254a7Smrg       /* Use GetTickCount here as the resolution and range is
128181254a7Smrg 	 sufficient for the INTEGER(kind=4) version, and
129181254a7Smrg 	 QueryPerformanceCounter has potential issues.  */
130181254a7Smrg       uint32_t cnt = GetTickCount ();
131181254a7Smrg       if (cnt > GFC_INTEGER_4_HUGE)
132181254a7Smrg 	cnt = cnt - GFC_INTEGER_4_HUGE - 1;
133181254a7Smrg       *count = cnt;
134181254a7Smrg     }
135181254a7Smrg   if (count_rate)
136181254a7Smrg     *count_rate = 1000;
137181254a7Smrg   if (count_max)
138181254a7Smrg     *count_max = GFC_INTEGER_4_HUGE;
139181254a7Smrg #else
140181254a7Smrg   time_t secs;
141181254a7Smrg   long fracsecs, tck;
142181254a7Smrg 
143181254a7Smrg   if (gf_gettime_mono (&secs, &fracsecs, &tck) == 0)
144181254a7Smrg     {
145181254a7Smrg       long tck_out = tck > 1000 ? 1000 : tck;
146181254a7Smrg       long tck_r = tck / tck_out;
147181254a7Smrg       GFC_UINTEGER_4 ucnt = (GFC_UINTEGER_4) secs * tck_out;
148181254a7Smrg       ucnt += fracsecs / tck_r;
149181254a7Smrg       if (ucnt > GFC_INTEGER_4_HUGE)
150181254a7Smrg 	ucnt = ucnt - GFC_INTEGER_4_HUGE - 1;
151181254a7Smrg       if (count)
152181254a7Smrg 	*count = ucnt;
153181254a7Smrg       if (count_rate)
154181254a7Smrg 	*count_rate = tck_out;
155181254a7Smrg       if (count_max)
156181254a7Smrg 	*count_max = GFC_INTEGER_4_HUGE;
157181254a7Smrg     }
158181254a7Smrg   else
159181254a7Smrg     {
160181254a7Smrg       if (count)
161181254a7Smrg 	*count = - GFC_INTEGER_4_HUGE;
162181254a7Smrg       if (count_rate)
163181254a7Smrg 	*count_rate = 0;
164181254a7Smrg       if (count_max)
165181254a7Smrg 	*count_max = 0;
166181254a7Smrg     }
167181254a7Smrg #endif
168181254a7Smrg }
169181254a7Smrg 
170181254a7Smrg 
171181254a7Smrg /* INTEGER(8) version of the above routine.  */
172181254a7Smrg 
173181254a7Smrg void
system_clock_8(GFC_INTEGER_8 * count,GFC_INTEGER_8 * count_rate,GFC_INTEGER_8 * count_max)174181254a7Smrg system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate,
175181254a7Smrg 		 GFC_INTEGER_8 *count_max)
176181254a7Smrg {
177181254a7Smrg #if defined(__MINGW32__)
178181254a7Smrg   LARGE_INTEGER cnt;
179181254a7Smrg   LARGE_INTEGER freq;
180181254a7Smrg   bool fail = false;
181181254a7Smrg   if (count && !QueryPerformanceCounter (&cnt))
182181254a7Smrg     fail = true;
183181254a7Smrg   if (count_rate && !QueryPerformanceFrequency (&freq))
184181254a7Smrg     fail = true;
185181254a7Smrg   if (fail)
186181254a7Smrg     {
187181254a7Smrg       if (count)
188181254a7Smrg 	*count = - GFC_INTEGER_8_HUGE;
189181254a7Smrg       if (count_rate)
190181254a7Smrg 	*count_rate = 0;
191181254a7Smrg       if (count_max)
192181254a7Smrg 	*count_max = 0;
193181254a7Smrg     }
194181254a7Smrg   else
195181254a7Smrg     {
196181254a7Smrg       if (count)
197181254a7Smrg 	*count = cnt.QuadPart;
198181254a7Smrg       if (count_rate)
199181254a7Smrg 	*count_rate = freq.QuadPart;
200181254a7Smrg       if (count_max)
201181254a7Smrg 	*count_max = GFC_INTEGER_8_HUGE;
202181254a7Smrg     }
203181254a7Smrg #else
204181254a7Smrg   time_t secs;
205181254a7Smrg   long fracsecs, tck;
206181254a7Smrg 
207181254a7Smrg   if (gf_gettime_mono (&secs, &fracsecs, &tck) == 0)
208181254a7Smrg     {
209181254a7Smrg       GFC_UINTEGER_8 ucnt = (GFC_UINTEGER_8) secs * tck;
210181254a7Smrg       ucnt += fracsecs;
211181254a7Smrg       if (ucnt > GFC_INTEGER_8_HUGE)
212181254a7Smrg 	ucnt = ucnt - GFC_INTEGER_8_HUGE - 1;
213181254a7Smrg       if (count)
214181254a7Smrg 	*count = ucnt;
215181254a7Smrg       if (count_rate)
216181254a7Smrg 	*count_rate = tck;
217181254a7Smrg       if (count_max)
218181254a7Smrg 	*count_max = GFC_INTEGER_8_HUGE;
219181254a7Smrg     }
220181254a7Smrg   else
221181254a7Smrg     {
222181254a7Smrg       if (count)
223181254a7Smrg 	*count = - GFC_INTEGER_8_HUGE;
224181254a7Smrg       if (count_rate)
225181254a7Smrg 	*count_rate = 0;
226181254a7Smrg       if (count_max)
227181254a7Smrg 	*count_max = 0;
228181254a7Smrg     }
229181254a7Smrg #endif
230181254a7Smrg }
231