timespecops.c revision 1.1.1.3 1 /* $NetBSD: timespecops.c,v 1.1.1.3 2015/10/23 17:47:45 christos Exp $ */
2
3 #include "config.h"
4
5 #include "ntp_types.h"
6 #include "ntp_fp.h"
7 #include "timespecops.h"
8
9 #include "unity.h"
10
11 #include <math.h>
12 #include <string.h>
13
14
15 #define TEST_ASSERT_EQUAL_timespec(a, b) { \
16 TEST_ASSERT_EQUAL_MESSAGE(a.tv_sec, b.tv_sec, "Field tv_sec"); \
17 TEST_ASSERT_EQUAL_MESSAGE(a.tv_nsec, b.tv_nsec, "Field tv_nsec"); \
18 }
19
20
21 #define TEST_ASSERT_EQUAL_l_fp(a, b) { \
22 TEST_ASSERT_EQUAL_MESSAGE(a.l_i, b.l_i, "Field l_i"); \
23 TEST_ASSERT_EQUAL_UINT_MESSAGE(a.l_uf, b.l_uf, "Field l_uf"); \
24 }
25
26
27 static u_int32 my_tick_to_tsf(u_int32 ticks);
28 static u_int32 my_tsf_to_tick(u_int32 tsf);
29
30
31 // that's it...
32 struct lfpfracdata {
33 long nsec;
34 u_int32 frac;
35 };
36
37
38 void test_Helpers1(void);
39 void test_Normalise(void);
40 void test_SignNoFrac(void);
41 void test_SignWithFrac(void);
42 void test_CmpFracEQ(void);
43 void test_CmpFracGT(void);
44 void test_CmpFracLT(void);
45 void test_AddFullNorm(void);
46 void test_AddFullOflow1(void);
47 void test_AddNsecNorm(void);
48 void test_AddNsecOflow1(void);
49 void test_SubFullNorm(void);
50 void test_SubFullOflow(void);
51 void test_SubNsecNorm(void);
52 void test_SubNsecOflow(void);
53 void test_Neg(void);
54 void test_AbsNoFrac(void);
55 void test_AbsWithFrac(void);
56 void test_Helpers2(void);
57 void test_ToLFPbittest(void);
58 void test_ToLFPrelPos(void);
59 void test_ToLFPrelNeg(void);
60 void test_ToLFPabs(void);
61 void test_FromLFPbittest(void);
62 void test_FromLFPrelPos(void);
63 void test_FromLFPrelNeg(void);
64 void test_LFProundtrip(void);
65 void test_ToString(void);
66
67 typedef int bool;
68
69 const bool timespec_isValid(struct timespec V);
70 struct timespec timespec_init(time_t hi, long lo);
71 l_fp l_fp_init(int32 i, u_int32 f);
72 bool AssertFpClose(const l_fp m, const l_fp n, const l_fp limit);
73 bool AssertTimespecClose(const struct timespec m, const struct timespec n, const struct timespec limit);
74
75
76 //******************************************MY CUSTOM FUNCTIONS*******************************
77
78
79
80 const bool
81 timespec_isValid(struct timespec V) {
82 return V.tv_nsec >= 0 && V.tv_nsec < 1000000000;
83 }
84
85
86 struct timespec
87 timespec_init(time_t hi, long lo) {
88 struct timespec V;
89 V.tv_sec = hi;
90 V.tv_nsec = lo;
91 return V;
92 }
93
94
95 l_fp
96 l_fp_init(int32 i, u_int32 f) {
97 l_fp temp;
98 temp.l_i = i;
99 temp.l_uf = f;
100
101 return temp;
102 }
103
104
105 bool
106 AssertFpClose(const l_fp m, const l_fp n, const l_fp limit) {
107 l_fp diff;
108
109 if (L_ISGEQ(&m, &n)) {
110 diff = m;
111 L_SUB(&diff, &n);
112 } else {
113 diff = n;
114 L_SUB(&diff, &m);
115 }
116 if (L_ISGEQ(&limit, &diff)){
117 return TRUE;
118 }
119 else {
120 printf("m_expr which is %s \nand\nn_expr which is %s\nare not close; diff=%susec\n", lfptoa(&m, 10), lfptoa(&n, 10), lfptoa(&diff, 10));
121 return FALSE;
122 }
123 }
124
125
126 bool
127 AssertTimespecClose(const struct timespec m, const struct timespec n, const struct timespec limit) {
128 struct timespec diff;
129
130 diff = abs_tspec(sub_tspec(m, n));
131 if (cmp_tspec(limit, diff) >= 0)
132 return TRUE;
133 else
134 {
135 printf("m_expr which is %ld.%lu \nand\nn_expr which is %ld.%lu\nare not close; diff=%ld.%lunsec\n", m.tv_sec, m.tv_nsec, n.tv_sec, n.tv_nsec, diff.tv_sec, diff.tv_nsec);
136 return FALSE;
137 }
138 }
139
140 //-----------------------------------------------
141
142 static const struct lfpfracdata fdata[] = {
143 { 0, 0x00000000 }, { 2218896, 0x00916ae6 },
144 { 16408100, 0x0433523d }, { 125000000, 0x20000000 },
145 { 250000000, 0x40000000 }, { 287455871, 0x4996b53d },
146 { 375000000, 0x60000000 }, { 500000000, 0x80000000 },
147 { 518978897, 0x84dbcd0e }, { 563730222, 0x90509fb3 },
148 { 563788007, 0x9054692c }, { 583289882, 0x95527c57 },
149 { 607074509, 0x9b693c2a }, { 625000000, 0xa0000000 },
150 { 645184059, 0xa52ac851 }, { 676497788, 0xad2ef583 },
151 { 678910895, 0xadcd1abb }, { 679569625, 0xadf84663 },
152 { 690926741, 0xb0e0932d }, { 705656483, 0xb4a5e73d },
153 { 723553854, 0xb93ad34c }, { 750000000, 0xc0000000 },
154 { 763550253, 0xc3780785 }, { 775284917, 0xc6791284 },
155 { 826190764, 0xd3813ce8 }, { 875000000, 0xe0000000 },
156 { 956805507, 0xf4f134a9 }, { 982570733, 0xfb89c16c }
157 };
158
159
160 u_int32
161 my_tick_to_tsf(u_int32 ticks) {
162 // convert nanoseconds to l_fp fractional units, using double
163 // precision float calculations or, if available, 64bit integer
164 // arithmetic. This should give the precise fraction, rounded to
165 // the nearest representation.
166 #ifdef HAVE_U_INT64
167 return (u_int32)((( ((u_int64)(ticks)) << 32) + 500000000) / 1000000000);
168 #else
169 return (u_int32)((double(ticks)) * 4.294967296 + 0.5);
170 #endif
171 // And before you ask: if ticks >= 1000000000, the result is
172 // truncated nonsense, so don't use it out-of-bounds.
173 }
174
175
176 u_int32
177 my_tsf_to_tick(u_int32 tsf) {
178 // Inverse operation: converts fraction to microseconds.
179 #ifdef HAVE_U_INT64
180 return (u_int32)(( ((u_int64)(tsf)) * 1000000000 + 0x80000000) >> 32);
181 #else
182 return (u_int32)(double(tsf) / 4.294967296 + 0.5);
183 #endif
184 // Beware: The result might be 10^9 due to rounding!
185 }
186
187
188
189 // ---------------------------------------------------------------------
190 // test support stuff -- part 1
191 // ---------------------------------------------------------------------
192
193 void
194 test_Helpers1(void) {
195 struct timespec x;
196
197 for (x.tv_sec = -2; x.tv_sec < 3; x.tv_sec++) {
198 x.tv_nsec = -1;
199 TEST_ASSERT_FALSE(timespec_isValid(x));
200 x.tv_nsec = 0;
201 TEST_ASSERT_TRUE(timespec_isValid(x));
202 x.tv_nsec = 999999999;
203 TEST_ASSERT_TRUE(timespec_isValid(x));
204 x.tv_nsec = 1000000000;
205 TEST_ASSERT_FALSE(timespec_isValid(x));
206 }
207 }
208
209
210 //----------------------------------------------------------------------
211 // test normalisation
212 //----------------------------------------------------------------------
213
214 void
215 test_Normalise(void) {
216 long ns;
217 for ( ns = -2000000000; ns <= 2000000000; ns += 10000000) {
218 struct timespec x = timespec_init(0, ns);
219
220 x = normalize_tspec(x);
221 TEST_ASSERT_TRUE(timespec_isValid(x));
222 }
223 }
224
225 //----------------------------------------------------------------------
226 // test classification
227 //----------------------------------------------------------------------
228
229 void
230 test_SignNoFrac(void) {
231 // sign test, no fraction
232 int i;
233 for (i = -4; i <= 4; ++i) {
234 struct timespec a = timespec_init(i, 0);
235 int E = (i > 0) - (i < 0);
236 int r = test_tspec(a);
237
238 TEST_ASSERT_EQUAL(E, r);
239 }
240 }
241
242
243 void
244 test_SignWithFrac(void) {
245 // sign test, with fraction
246 int i;
247 for (i = -4; i <= 4; ++i) {
248 struct timespec a = timespec_init(i, 10);
249 int E = (i >= 0) - (i < 0);
250 int r = test_tspec(a);
251 TEST_ASSERT_EQUAL(E, r);
252 }
253 }
254
255 //----------------------------------------------------------------------
256 // test compare
257 //----------------------------------------------------------------------
258 void
259 test_CmpFracEQ(void) {
260 // fractions are equal
261 int i, j;
262 for (i = -4; i <= 4; ++i)
263 for (j = -4; j <= 4; ++j) {
264 struct timespec a = timespec_init( i , 200);
265 struct timespec b = timespec_init( j , 200);
266 int E = (i > j) - (i < j);
267 int r = cmp_tspec_denorm(a, b);
268 TEST_ASSERT_EQUAL(E, r);
269 }
270 }
271
272
273 void
274 test_CmpFracGT(void) {
275 // fraction a bigger fraction b
276 int i, j;
277 for (i = -4; i <= 4; ++i)
278 for (j = -4; j <= 4; ++j) {
279 struct timespec a = timespec_init(i, 999999800);
280 struct timespec b = timespec_init(j, 200);
281 int E = (i >= j) - (i < j);
282 int r = cmp_tspec_denorm(a, b);
283 TEST_ASSERT_EQUAL(E, r);
284 }
285 }
286
287
288 void
289 test_CmpFracLT(void) {
290 // fraction a less fraction b
291 int i, j;
292 for (i = -4; i <= 4; ++i)
293 for (j = -4; j <= 4; ++j) {
294 struct timespec a = timespec_init(i, 200);
295 struct timespec b = timespec_init(j, 999999800);
296 int E = (i > j) - (i <= j);
297 int r = cmp_tspec_denorm(a, b);
298 TEST_ASSERT_EQUAL(E, r);
299 }
300 }
301
302 //----------------------------------------------------------------------
303 // Test addition (sum)
304 //----------------------------------------------------------------------
305
306 void
307 test_AddFullNorm(void) {
308 int i, j;
309 for (i = -4; i <= 4; ++i)
310 for (j = -4; j <= 4; ++j) {
311 struct timespec a = timespec_init(i, 200);
312 struct timespec b = timespec_init(j, 400);
313 struct timespec E = timespec_init(i + j, 200 + 400);
314 struct timespec c;
315
316 c = add_tspec(a, b);
317 TEST_ASSERT_EQUAL_timespec(E, c);
318 }
319 }
320
321
322 void
323 test_AddFullOflow1(void) {
324 int i, j;
325 for (i = -4; i <= 4; ++i)
326 for (j = -4; j <= 4; ++j) {
327 struct timespec a = timespec_init(i, 200);
328 struct timespec b = timespec_init(j, 999999900);
329 struct timespec E = timespec_init(i + j + 1, 100);
330 struct timespec c;
331
332 c = add_tspec(a, b);
333 TEST_ASSERT_EQUAL_timespec(E, c);
334 }
335 }
336
337
338 void
339 test_AddNsecNorm(void) {
340 int i;
341 for (i = -4; i <= 4; ++i) {
342 struct timespec a = timespec_init(i, 200);
343 struct timespec E = timespec_init(i, 600);
344 struct timespec c;
345
346 c = add_tspec_ns(a, 600 - 200);
347 TEST_ASSERT_EQUAL_timespec(E, c);
348 }
349 }
350
351
352 void
353 test_AddNsecOflow1(void) {
354 int i;
355 for (i = -4; i <= 4; ++i) {
356 struct timespec a = timespec_init(i, 200);
357 struct timespec E = timespec_init(i + 1, 100);
358 struct timespec c;
359
360 c = add_tspec_ns(a, NANOSECONDS - 100);
361 TEST_ASSERT_EQUAL_timespec(E, c);
362 }
363 }
364
365 //----------------------------------------------------------------------
366 // test subtraction (difference)
367 //----------------------------------------------------------------------
368
369 void
370 test_SubFullNorm(void) {
371 int i, j;
372 for (i = -4; i <= 4; ++i)
373 for (j = -4; j <= 4; ++j) {
374 struct timespec a = timespec_init( i , 600);
375 struct timespec b = timespec_init( j , 400);
376 struct timespec E = timespec_init(i-j, 200);
377 struct timespec c;
378
379 c = sub_tspec(a, b);
380 TEST_ASSERT_EQUAL_timespec(E, c);
381 }
382 }
383
384
385 void
386 test_SubFullOflow(void) {
387 int i, j;
388 for (i = -4; i <= 4; ++i)
389 for (j = -4; j <= 4; ++j) {
390 struct timespec a = timespec_init(i, 100);
391 struct timespec b = timespec_init(j, 999999900);
392 struct timespec E = timespec_init(i - j - 1, 200);
393 struct timespec c;
394
395 c = sub_tspec(a, b);
396 TEST_ASSERT_EQUAL_timespec(E, c);
397 }
398 }
399
400
401 void
402 test_SubNsecNorm(void) {
403 int i;
404 for (i = -4; i <= 4; ++i) {
405 struct timespec a = timespec_init(i, 600);
406 struct timespec E = timespec_init(i, 200);
407 struct timespec c;
408
409 c = sub_tspec_ns(a, 600 - 200);
410 TEST_ASSERT_EQUAL_timespec(E, c);
411 }
412 }
413
414
415 void
416 test_SubNsecOflow(void) {
417 int i;
418 for (i = -4; i <= 4; ++i) {
419 struct timespec a = timespec_init( i , 100);
420 struct timespec E = timespec_init(i-1, 200);
421 struct timespec c;
422
423 c = sub_tspec_ns(a, NANOSECONDS - 100);
424 TEST_ASSERT_EQUAL_timespec(E, c);
425 }
426 }
427
428 //----------------------------------------------------------------------
429 // test negation
430 //----------------------------------------------------------------------
431
432
433 void
434 test_Neg(void) {
435 int i;
436 for (i = -4; i <= 4; ++i) {
437 struct timespec a = timespec_init(i, 100);
438 struct timespec b;
439 struct timespec c;
440
441 b = neg_tspec(a);
442 c = add_tspec(a, b);
443 TEST_ASSERT_EQUAL(0, test_tspec(c));
444 }
445 }
446
447 //----------------------------------------------------------------------
448 // test abs value
449 //----------------------------------------------------------------------
450
451 void
452 test_AbsNoFrac(void) {
453 int i;
454 for (i = -4; i <= 4; ++i) {
455 struct timespec a = timespec_init(i , 0);
456 struct timespec b;
457
458 b = abs_tspec(a);
459 TEST_ASSERT_EQUAL((i != 0), test_tspec(b));
460 }
461 }
462
463
464 void
465 test_AbsWithFrac(void) {
466 int i;
467 for (i = -4; i <= 4; ++i) {
468 struct timespec a = timespec_init(i, 100);
469 struct timespec b;
470
471 b = abs_tspec(a);
472 TEST_ASSERT_EQUAL(1, test_tspec(b));
473 }
474 }
475
476 // ---------------------------------------------------------------------
477 // test support stuff -- part 2
478 // ---------------------------------------------------------------------
479
480 void
481 test_Helpers2(void) {
482 struct timespec limit = timespec_init(0, 2);
483
484 struct timespec x, y;
485 long i;
486
487 for (x.tv_sec = -2; x.tv_sec < 3; x.tv_sec++)
488 for (x.tv_nsec = 1;
489 x.tv_nsec < 1000000000;
490 x.tv_nsec += 499999999) {
491 for (i = -4; i < 5; ++i) {
492 y = x;
493 y.tv_nsec += i;
494 if (i >= -2 && i <= 2){
495 TEST_ASSERT_TRUE(AssertTimespecClose(x, y, limit));
496 }
497 else
498 {
499 TEST_ASSERT_FALSE(AssertTimespecClose(x, y, limit));
500 }
501 }
502 }
503 }
504
505 //----------------------------------------------------------------------
506 // conversion to l_fp
507 //----------------------------------------------------------------------
508
509 void
510 test_ToLFPbittest(void) {
511 l_fp lfpClose = l_fp_init(0, 1);
512 u_int32 i;
513 for (i = 0; i < 1000000000; i+=1000) {
514 struct timespec a = timespec_init(1, i);
515 l_fp E= l_fp_init(1, my_tick_to_tsf(i));
516 l_fp r;
517
518 r = tspec_intv_to_lfp(a);
519 TEST_ASSERT_TRUE(AssertFpClose(E, r, lfpClose));
520 }
521 }
522
523
524 void
525 test_ToLFPrelPos(void) {
526 int i;
527 for (i = 0; i < COUNTOF(fdata); ++i) {
528 struct timespec a = timespec_init(1, fdata[i].nsec);
529 l_fp E = l_fp_init(1, fdata[i].frac);
530 l_fp r;
531
532 r = tspec_intv_to_lfp(a);
533 TEST_ASSERT_EQUAL_l_fp(E, r);
534 }
535 }
536
537
538 void
539 test_ToLFPrelNeg(void) {
540 int i;
541 for (i = 0; i < COUNTOF(fdata); ++i) {
542 struct timespec a = timespec_init(-1, fdata[i].nsec);
543 l_fp E = l_fp_init(~0, fdata[i].frac);
544 l_fp r;
545
546 r = tspec_intv_to_lfp(a);
547 TEST_ASSERT_EQUAL_l_fp(E, r);
548 }
549 }
550
551
552 void
553 test_ToLFPabs(void) {
554 int i;
555 for (i = 0; i < COUNTOF(fdata); ++i) {
556 struct timespec a = timespec_init(1, fdata[i].nsec);
557 l_fp E = l_fp_init(1 + JAN_1970, fdata[i].frac);
558 l_fp r;
559
560 r = tspec_stamp_to_lfp(a);
561 TEST_ASSERT_EQUAL_l_fp(E, r);
562 }
563 }
564
565 //----------------------------------------------------------------------
566 // conversion from l_fp
567 //----------------------------------------------------------------------
568
569 void
570 test_FromLFPbittest(void) {
571 struct timespec limit = timespec_init(0, 2);
572
573 // Not *exactly* a bittest, because 2**32 tests would take a
574 // really long time even on very fast machines! So we do test
575 // every 1000 fractional units.
576 u_int32 tsf;
577 for (tsf = 0; tsf < ~((u_int32)(1000)); tsf += 1000) {
578 struct timespec E = timespec_init(1, my_tsf_to_tick(tsf));
579 l_fp a = l_fp_init(1, tsf);
580 struct timespec r;
581
582 r = lfp_intv_to_tspec(a);
583 // The conversion might be off by one nanosecond when
584 // comparing to calculated value.
585 TEST_ASSERT_TRUE(AssertTimespecClose(E, r, limit));
586 }
587 }
588
589
590 void
591 test_FromLFPrelPos(void) {
592 struct timespec limit = timespec_init(0, 2);
593 int i;
594 for (i = 0; i < COUNTOF(fdata); ++i) {
595 l_fp a = l_fp_init(1, fdata[i].frac);
596 struct timespec E = timespec_init(1, fdata[i].nsec);
597 struct timespec r;
598
599 r = lfp_intv_to_tspec(a);
600 TEST_ASSERT_TRUE(AssertTimespecClose(E, r, limit));
601 }
602 }
603
604
605 void
606 test_FromLFPrelNeg(void) {
607 struct timespec limit = timespec_init(0, 2);
608 int i;
609 for (i = 0; i < COUNTOF(fdata); ++i) {
610 l_fp a = l_fp_init(~0, fdata[i].frac);
611 struct timespec E = timespec_init(-1, fdata[i].nsec);
612 struct timespec r;
613
614 r = lfp_intv_to_tspec(a);
615 TEST_ASSERT_TRUE(AssertTimespecClose(E, r, limit));
616 }
617 }
618
619
620 // nsec -> frac -> nsec roundtrip, using a prime start and increment
621 void
622 test_LFProundtrip(void) {
623 int32_t t;
624 u_int32 i;
625 for (t = -1; t < 2; ++t)
626 for (i = 4999; i < 1000000000; i += 10007) {
627 struct timespec E = timespec_init(t, i);
628 l_fp a;
629 struct timespec r;
630
631 a = tspec_intv_to_lfp(E);
632 r = lfp_intv_to_tspec(a);
633 TEST_ASSERT_EQUAL_timespec(E, r);
634 }
635 }
636
637 //----------------------------------------------------------------------
638 // string formatting
639 //----------------------------------------------------------------------
640
641 void
642 test_ToString(void) {
643 static const struct {
644 time_t sec;
645 long nsec;
646 const char * repr;
647 } data [] = {
648 { 0, 0, "0.000000000" },
649 { 2, 0, "2.000000000" },
650 {-2, 0, "-2.000000000" },
651 { 0, 1, "0.000000001" },
652 { 0,-1, "-0.000000001" },
653 { 1,-1, "0.999999999" },
654 {-1, 1, "-0.999999999" },
655 {-1,-1, "-1.000000001" },
656 };
657 int i;
658 for (i = 0; i < COUNTOF(data); ++i) {
659 struct timespec a = timespec_init(data[i].sec, data[i].nsec);
660 const char * E = data[i].repr;
661 const char * r = tspectoa(a);
662 TEST_ASSERT_EQUAL_STRING(E, r);
663 }
664 }
665
666 // -*- EOF -*-
667