1 /*
2  * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24  /*
25 
26    Timer - struct timespec conversion runtimes and easy to use functions to
27            measure elapsed time.
28 
29   */
30 
31 #ifndef TST_TIMER
32 #define TST_TIMER
33 
34 #include <sys/time.h>
35 #include <time.h>
36 
tst_timespec_to_ns(struct timespec t)37 static inline long long tst_timespec_to_ns(struct timespec t)
38 {
39 	return t.tv_sec * 1000000000 + t.tv_nsec;
40 }
41 
42 /*
43  * Converts timespec to microseconds.
44  */
tst_timespec_to_us(struct timespec t)45 static inline long long tst_timespec_to_us(struct timespec t)
46 {
47 	return t.tv_sec * 1000000 + (t.tv_nsec + 500) / 1000;
48 }
49 
50 /*
51  * Converts timespec to miliseconds.
52  */
tst_timespec_to_ms(struct timespec t)53 static inline long long tst_timespec_to_ms(struct timespec t)
54 {
55 	return t.tv_sec * 1000 + (t.tv_nsec + 500000) / 1000000;
56 }
57 
58 /*
59  * Converts timeval to microseconds.
60  */
tst_timeval_to_us(struct timeval t)61 static inline long long tst_timeval_to_us(struct timeval t)
62 {
63 	return t.tv_sec * 1000000 + t.tv_usec;
64 }
65 
66 /*
67  * Converts timeval to miliseconds.
68  */
tst_timeval_to_ms(struct timeval t)69 static inline long long tst_timeval_to_ms(struct timeval t)
70 {
71 	return t.tv_sec * 1000 + (t.tv_usec + 500) / 1000;
72 }
73 
74 /*
75  * Converts ms to struct timeval
76  */
tst_ms_to_timeval(long long ms)77 static inline struct timeval tst_ms_to_timeval(long long ms)
78 {
79 	struct timeval ret;
80 
81 	ret.tv_sec = ms / 1000;
82 	ret.tv_usec = (ms % 1000) * 1000;
83 
84 	return ret;
85 }
86 
87 /*
88  * Converts us to struct timeval
89  */
tst_us_to_timeval(long long us)90 static inline struct timeval tst_us_to_timeval(long long us)
91 {
92 	struct timeval ret;
93 
94 	ret.tv_sec = us / 1000000;
95 	ret.tv_usec = us % 1000000;
96 
97 	return ret;
98 }
99 
100 /*
101  * Converts ms to struct timespec
102  */
tst_ms_to_timespec(long long ms)103 static inline struct timespec tst_ms_to_timespec(long long ms)
104 {
105 	struct timespec ret;
106 
107 	ret.tv_sec = ms / 1000;
108 	ret.tv_nsec = (ms % 1000) * 1000000;
109 
110 	return ret;
111 }
112 
113 /*
114  * Converts us to struct timespec
115  */
tst_us_to_timespec(long long us)116 static inline struct timespec tst_us_to_timespec(long long us)
117 {
118 	struct timespec ret;
119 
120 	ret.tv_sec = us / 1000000;
121 	ret.tv_nsec = (us % 1000000) * 1000;
122 
123 	return ret;
124 }
125 
126 /*
127  * Comparsions
128  */
tst_timespec_lt(struct timespec t1,struct timespec t2)129 static inline int tst_timespec_lt(struct timespec t1, struct timespec t2)
130 {
131 	if (t1.tv_sec == t2.tv_sec)
132 		return t1.tv_nsec < t2.tv_nsec;
133 
134 	return t1.tv_sec < t2.tv_sec;
135 }
136 
137 /*
138  * Adds us microseconds to t.
139  */
tst_timespec_add_us(struct timespec t,long long us)140 static inline struct timespec tst_timespec_add_us(struct timespec t,
141                                                   long long us)
142 {
143 	t.tv_sec += us / 1000000;
144 	t.tv_nsec += (us % 1000000) * 1000;
145 
146 	if (t.tv_nsec >= 1000000000) {
147 		t.tv_sec++;
148 		t.tv_nsec -= 1000000000;
149 	}
150 
151 	return t;
152 }
153 
154 /*
155  * Returns difference between two timespec structures.
156  */
tst_timespec_diff(struct timespec t1,struct timespec t2)157 static inline struct timespec tst_timespec_diff(struct timespec t1,
158                                                 struct timespec t2)
159 {
160 	struct timespec res;
161 
162 	res.tv_sec = t1.tv_sec - t2.tv_sec;
163 
164 	if (t1.tv_nsec < t2.tv_nsec) {
165 		res.tv_sec--;
166 		res.tv_nsec = 1000000000 - (t2.tv_nsec - t1.tv_nsec);
167 	} else {
168 		res.tv_nsec = t1.tv_nsec - t2.tv_nsec;
169 	}
170 
171 	return res;
172 }
173 
tst_timespec_diff_ns(struct timespec t1,struct timespec t2)174 static inline long long tst_timespec_diff_ns(struct timespec t1,
175 					     struct timespec t2)
176 {
177 	return t1.tv_nsec - t2.tv_nsec + 1000000000LL * (t1.tv_sec - t2.tv_sec);
178 }
179 
tst_timespec_diff_us(struct timespec t1,struct timespec t2)180 static inline long long tst_timespec_diff_us(struct timespec t1,
181                                              struct timespec t2)
182 {
183 	return tst_timespec_to_us(tst_timespec_diff(t1, t2));
184 }
185 
tst_timespec_diff_ms(struct timespec t1,struct timespec t2)186 static inline long long tst_timespec_diff_ms(struct timespec t1,
187                                              struct timespec t2)
188 {
189 	return tst_timespec_to_ms(tst_timespec_diff(t1, t2));
190 }
191 
192 /*
193  * Returns difference between two timeval structures.
194  */
tst_timeval_diff(struct timeval t1,struct timeval t2)195 static inline struct timeval tst_timeval_diff(struct timeval t1,
196                                               struct timeval t2)
197 {
198 	struct timeval res;
199 
200 	res.tv_sec = t1.tv_sec - t2.tv_sec;
201 
202 	if (t1.tv_usec < t2.tv_usec) {
203 		res.tv_sec--;
204 		res.tv_usec = 1000000 - (t2.tv_usec - t1.tv_usec);
205 	} else {
206 		res.tv_usec = t1.tv_usec - t2.tv_usec;
207 	}
208 
209 	return res;
210 }
211 
tst_timeval_diff_us(struct timeval t1,struct timeval t2)212 static inline long long tst_timeval_diff_us(struct timeval t1,
213                                             struct timeval t2)
214 {
215 	return tst_timeval_to_us(tst_timeval_diff(t1, t2));
216 }
217 
tst_timeval_diff_ms(struct timeval t1,struct timeval t2)218 static inline long long tst_timeval_diff_ms(struct timeval t1,
219                                             struct timeval t2)
220 {
221 	return tst_timeval_to_ms(tst_timeval_diff(t1, t2));
222 }
223 
224 /*
225  * Returns absolute value of difference between two timespec structures.
226  */
tst_timespec_abs_diff(struct timespec t1,struct timespec t2)227 static inline struct timespec tst_timespec_abs_diff(struct timespec t1,
228                                                     struct timespec t2)
229 {
230 	if (tst_timespec_lt(t1, t2))
231 		return tst_timespec_diff(t2, t1);
232 	else
233 		return tst_timespec_diff(t1, t2);
234 }
235 
tst_timespec_abs_diff_us(struct timespec t1,struct timespec t2)236 static inline long long tst_timespec_abs_diff_us(struct timespec t1,
237                                                  struct timespec t2)
238 {
239        return tst_timespec_to_us(tst_timespec_abs_diff(t1, t2));
240 }
241 
tst_timespec_abs_diff_ms(struct timespec t1,struct timespec t2)242 static inline long long tst_timespec_abs_diff_ms(struct timespec t1,
243                                                  struct timespec t2)
244 {
245        return tst_timespec_to_ms(tst_timespec_abs_diff(t1, t2));
246 }
247 
248 /*
249  * Exits the test with TCONF if particular timer is not supported. This is
250  * intended to be used in test setup. There is no cleanup callback parameter as
251  * you are expected to call it before initializing any resources that has to be
252  * cleaned up later.
253  *
254  * @clk_id: Posix clock to use.
255  */
256 void tst_timer_check(clockid_t clk_id);
257 
258 /*
259  * Marks a start time for given clock type.
260  *
261  * @clk_id: Posix clock to use.
262  */
263 void tst_timer_start(clockid_t clk_id);
264 
265 /*
266  * Returns true if timer started by tst_timer_start() has been running for
267  * longer than ms seconds.
268  *
269  * @ms: Time interval in miliseconds.
270  */
271 int tst_timer_expired_ms(long long ms);
272 
273 /*
274  * Marks timer end time.
275  */
276 void tst_timer_stop(void);
277 
278 /*
279  * Retuns elapsed time in struct timespec.
280  */
281 struct timespec tst_timer_elapsed(void);
282 
283 /*
284  * Returns elapsed time in miliseconds.
285  */
tst_timer_elapsed_ms(void)286 static inline long long tst_timer_elapsed_ms(void)
287 {
288 	return tst_timespec_to_ms(tst_timer_elapsed());
289 }
290 
291 /*
292  * Returns elapsed time in microseconds.
293  */
tst_timer_elapsed_us(void)294 static inline long long tst_timer_elapsed_us(void)
295 {
296 	return tst_timespec_to_us(tst_timer_elapsed());
297 }
298 
299 #endif /* TST_TIMER */
300