1 /* 2 * Copyright (c) 2005 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "defs.h" 36 37 static int client_insane(struct server_info **, int, server_info_t); 38 39 void 40 client_init(void) 41 { 42 } 43 44 int 45 client_main(struct server_info **info_ary, int count) 46 { 47 struct server_info *best_off; 48 struct server_info *best_freq; 49 double last_freq; 50 double freq; 51 double offset; 52 int calc_offset_correction; 53 int didreconnect; 54 int i; 55 int insane; 56 57 last_freq = 0.0; 58 59 for (;;) { 60 /* 61 * Subtract the interval from poll_sleep and poll the client 62 * if it reaches 0. 63 * 64 * Because we do not compensate for offset corrections which are 65 * in progress, we cannot accumulate data for an offset correction 66 * while a prior correction is still being worked through by the 67 * system. 68 */ 69 calc_offset_correction = !sysntp_offset_correction_is_running(); 70 for (i = 0; i < count; ++i) 71 client_poll(info_ary[i], min_sleep_opt, calc_offset_correction); 72 73 /* 74 * Find the best client (or synthesize one). A different client 75 * can be chosen for frequency and offset. Note in particular 76 * that offset counters and averaging code gets reset when an 77 * offset correction is made (otherwise the averaging history will 78 * cause later corrections to overshoot). 79 * 80 * The regression used to calculate the frequency is a much 81 * longer-term entity and is NOT reset, so it is still possible 82 * for the offset correction code to make minor adjustments to 83 * the frequency if it so desires. 84 * 85 * client_check may replace the server_info pointer with a new 86 * one. 87 */ 88 best_off = NULL; 89 best_freq = NULL; 90 for (i = 0; i < count; ++i) 91 client_check(&info_ary[i], &best_off, &best_freq); 92 93 /* 94 * Check for server insanity. In large NNTP pools some servers 95 * may just be dead wrong, but report that they are right. 96 */ 97 if (best_off) { 98 insane = client_insane(info_ary, count, best_off); 99 if (insane > 0) { 100 /* 101 * best_off meets the quorum requirements and is good 102 * (keep best_off) 103 */ 104 best_off->server_insane = 0; 105 } else if (insane == 0) { 106 /* 107 * best_off is probably good, but we do not have enough 108 * servers reporting yet to meet the quorum requirements. 109 */ 110 best_off = NULL; 111 } else { 112 /* 113 * best_off is ugly, mark the server as being insane for 114 * 60 minutes. 115 */ 116 best_off->server_insane = 60 * 60; 117 logdebuginfo(best_off, 1, 118 "excessive offset deviation, mapping out\n"); 119 best_off = NULL; 120 } 121 } 122 123 /* 124 * Offset correction. 125 */ 126 if (best_off) { 127 offset = best_off->lin_sumoffset / best_off->lin_countoffset; 128 lin_resetalloffsets(info_ary, count); 129 if (offset < -COURSE_OFFSET_CORRECTION_LIMIT || 130 offset > COURSE_OFFSET_CORRECTION_LIMIT || 131 quickset_opt 132 ) { 133 freq = sysntp_correct_course_offset(offset); 134 quickset_opt = 0; 135 } else { 136 freq = sysntp_correct_offset(offset); 137 } 138 } else { 139 freq = 0.0; 140 } 141 142 /* 143 * Frequency correction (throw away minor freq adjusts from the 144 * offset code if we can't do a frequency correction here). Do 145 * not reissue if it hasn't changed from the last issued correction. 146 */ 147 if (best_freq) { 148 freq += best_freq->lin_cache_freq; 149 if (last_freq != freq) { 150 sysntp_correct_freq(freq); 151 last_freq = freq; 152 } 153 } 154 155 /* 156 * This function is responsible for managing the polling mode and 157 * figures out how long we should sleep. 158 */ 159 didreconnect = 0; 160 for (i = 0; i < count; ++i) 161 client_manage_polling_mode(info_ary[i], &didreconnect); 162 if (didreconnect) 163 client_check_duplicate_ips(info_ary, count); 164 165 /* 166 * Polling loop sleep. 167 */ 168 usleep(min_sleep_opt * 1000000 + random() % 500000); 169 } 170 } 171 172 void 173 client_poll(server_info_t info, int poll_interval, int calc_offset_correction) 174 { 175 struct timeval rtv; 176 struct timeval ltv; 177 struct timeval lbtv; 178 double offset; 179 180 /* 181 * Adjust the insane-server countdown 182 */ 183 if (info->server_insane > poll_interval) 184 info->server_insane -= poll_interval; 185 else 186 info->server_insane = 0; 187 188 /* 189 * By default we always poll. If the polling interval comes under 190 * active management the poll_sleep will be non-zero. 191 */ 192 if (info->poll_sleep > poll_interval) { 193 info->poll_sleep -= poll_interval; 194 return; 195 } 196 info->poll_sleep = 0; 197 198 /* 199 * If the client isn't open don't mess with the poll_failed count 200 * or anything else. We are left in the init or startup phase. 201 */ 202 if (info->fd < 0) { 203 if (info->poll_failed < 0x7FFFFFFF) 204 ++info->poll_failed; 205 return; 206 } 207 208 logdebuginfo(info, 4, "poll, "); 209 if (udp_ntptimereq(info->fd, &rtv, <v, &lbtv) < 0) { 210 ++info->poll_failed; 211 logdebug(4, "no response (%d failures in a row)\n", info->poll_failed); 212 if (info->poll_failed == POLL_FAIL_RESET) { 213 if (info->lin_count != 0) { 214 logdebuginfo(info, 4, "resetting regression due to failures\n"); 215 } 216 lin_reset(info); 217 } 218 return; 219 } 220 221 /* 222 * Successful query. Update polling info for the polling mode manager. 223 */ 224 ++info->poll_count; 225 info->poll_failed = 0; 226 227 /* 228 * Figure out the offset (the difference between the reported 229 * time and our current time) for linear regression purposes. 230 */ 231 offset = tv_delta_double(&rtv, <v); 232 233 while (info) { 234 /* 235 * Linear regression 236 */ 237 if (debug_level >= 4) { 238 struct tm *tp; 239 char buf[64]; 240 time_t t; 241 242 t = rtv.tv_sec; 243 tp = localtime(&t); 244 strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", tp); 245 logdebug(4, "%s.%03ld ", buf, rtv.tv_usec / 1000); 246 } 247 lin_regress(info, <v, &lbtv, offset, calc_offset_correction); 248 info = info->altinfo; 249 if (info && debug_level >= 4) { 250 logdebug(4, "%*.*s: poll, ", 251 (int)strlen(info->target), 252 (int)strlen(info->target), "(alt)"); 253 } 254 } 255 } 256 257 /* 258 * Find the best client (or synthesize a fake info structure to return). 259 * We can find separate best clients for offset and frequency. 260 */ 261 void 262 client_check(struct server_info **checkp, 263 struct server_info **best_off, 264 struct server_info **best_freq) 265 { 266 struct server_info *check = *checkp; 267 struct server_info *info; 268 int min_samples; 269 270 /* 271 * Start an alternate linear regression once our current one 272 * has passed a certain point. 273 */ 274 if (check->lin_count >= LIN_RESTART / 2 && check->altinfo == NULL) { 275 info = malloc(sizeof(*info)); 276 assert(info != NULL); 277 /* note: check->altinfo is NULL as of the bcopy */ 278 bcopy(check, info, sizeof(*info)); 279 check->altinfo = info; 280 lin_reset(info); 281 } 282 283 /* 284 * Replace our current linear regression with the alternate once 285 * the current one has hit its limit (beyond a certain point the 286 * linear regression starts to work against us, preventing us from 287 * reacting to changing conditions). 288 * 289 * Report any significant change in the offset or ppm. 290 */ 291 if (check->lin_count >= LIN_RESTART) { 292 if ((info = check->altinfo) && info->lin_count >= LIN_RESTART / 2) { 293 double freq_diff; 294 295 freq_diff = info->lin_cache_freq - check->lin_cache_freq; 296 logdebuginfo(info, 4, "Switching to alternate, Frequency " 297 "difference is %6.3f ppm\n", 298 freq_diff * 1.0E+6); 299 *checkp = info; 300 free(check); 301 check = info; 302 } 303 } 304 305 /* 306 * BEST CLIENT FOR FREQUENCY CORRECTION: 307 * 308 * Frequency corrections get better the longer the time separation 309 * between samples. 310 * 311 * 8 samples and a correlation > 0.99, or 312 * 16 samples and a correlation > 0.96 313 */ 314 info = *best_freq; 315 if ((check->lin_count >= 8 && fabs(check->lin_cache_corr) >= 0.99) || 316 (check->lin_count >= 16 && fabs(check->lin_cache_corr) >= 0.96) 317 ) { 318 if (info == NULL || 319 fabs(check->lin_cache_corr) > fabs(info->lin_cache_corr) 320 ) { 321 info = check; 322 *best_freq = info; 323 } 324 325 } 326 327 /* 328 * BEST CLIENT FOR OFFSET CORRECTION: 329 * 330 * Use the standard-deviation and require at least 4 samples. An 331 * offset correction is valid if the standard deviation is less then 332 * the average offset divided by 4. 333 * 334 * If we are in maintainance mode, require 8 samples instead of 4. 335 * Offset corrections get better with more samples. This reduces 336 * ping-pong effects that can occur with a small number of samples. 337 * 338 * Servers marked as being insane are not allowed 339 */ 340 info = *best_off; 341 if (info && info->poll_mode == POLL_MAINTAIN) 342 min_samples = 8; 343 else 344 min_samples = 4; 345 if (check->lin_countoffset >= min_samples && 346 (check->lin_cache_stddev < 347 fabs(check->lin_sumoffset / check->lin_countoffset / 4)) && 348 check->server_insane == 0 349 ) { 350 if (info == NULL || 351 fabs(check->lin_cache_stddev) < fabs(info->lin_cache_stddev) 352 ) { 353 info = check; 354 *best_off = info; 355 } 356 } 357 } 358 359 /* 360 * Actively manage the polling interval. Note that the poll_* fields are 361 * always transfered to the alternate regression when the check code replaces 362 * the current regression with a new one. 363 * 364 * This routine is called from the main loop for each base info structure. 365 * The polling mode applies to all alternates so we do not have to iterate 366 * through the alt's. 367 */ 368 void 369 client_manage_polling_mode(struct server_info *info, int *didreconnect) 370 { 371 /* 372 * Permanently failed servers are ignored. 373 */ 374 if (info->server_state == -2) 375 return; 376 377 /* 378 * Our polling interval has not yet passed. 379 */ 380 if (info->poll_sleep) 381 return; 382 383 /* 384 * Standard polling mode progression 385 */ 386 switch(info->poll_mode) { 387 case POLL_FIXED: 388 /* 389 * Initial state after connect or when a reconnect is required. 390 */ 391 if (info->fd < 0) { 392 logdebuginfo(info, 2, "polling mode INIT, relookup & reconnect\n"); 393 reconnect_server(info); 394 *didreconnect = 1; 395 if (info->fd < 0) { 396 if (info->poll_failed >= POLL_RECOVERY_RESTART * 5) 397 info->poll_sleep = max_sleep_opt; 398 else if (info->poll_failed >= POLL_RECOVERY_RESTART) 399 info->poll_sleep = nom_sleep_opt; 400 else 401 info->poll_sleep = min_sleep_opt; 402 break; 403 } 404 405 /* 406 * Transition the server to the DNS lookup successful state. 407 * Note that the server state does not transition out of 408 * lookup successful if we relookup after a packet failure 409 * so the message is printed only once, usually. 410 */ 411 client_setserverstate(info, 0, "DNS lookup success"); 412 413 /* 414 * If we've failed many times switch to the startup state but 415 * do not fall through into it. break the switch and a single 416 * poll will be made after the nominal polling interval. 417 */ 418 if (info->poll_failed >= POLL_RECOVERY_RESTART * 5) { 419 logdebuginfo(info, 2, "polling mode INIT->STARTUP (very slow)\n"); 420 info->poll_mode = POLL_STARTUP; 421 info->poll_sleep = max_sleep_opt; 422 info->poll_count = 0; 423 break; 424 } else if (info->poll_failed >= POLL_RECOVERY_RESTART) { 425 logdebuginfo(info, 2, "polling mode INIT->STARTUP (slow)\n"); 426 info->poll_mode = POLL_STARTUP; 427 info->poll_count = 0; 428 break; 429 } 430 } 431 432 /* 433 * Fall through to the startup state. 434 */ 435 info->poll_mode = POLL_STARTUP; 436 logdebuginfo(info, 2, "polling mode INIT->STARTUP (normal)\n"); 437 /* fall through */ 438 case POLL_STARTUP: 439 /* 440 * Transition to a FAILED state if too many poll failures occured. 441 */ 442 if (info->poll_failed >= POLL_FAIL_RESET) { 443 logdebuginfo(info, 2, "polling mode STARTUP->FAILED\n"); 444 info->poll_mode = POLL_FAILED; 445 info->poll_count = 0; 446 break; 447 } 448 449 /* 450 * Transition the server to operational. Do a number of minimum 451 * interval polls to try to get a good offset calculation quickly. 452 */ 453 if (info->poll_count) 454 client_setserverstate(info, 1, "connected ok"); 455 if (info->poll_count < POLL_STARTUP_MAX) { 456 info->poll_sleep = min_sleep_opt; 457 break; 458 } 459 460 /* 461 * Once we've got our polls fall through to aquisition mode to 462 * do aquisition processing. 463 */ 464 info->poll_mode = POLL_ACQUIRE; 465 info->poll_count = 0; 466 logdebuginfo(info, 2, "polling mode STARTUP->ACQUIRE\n"); 467 /* fall through */ 468 case POLL_ACQUIRE: 469 /* 470 * Transition to a FAILED state if too many poll failures occured. 471 */ 472 if (info->poll_failed >= POLL_FAIL_RESET) { 473 logdebuginfo(info, 2, "polling mode STARTUP->FAILED\n"); 474 info->poll_mode = POLL_FAILED; 475 info->poll_count = 0; 476 break; 477 } 478 479 /* 480 * Acquisition mode using the nominal timeout. We do not shift 481 * to maintainance mode unless the correlation is at least 0.90 482 */ 483 if (info->poll_count < POLL_ACQUIRE_MAX || 484 info->lin_count < 8 || 485 fabs(info->lin_cache_corr) < 0.85 486 ) { 487 if (info->poll_count >= POLL_ACQUIRE_MAX && 488 info->lin_count == LIN_RESTART - 2 489 ) { 490 logdebuginfo(info, 2, 491 "WARNING: Unable to shift this source to " 492 "maintenance mode. Target correlation is aweful\n"); 493 } 494 break; 495 } 496 info->poll_mode = POLL_MAINTAIN; 497 info->poll_count = 0; 498 logdebuginfo(info, 2, "polling mode ACQUIRE->MAINTAIN\n"); 499 /* fall through */ 500 case POLL_MAINTAIN: 501 /* 502 * Transition to a FAILED state if too many poll failures occured. 503 */ 504 if (info->poll_failed >= POLL_FAIL_RESET) { 505 logdebuginfo(info, 2, "polling mode STARTUP->FAILED\n"); 506 info->poll_mode = POLL_FAILED; 507 info->poll_count = 0; 508 break; 509 } 510 511 /* 512 * Maintaince mode, max polling interval. 513 * 514 * Transition back to acquisition mode if we are unable to maintain 515 * this mode due to the correlation going bad. 516 */ 517 if (info->lin_count >= LIN_RESTART / 2 && 518 fabs(info->lin_cache_corr) < 0.70 519 ) { 520 logdebuginfo(info, 2, 521 "polling mode MAINTAIN->ACQUIRE. Unable to maintain\n" 522 "the maintenance mode because the correlation went" 523 " bad!\n"); 524 info->poll_mode = POLL_ACQUIRE; 525 info->poll_count = 0; 526 break; 527 } 528 info->poll_sleep = max_sleep_opt; 529 break; 530 case POLL_FAILED: 531 /* 532 * We have a communications failure. A late recovery is possible 533 * if we enter this state with a good poll. 534 */ 535 if (info->poll_count != 0) { 536 logdebuginfo(info, 2, "polling mode FAILED->ACQUIRE\n"); 537 if (info->poll_failed >= POLL_FAIL_RESET) 538 info->poll_mode = POLL_STARTUP; 539 else 540 info->poll_mode = POLL_ACQUIRE; 541 /* do not reset poll_count */ 542 break; 543 } 544 545 /* 546 * If we have been failed too long, disconnect from the server 547 * and start us all over again. Note that the failed count is not 548 * reset to 0. 549 */ 550 if (info->poll_failed >= POLL_RECOVERY_RESTART) { 551 logdebuginfo(info, 2, "polling mode FAILED->INIT\n"); 552 client_setserverstate(info, 0, "FAILED"); 553 disconnect_server(info); 554 info->poll_mode = POLL_FIXED; 555 break; 556 } 557 break; 558 } 559 560 /* 561 * If the above state machine has not set a polling interval, set a 562 * nominal polling interval. 563 */ 564 if (info->poll_sleep == 0) 565 info->poll_sleep = nom_sleep_opt; 566 } 567 568 /* 569 * Look for duplicate IP addresses. This is done very inoften, so we do 570 * not use a particularly efficient algorithm. 571 * 572 * Only reconnect a client which has not done its initial poll. 573 */ 574 void 575 client_check_duplicate_ips(struct server_info **info_ary, int count) 576 { 577 server_info_t info1; 578 server_info_t info2; 579 int tries; 580 int i; 581 int j; 582 583 for (i = 0; i < count; ++i) { 584 info1 = info_ary[i]; 585 if (info1->fd < 0 || info1->server_state != 0) 586 continue; 587 for (tries = 0; tries < 10; ++tries) { 588 for (j = 0; j < count; ++j) { 589 info2 = info_ary[j]; 590 if (i == j || info2->fd < 0) 591 continue; 592 if (info1->fd < 0 || /* info1 was lost in previous reconnect */ 593 strcmp(info1->ipstr, info2->ipstr) == 0) { 594 reconnect_server(info1); 595 break; 596 } 597 } 598 if (j == count) 599 break; 600 } 601 if (tries == 10) { 602 disconnect_server(info1); 603 client_setserverstate(info1, -2, 604 "permanently disabling duplicate server"); 605 } 606 } 607 } 608 609 /* 610 * Calculate whether the server pointed to by *bestp is insane or not. 611 * For some reason some servers in e.g. the ntp pool are sometimes an hour 612 * off. If we have at least three servers in the pool require that a 613 * quorum agree that the current best server's offset is reasonable. 614 * 615 * Allow +/- 0.5 seconds of error for now (settable with option). 616 * 617 * Returns -1 if insane, 0 if not enough samples, and 1 if ok 618 */ 619 static 620 int 621 client_insane(struct server_info **info_ary, int count, server_info_t best) 622 { 623 server_info_t info; 624 double best_offset; 625 double info_offset; 626 int good; 627 int bad; 628 int skip; 629 int quorum; 630 int i; 631 632 /* 633 * If only one ntp server we cannot check to see if it is insane 634 */ 635 if (count < 2) 636 return(1); 637 best_offset = best->lin_sumoffset / best->lin_countoffset; 638 639 /* 640 * Calculated the quorum. Do not count permanently failed servers 641 * in the calculation. 642 * 643 * adjusted count quorum 644 * 2 2 645 * 3 2 646 * 4 3 647 * 5 3 648 */ 649 quorum = count; 650 for (i = 0; i < count; ++i) { 651 info = info_ary[i]; 652 if (info->server_state == -2) 653 --quorum; 654 } 655 656 quorum = quorum / 2 + 1; 657 good = 0; 658 bad = 0; 659 skip = 0; 660 661 /* 662 * Find the good, the bad, and the ugly. We need at least four samples 663 * and a stddev within the deviation being checked to count a server 664 * in the calculation. 665 */ 666 for (i = 0; i < count; ++i) { 667 info = info_ary[i]; 668 if (info->lin_countoffset < 4 || 669 info->lin_cache_stddev > insane_deviation 670 ) { 671 ++skip; 672 continue; 673 } 674 675 info_offset = info->lin_sumoffset / info->lin_countoffset; 676 info_offset -= best_offset; 677 if (info_offset < -insane_deviation || info_offset > insane_deviation) 678 ++bad; 679 else 680 ++good; 681 } 682 683 /* 684 * Did we meet our quorum? 685 */ 686 logdebuginfo(best, 5, "insanecheck good=%d bad=%d skip=%d " 687 "quorum=%d (allowed=%-+8.6f)\n", 688 good, bad, skip, quorum, insane_deviation); 689 if (good >= quorum) 690 return(1); 691 if (good + skip >= quorum) 692 return(0); 693 return(-1); 694 } 695 696 /* 697 * Linear regression. 698 * 699 * ltv local time as of when the offset error was calculated between 700 * local time and remote time. 701 * 702 * lbtv base time as of when local time was obtained. Used to 703 * calculate the cumulative corrections made to the system's 704 * real time clock so we can de-correct the offset for the 705 * linear regression. 706 * 707 * X is the time axis, in seconds. 708 * Y is the uncorrected offset, in seconds. 709 */ 710 void 711 lin_regress(server_info_t info, struct timeval *ltv, struct timeval *lbtv, 712 double offset, int calc_offset_correction) 713 { 714 double time_axis; 715 double uncorrected_offset; 716 717 /* 718 * De-correcting the offset: 719 * 720 * The passed offset is (our_real_time - remote_real_time). To remove 721 * corrections from our_real_time we take the difference in the basetime 722 * (new_base_time - old_base_time) and subtract that from the offset. 723 * That is, if the basetime goesup, the uncorrected offset goes down. 724 */ 725 if (info->lin_count == 0) { 726 info->lin_tv = *ltv; 727 info->lin_btv = *lbtv; 728 time_axis = 0; 729 uncorrected_offset = offset; 730 } else { 731 time_axis = tv_delta_double(&info->lin_tv, ltv); 732 uncorrected_offset = offset - tv_delta_double(&info->lin_btv, lbtv); 733 } 734 735 /* 736 * We have to use the uncorrected offset for frequency calculations. 737 */ 738 ++info->lin_count; 739 info->lin_sumx += time_axis; 740 info->lin_sumx2 += time_axis * time_axis; 741 info->lin_sumy += uncorrected_offset; 742 info->lin_sumy2 += uncorrected_offset * uncorrected_offset; 743 info->lin_sumxy += time_axis * uncorrected_offset; 744 745 /* 746 * We have to use the corrected offset for offset calculations. 747 */ 748 if (calc_offset_correction) { 749 ++info->lin_countoffset; 750 info->lin_sumoffset += offset; 751 info->lin_sumoffset2 += offset * offset; 752 } 753 754 /* 755 * Calculate various derived values. This gets us slope, y-intercept, 756 * and correlation from the linear regression. 757 */ 758 if (info->lin_count > 1) { 759 info->lin_cache_slope = 760 (info->lin_count * info->lin_sumxy - info->lin_sumx * info->lin_sumy) / 761 (info->lin_count * info->lin_sumx2 - info->lin_sumx * info->lin_sumx); 762 763 info->lin_cache_yint = 764 (info->lin_sumy - info->lin_cache_slope * info->lin_sumx) / 765 (info->lin_count); 766 767 info->lin_cache_corr = 768 (info->lin_count * info->lin_sumxy - info->lin_sumx * info->lin_sumy) / 769 sqrt((info->lin_count * info->lin_sumx2 - 770 info->lin_sumx * info->lin_sumx) * 771 (info->lin_count * info->lin_sumy2 - 772 info->lin_sumy * info->lin_sumy) 773 ); 774 } 775 776 /* 777 * Calculate more derived values. This gets us the standard-deviation 778 * of offsets. The standard deviation approximately means that 68% 779 * of the samples fall within the calculated stddev of the mean. 780 */ 781 if (info->lin_countoffset > 1) { 782 info->lin_cache_stddev = 783 sqrt((info->lin_sumoffset2 - 784 ((info->lin_sumoffset * info->lin_sumoffset / 785 info->lin_countoffset))) / 786 (info->lin_countoffset - 1.0)); 787 } 788 789 /* 790 * Save the most recent offset, we might use it in the future. 791 * Save the frequency correction (we might scale the slope later so 792 * we have a separate field for the actual frequency correction in 793 * seconds per second). 794 */ 795 info->lin_cache_offset = offset; 796 info->lin_cache_freq = info->lin_cache_slope; 797 798 if (debug_level >= 4) { 799 logdebuginfo(info, 4, "iter=%2d time=%7.3f off=%+.6f uoff=%+.6f", 800 (int)info->lin_count, 801 time_axis, offset, uncorrected_offset); 802 if (info->lin_count > 1) { 803 logdebug(4, " slope %+7.6f" 804 " yint %+3.2f corr %+7.6f freq_ppm %+4.2f", 805 info->lin_cache_slope, 806 info->lin_cache_yint, 807 info->lin_cache_corr, 808 info->lin_cache_freq * 1000000.0); 809 } 810 if (info->lin_countoffset > 1) { 811 logdebug(4, " stddev %7.6f", info->lin_cache_stddev); 812 } else if (calc_offset_correction == 0) { 813 /* cannot calculate offset correction due to prior correction */ 814 logdebug(4, " offset_ignored"); 815 } 816 logdebug(4, "\n"); 817 } 818 } 819 820 /* 821 * Reset the linear regression data. The info structure will not again be 822 * a candidate for frequency or offset correction until sufficient data 823 * has been accumulated to make a decision. 824 */ 825 void 826 lin_reset(server_info_t info) 827 { 828 server_info_t scan; 829 830 info->lin_count = 0; 831 info->lin_sumx = 0; 832 info->lin_sumy = 0; 833 info->lin_sumxy = 0; 834 info->lin_sumx2 = 0; 835 info->lin_sumy2 = 0; 836 837 info->lin_countoffset = 0; 838 info->lin_sumoffset = 0; 839 info->lin_sumoffset2 = 0; 840 841 info->lin_cache_slope = 0; 842 info->lin_cache_yint = 0; 843 info->lin_cache_corr = 0; 844 info->lin_cache_offset = 0; 845 info->lin_cache_freq = 0; 846 847 /* 848 * Destroy any additional alternative regressions. 849 */ 850 while ((scan = info->altinfo) != NULL) { 851 info->altinfo = scan->altinfo; 852 free(scan); 853 } 854 } 855 856 /* 857 * Sometimes we want to clean out the offset calculations without 858 * destroying the linear regression used to figure out the frequency 859 * correction. This usually occurs whenever we issue an offset 860 * adjustment to the system, which invalidates any offset data accumulated 861 * up to that point. 862 */ 863 void 864 lin_resetalloffsets(struct server_info **info_ary, int count) 865 { 866 server_info_t info; 867 int i; 868 869 for (i = 0; i < count; ++i) { 870 for (info = info_ary[i]; info; info = info->altinfo) 871 lin_resetoffsets(info); 872 } 873 } 874 875 void 876 lin_resetoffsets(server_info_t info) 877 { 878 info->lin_countoffset = 0; 879 info->lin_sumoffset = 0; 880 info->lin_sumoffset2 = 0; 881 } 882 883 void 884 client_setserverstate(server_info_t info, int state, const char *str) 885 { 886 if (info->server_state != state) { 887 info->server_state = state; 888 logdebuginfo(info, 1, "%s\n", str); 889 } 890 } 891 892