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