1 /* Jitter utility: timing functions.
2
3 Copyright (C) 2020 Luca Saiu
4 Written by Luca Saiu
5
6 This file is part of Jitter.
7
8 Jitter is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Jitter is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */
20
21
22 #include <jitter/jitter-time.h>
23
24 #include <time.h>
25 #include <sys/time.h>
26
27 #include <jitter/jitter.h>
28 #include <jitter/jitter-malloc.h>
29 #include <jitter/jitter-config.h>
30
31
32
33
34 /* Portability layer.
35 * ************************************************************************** */
36
37 /* Any reasonable C library should implement struct timeval and the related C
38 API. However some sysems will implement some more precise alternative as
39 well. This funcionality is a thin layer intended to abstract over system
40 differences, and use the more precise facility where available. */
41
42 /* Define a few simple macros allowing to abstract over the different APIs,
43 which luckily are very similar. */
44 #if defined (JITTER_HAVE_CLOCK_GETTIME)
45 /* This configuration has struct timespec , which allows, at least as far as
46 the API goes, nanosecond resolution. GNU/Linux appears to actually
47 implement nanosecond resolution, if clock_getres is to be trusted:
48 struct timespec foo;
49 int q = clock_getres (CLOCK_REALTIME, & foo);
50 printf (">>> %i: %20.10f\n", q, JITTER_TIME_TO_DOUBLE (& foo));
51 This prints
52 >>> 0: 0.0000000010
53 on my system. */
54 # define JITTER_TIME_STRUCT \
55 struct timespec
56 # define JITTER_TIME_FUNCTION(_jitter_pointer_arg) \
57 (clock_gettime (CLOCK_REALTIME, \
58 (JITTER_TIME_STRUCT *) (_jitter_pointer_arg)))
59 # define JITTER_TIME_TO_DOUBLE(_jitter_pointer_arg) \
60 ((_jitter_pointer_arg)->tv_nsec * 1e-9 \
61 + (_jitter_pointer_arg)->tv_sec)
62 #else
63 /* Fall back on struct timeval , which is only precise to the millisecond. */
64 # define JITTER_TIME_STRUCT \
65 struct timeval
66 # define JITTER_TIME_FUNCTION(_jitter_pointer_arg) \
67 (gettimeofday ((JITTER_TIME_STRUCT *) (_jitter_pointer_arg), \
68 NULL))
69 # define JITTER_TIME_TO_DOUBLE(_jitter_pointer_arg) \
70 ((_jitter_pointer_arg)->tv_usec * 1e-6 \
71 + (_jitter_pointer_arg)->tv_sec)
72 #endif
73
74
75
76
77 /* Implementation.
78 * ************************************************************************** */
79
80 jitter_point_in_time
jitter_point_in_time_make(void)81 jitter_point_in_time_make (void)
82 {
83 /* No initialisation is needed or performed. */
84 return jitter_xmalloc (sizeof (JITTER_TIME_STRUCT));
85 }
86
87 void
jitter_point_in_time_destroy(jitter_point_in_time p)88 jitter_point_in_time_destroy (jitter_point_in_time p)
89 {
90 free (p);
91 }
92
93 void
jitter_time_set_now(jitter_point_in_time now)94 jitter_time_set_now (jitter_point_in_time now)
95 {
96 JITTER_TIME_FUNCTION (now);
97 }
98
99 double
jitter_time_subtract(jitter_point_in_time later_abstract,jitter_point_in_time earlier_abstract)100 jitter_time_subtract (jitter_point_in_time later_abstract,
101 jitter_point_in_time earlier_abstract)
102 {
103 JITTER_TIME_STRUCT *later = later_abstract;
104 JITTER_TIME_STRUCT *earlier = earlier_abstract;
105 return JITTER_TIME_TO_DOUBLE (later) - JITTER_TIME_TO_DOUBLE (earlier);
106 }
107
108 double
jitter_time_subtract_from_now(jitter_point_in_time earlier)109 jitter_time_subtract_from_now (jitter_point_in_time earlier)
110 {
111 /* Measure the time now, writing into an automatic variable. */
112 JITTER_TIME_STRUCT now;
113 jitter_time_set_now (& now);
114
115 /* I am keeping the result in a variable in the hope of preventing sibling
116 call optimization from rewriting the code in a way that passes a pointer to
117 an automatic variable in a dead frame. */
118 double result = jitter_time_subtract (& now, earlier);
119 return result;
120 }
121