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 milliseconds.
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 milliseconds.
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  * Adds two timespec structures.
156  */
tst_timespec_add(struct timespec t1,struct timespec t2)157 static inline struct timespec tst_timespec_add(struct timespec t1,
158                                                struct timespec t2)
159 {
160 	struct timespec res;
161 
162 	res.tv_sec = t1.tv_sec + t2.tv_sec;
163 	res.tv_nsec = t1.tv_nsec + t2.tv_nsec;
164 
165 	if (res.tv_nsec >= 1000000000) {
166 		res.tv_sec++;
167 		res.tv_nsec -= 1000000000;
168 	}
169 
170 	return res;
171 }
172 
173 /*
174  * Subtracts us microseconds from t.
175  */
tst_timespec_sub_us(struct timespec t,long long us)176 static inline struct timespec tst_timespec_sub_us(struct timespec t,
177                                                   long long us)
178 {
179 	t.tv_sec -= us / 1000000;
180 	t.tv_nsec -= (us % 1000000) * 1000;
181 
182 	if (t.tv_nsec < 0) {
183 		t.tv_sec--;
184 		t.tv_nsec += 1000000000;
185 	}
186 
187 	return t;
188 }
189 
190 /*
191  * Returns difference between two timespec structures.
192  */
tst_timespec_diff(struct timespec t1,struct timespec t2)193 static inline struct timespec tst_timespec_diff(struct timespec t1,
194                                                 struct timespec t2)
195 {
196 	struct timespec res;
197 
198 	res.tv_sec = t1.tv_sec - t2.tv_sec;
199 
200 	if (t1.tv_nsec < t2.tv_nsec) {
201 		res.tv_sec--;
202 		res.tv_nsec = 1000000000 - (t2.tv_nsec - t1.tv_nsec);
203 	} else {
204 		res.tv_nsec = t1.tv_nsec - t2.tv_nsec;
205 	}
206 
207 	return res;
208 }
209 
tst_timespec_diff_ns(struct timespec t1,struct timespec t2)210 static inline long long tst_timespec_diff_ns(struct timespec t1,
211 					     struct timespec t2)
212 {
213 	return t1.tv_nsec - t2.tv_nsec + 1000000000LL * (t1.tv_sec - t2.tv_sec);
214 }
215 
tst_timespec_diff_us(struct timespec t1,struct timespec t2)216 static inline long long tst_timespec_diff_us(struct timespec t1,
217                                              struct timespec t2)
218 {
219 	return tst_timespec_to_us(tst_timespec_diff(t1, t2));
220 }
221 
tst_timespec_diff_ms(struct timespec t1,struct timespec t2)222 static inline long long tst_timespec_diff_ms(struct timespec t1,
223                                              struct timespec t2)
224 {
225 	return tst_timespec_to_ms(tst_timespec_diff(t1, t2));
226 }
227 
228 /*
229  * Returns difference between two timeval structures.
230  */
tst_timeval_diff(struct timeval t1,struct timeval t2)231 static inline struct timeval tst_timeval_diff(struct timeval t1,
232                                               struct timeval t2)
233 {
234 	struct timeval res;
235 
236 	res.tv_sec = t1.tv_sec - t2.tv_sec;
237 
238 	if (t1.tv_usec < t2.tv_usec) {
239 		res.tv_sec--;
240 		res.tv_usec = 1000000 - (t2.tv_usec - t1.tv_usec);
241 	} else {
242 		res.tv_usec = t1.tv_usec - t2.tv_usec;
243 	}
244 
245 	return res;
246 }
247 
tst_timeval_diff_us(struct timeval t1,struct timeval t2)248 static inline long long tst_timeval_diff_us(struct timeval t1,
249                                             struct timeval t2)
250 {
251 	return tst_timeval_to_us(tst_timeval_diff(t1, t2));
252 }
253 
tst_timeval_diff_ms(struct timeval t1,struct timeval t2)254 static inline long long tst_timeval_diff_ms(struct timeval t1,
255                                             struct timeval t2)
256 {
257 	return tst_timeval_to_ms(tst_timeval_diff(t1, t2));
258 }
259 
260 /*
261  * Returns absolute value of difference between two timespec structures.
262  */
tst_timespec_abs_diff(struct timespec t1,struct timespec t2)263 static inline struct timespec tst_timespec_abs_diff(struct timespec t1,
264                                                     struct timespec t2)
265 {
266 	if (tst_timespec_lt(t1, t2))
267 		return tst_timespec_diff(t2, t1);
268 	else
269 		return tst_timespec_diff(t1, t2);
270 }
271 
tst_timespec_abs_diff_us(struct timespec t1,struct timespec t2)272 static inline long long tst_timespec_abs_diff_us(struct timespec t1,
273                                                  struct timespec t2)
274 {
275        return tst_timespec_to_us(tst_timespec_abs_diff(t1, t2));
276 }
277 
tst_timespec_abs_diff_ms(struct timespec t1,struct timespec t2)278 static inline long long tst_timespec_abs_diff_ms(struct timespec t1,
279                                                  struct timespec t2)
280 {
281        return tst_timespec_to_ms(tst_timespec_abs_diff(t1, t2));
282 }
283 
284 /*
285  * Exits the test with TCONF if particular timer is not supported. This is
286  * intended to be used in test setup. There is no cleanup callback parameter as
287  * you are expected to call it before initializing any resources that has to be
288  * cleaned up later.
289  *
290  * @clk_id: Posix clock to use.
291  */
292 void tst_timer_check(clockid_t clk_id);
293 
294 /*
295  * Marks a start time for given clock type.
296  *
297  * @clk_id: Posix clock to use.
298  */
299 void tst_timer_start(clockid_t clk_id);
300 
301 /*
302  * Returns true if timer started by tst_timer_start() has been running for
303  * longer than ms seconds.
304  *
305  * @ms: Time interval in milliseconds.
306  */
307 int tst_timer_expired_ms(long long ms);
308 
309 /*
310  * Marks timer end time.
311  */
312 void tst_timer_stop(void);
313 
314 /*
315  * Retuns elapsed time in struct timespec.
316  */
317 struct timespec tst_timer_elapsed(void);
318 
319 /*
320  * Returns elapsed time in milliseconds.
321  */
tst_timer_elapsed_ms(void)322 static inline long long tst_timer_elapsed_ms(void)
323 {
324 	return tst_timespec_to_ms(tst_timer_elapsed());
325 }
326 
327 /*
328  * Returns elapsed time in microseconds.
329  */
tst_timer_elapsed_us(void)330 static inline long long tst_timer_elapsed_us(void)
331 {
332 	return tst_timespec_to_us(tst_timer_elapsed());
333 }
334 
335 /*
336  * Returns a string containing given clock type name
337  */
338 const char *tst_clock_name(clockid_t);
339 
340 #endif /* TST_TIMER */
341