1 /* Get the system clock resolution.
2
3 Copyright 2021-2023 Free Software Foundation, Inc.
4
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.
9
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.
14
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/>. */
17
18 /* Written by Paul Eggert. */
19
20 #include <config.h>
21
22 #include "timespec.h"
23
24 static long int _GL_ATTRIBUTE_CONST
25 gcd (long int a, long int b)
26 {
27 while (b != 0)
28 {
29 long int r = a % b;
30 a = b;
31 b = r;
32 }
33 return a;
34 }
35
36 /* Return the system time resolution in nanoseconds. */
37
38 long int
39 gettime_res (void)
40 {
41 struct timespec res;
42 #if defined CLOCK_REALTIME && HAVE_CLOCK_GETRES
43 clock_getres (CLOCK_REALTIME, &res);
44 #elif defined HAVE_TIMESPEC_GETRES
45 timespec_getres (&res, TIME_UTC);
46 #else
47 /* Guess high and let the later code deduce better. */
48 res.tv_sec = 1;
49 res.tv_nsec = 0;
50 #endif
51
52 /* On all Gnulib platforms the following calculations do not overflow. */
53
54 long int hz = TIMESPEC_HZ;
55 long int r = res.tv_nsec <= 0 ? hz : res.tv_nsec;
56 struct timespec earlier = { .tv_nsec = -1 };
57
58 /* On some platforms, clock_getres (CLOCK_REALTIME, ...) yields a
59 too-large resolution, under the mistaken theory that it should
60 return the timer interval. For example, on AIX 7.2 POWER8
61 clock_getres yields 10 ms even though clock_gettime yields 1 μs
62 resolution. Work around the problem with high probability by
63 trying clock_gettime several times and observing the resulting
64 bounds on resolution. */
65 int nsamples = 32;
66 for (int i = 0; 1 < r && i < nsamples; i++)
67 {
68 /* If successive timestamps disagree the clock resolution must
69 be small, so exit the inner loop to check this sample.
70 Otherwise, arrange for the outer loop to exit but continue
71 the inner-loop search for a differing timestamp sample. */
72 struct timespec now;
73 for (;; i = nsamples)
74 {
75 now = current_timespec ();
76 if (earlier.tv_nsec != now.tv_nsec || earlier.tv_sec != now.tv_sec)
77 break;
78 }
79 earlier = now;
80
81 if (0 < now.tv_nsec)
82 r = gcd (r, now.tv_nsec);
83 }
84
85 return r;
86 }
87
88 /*
89 * Hey Emacs!
90 * Local Variables:
91 * coding: utf-8
92 * End:
93 */