exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / gettime-res.c
blob8bde4122a78297dc1fa88d33e84f805dea9e0925
1 /* Get the system clock resolution.
3 Copyright 2021-2024 Free Software Foundation, Inc.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation, either version 3 of the
8 License, or (at your option) any later version.
10 This file is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Paul Eggert. */
20 #include <config.h>
22 #include "timespec.h"
24 static long int _GL_ATTRIBUTE_CONST
25 gcd (long int a, long int b)
27 while (b != 0)
29 long int r = a % b;
30 a = b;
31 b = r;
33 return a;
36 /* Return the system time resolution in nanoseconds. */
38 long int
39 gettime_res (void)
41 #if defined __sun && defined __sparc
42 /* On Solaris 11.4/SPARC (with a SPARC-M8 CPU)
43 clock_getres (CLOCK_REALTIME, ...) returns a resolution of 1000000 ns,
44 and clock_gettime (CLOCK_REALTIME) returns a multiple of 5 ns with a
45 probability of ca. 1 - 1/300000. Thus the heuristic below with the
46 32 samples guesses a resolution of 5 ns with a probability of ca.
47 1 - 1/10000. But occasionally clock_gettime (CLOCK_REALTIME) returns
48 only a multiple of 1 ns.
49 Simple guesswork is not enough to cope with this irregular behaviour.
50 Therefore, here is an override. */
51 return 1;
52 #else
53 struct timespec res;
54 # if defined CLOCK_REALTIME && HAVE_CLOCK_GETRES
55 clock_getres (CLOCK_REALTIME, &res);
56 # elif defined HAVE_TIMESPEC_GETRES
57 timespec_getres (&res, TIME_UTC);
58 # else
59 /* Guess high and let the later code deduce better. */
60 res.tv_sec = 1;
61 res.tv_nsec = 0;
62 # endif
64 /* On all Gnulib platforms the following calculations do not overflow. */
66 long int hz = TIMESPEC_HZ;
67 long int r = res.tv_nsec <= 0 ? hz : res.tv_nsec;
68 struct timespec earlier = { .tv_nsec = -1 };
70 /* On some platforms, clock_getres (CLOCK_REALTIME, ...) yields a
71 too-large resolution, under the mistaken theory that it should
72 return the timer interval. For example, on AIX 7.2 POWER8
73 clock_getres yields 10 ms even though clock_gettime yields 1 μs
74 resolution. Work around the problem with high probability by
75 trying clock_gettime several times and observing the resulting
76 bounds on resolution. */
77 int nsamples = 32;
78 for (int i = 0; 1 < r && i < nsamples; i++)
80 /* If successive timestamps disagree the clock resolution must
81 be small, so exit the inner loop to check this sample.
82 Otherwise, arrange for the outer loop to exit but continue
83 the inner-loop search for a differing timestamp sample. */
84 struct timespec now;
85 for (;; i = nsamples)
87 now = current_timespec ();
88 if (earlier.tv_nsec != now.tv_nsec || earlier.tv_sec != now.tv_sec)
89 break;
91 earlier = now;
93 if (0 < now.tv_nsec)
94 r = gcd (r, now.tv_nsec);
97 return r;
98 #endif
102 * Hey Emacs!
103 * Local Variables:
104 * coding: utf-8
105 * End: