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