diff --git a/chrony.texi b/chrony.texi index beb6b40..f86a0ac 100644 --- a/chrony.texi +++ b/chrony.texi @@ -1861,8 +1861,8 @@ Local poll [10] Remote poll [10] @item `Score' (an internal score within each polling level used to decide when -to increase or decrease the polling level. This is adjusted based on -changes to the variance of the measurements obtained from the source). [1] +to increase or decrease the polling level. This is adjusted based on number +of measurements currently being used for the regression algorithm). [1.0] @item The estimated local clock error (`theta' in RFC1305). Positive indicates that the local clock is slow. [-4.966e-03]. @item @@ -2629,6 +2629,12 @@ selecting that source. This is useful with low stratum sources that are known to be unrealiable or inaccurate and which should be used only when other sources are unreachable. +@item polltarget +Target number of measurements to use for the regression algorithm which +@code{chronyd} will try to maintain by adjusting polling interval between +@code{minpoll} and @code{maxpoll}. A higher target makes @code{chronyd} prefer +shorter polling intervals. The default is 6 and a useful range is 6 to 60. + @item prefer Prefer this source over sources without prefer option. diff --git a/client.c b/client.c index 2b7164e..c31564d 100644 --- a/client.c +++ b/client.c @@ -936,6 +936,11 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) break; } + if (data.params.poll_target != SRC_DEFAULT_POLLTARGET) { + fprintf(stderr, "Option polltarget not supported\n"); + break; + } + msg->data.ntp_source.port = htonl((unsigned long) data.port); UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr); msg->data.ntp_source.minpoll = htonl(data.params.minpoll); @@ -983,6 +988,9 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) case CPS_BadMinstratum: fprintf(stderr, "Unreadable minstratum value\n"); break; + case CPS_BadPolltarget: + fprintf(stderr, "Unreadable polltarget value\n"); + break; } return result; diff --git a/cmdmon.c b/cmdmon.c index 1a1c10e..3b9fe19 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -1251,6 +1251,7 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m /* not transmitted in cmdmon protocol yet */ params.min_stratum = SRC_DEFAULT_MINSTRATUM; + params.poll_target = SRC_DEFAULT_POLLTARGET; status = NSR_AddSource(&rem_addr, type, ¶ms); switch (status) { diff --git a/cmdparse.c b/cmdparse.c index dca477f..be45989 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -60,6 +60,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src) src->params.auto_offline = 0; src->params.iburst = 0; src->params.min_stratum = SRC_DEFAULT_MINSTRATUM; + src->params.poll_target = SRC_DEFAULT_POLLTARGET; src->params.sel_option = SRC_SelectNormal; result = CPS_Success; @@ -165,6 +166,15 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src) line += n; } + } else if (!strncasecmp(cmd, "polltarget", 10)) { + if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) { + result = CPS_BadPolltarget; + ok = 0; + done = 1; + } else { + line += n; + } + } else if (!strncasecmp(cmd, "noselect", 8)) { src->params.sel_option = SRC_SelectNoselect; diff --git a/cmdparse.h b/cmdparse.h index 9f4d4ae..a6353bd 100644 --- a/cmdparse.h +++ b/cmdparse.h @@ -45,7 +45,8 @@ typedef enum { CPS_BadMaxdelayratio, CPS_BadMaxdelay, CPS_BadKey, - CPS_BadMinstratum + CPS_BadMinstratum, + CPS_BadPolltarget } CPS_Status; typedef struct { diff --git a/conf.c b/conf.c index 552a5fd..5bfd326 100644 --- a/conf.c +++ b/conf.c @@ -397,6 +397,9 @@ parse_source(const char *line, NTP_Source_Type type) case CPS_BadMinstratum: LOG(LOGS_WARN, LOGF_Configure, "Unreadable minstratum value at line %d", line_number); break; + case CPS_BadPolltarget: + LOG(LOGS_WARN, LOGF_Configure, "Unreadable polltarget value at line %d", line_number); + break; } return; diff --git a/ntp_core.c b/ntp_core.c index 7f8d3ca..62148cb 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -55,10 +55,6 @@ static LOG_FileID logfileid; /* Day number of 1 Jan 1970 */ #define MJD_1970 40587 -/* ================================================== */ - -#define ZONE_WIDTH 4 - /* ================================================== */ /* Enumeration used for remembering the operating mode of one of the sources */ @@ -110,6 +106,10 @@ struct NCR_Instance_Record { int min_stratum; /* Increase stratum in received packets to the minimum */ + int poll_target; /* Target number of sourcestats samples */ + + double poll_score; /* Score of current local poll */ + double max_delay; /* Maximum round-trip delay to the peer that we can tolerate and still use the sample for generating @@ -163,8 +163,6 @@ struct NCR_Instance_Record { SRC_Instance source; - int score; - int burst_good_samples_to_go; int burst_total_samples_to_go; @@ -215,7 +213,7 @@ void NCR_Initialise(void) { logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements", - " Date (UTC) Time IP Address L St 1234 ab 5678 LP RP SC Offset Peer del. Peer disp. Root del. Root disp.") + " Date (UTC) Time IP Address L St 1234 ab 5678 LP RP Score Offset Peer del. Peer disp. Root del. Root disp.") : -1; access_auth_table = ADF_CreateTable(); @@ -292,7 +290,8 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar result->remote_orig.hi = 0; result->remote_orig.lo = 0; - result->score = 0; + result->poll_target = params->poll_target; + result->poll_score = 0.0; if (params->online) { start_initial_timeout(result); @@ -448,29 +447,28 @@ check_packet_auth(NTP_Packet *pkt, unsigned long keyid) /* ================================================== */ static void -normalise_score(NCR_Instance inst) +adjust_poll(NCR_Instance inst, double adj) { + inst->poll_score += adj; - while (inst->score >= ZONE_WIDTH) { - ++inst->local_poll; - inst->score -= ZONE_WIDTH; + if (inst->poll_score >= 1.0) { + inst->local_poll += (int)inst->poll_score; + inst->poll_score -= (int)inst->poll_score; } - while (inst->score < 0) { - if (inst->local_poll > 0) { - --inst->local_poll; - } - inst->score += ZONE_WIDTH; + + if (inst->poll_score < 0.0) { + inst->local_poll += (int)(inst->poll_score - 1.0); + inst->poll_score -= (int)(inst->poll_score - 1.0); } /* Clamp polling interval to defined range */ if (inst->local_poll < inst->minpoll) { inst->local_poll = inst->minpoll; - inst->score = 0; + inst->poll_score = 0; } else if (inst->local_poll > inst->maxpoll) { inst->local_poll = inst->maxpoll; - inst->score = ZONE_WIDTH - 1; + inst->poll_score = 1.0; } - } /* ================================================== */ @@ -652,13 +650,11 @@ transmit_timeout(void *arg) if (SRC_IsSyncPeer(inst->source)) { if (inst->tx_count >= 2) { /* Implies we have missed at least one transmission */ - inst->score -= 3; - normalise_score(inst); + adjust_poll(inst, -0.75); } } else { if (inst->tx_count >= 2) { - inst->score += 1; - normalise_score(inst); + adjust_poll(inst, 0.25); } } @@ -810,7 +806,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins int poll_to_use; double delay_time = 0; int requeue_transmit = 0; - int delta_score; + double poll_adj; /* ==================== */ @@ -1089,31 +1085,22 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins temp>>=1; } while (temp); - inst->local_poll -= shift; - inst->score = 0; + poll_adj = -shift - inst->poll_score + 0.5; } else { + int samples = SRC_Samples(inst->source); - switch (SRC_LastSkewChange(inst->source)) { - case SRC_Skew_Decrease: - delta_score = 1; - break; - case SRC_Skew_Nochange: - delta_score = 0; - break; - case SRC_Skew_Increase: - delta_score = -2; - break; - default: /* Should not happen! */ - delta_score = 0; - break; - } + /* Adjust polling interval so that the number of sourcestats samples + remains close to the target value */ + poll_adj = ((double)samples / inst->poll_target - 1.0) / inst->poll_target; - inst->score += delta_score; + /* Use higher gain when decreasing the interval */ + if (samples < inst->poll_target) { + poll_adj *= 2.0; + } } - normalise_score(inst); - + adjust_poll(inst, poll_adj); } /* Reduce polling rate if KoD RATE was received */ @@ -1253,7 +1240,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins /* Do measurement logging */ if (logfileid != -1) { - LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d %1d%1d%1d%1d %2d %2d %2d %10.3e %10.3e %10.3e %10.3e %10.3e", + LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d %1d%1d%1d%1d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e", UTI_TimeToLogForm(sample_time.tv_sec), UTI_IPToString(&inst->remote_addr.ip_addr), sync_stats[pkt_leap], @@ -1262,7 +1249,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins test4a, test4b, test5, test6, test7, test8, inst->local_poll, inst->remote_poll, - (inst->score), + inst->poll_score, theta, delta, epsilon, pkt_root_delay, pkt_root_dispersion); } @@ -1668,7 +1655,7 @@ NCR_TakeSourceOnline(NCR_Instance inst) /* We are not already actively polling it */ LOG(LOGS_INFO, LOGF_NtpCore, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr)); inst->local_poll = inst->minpoll; - inst->score = (ZONE_WIDTH >> 1); + inst->poll_score = 0.5; inst->opmode = MD_ONLINE; start_initial_timeout(inst); } diff --git a/sources.c b/sources.c index a019890..38706ca 100644 --- a/sources.c +++ b/sources.c @@ -1027,3 +1027,11 @@ SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst) } /* ================================================== */ + +int +SRC_Samples(SRC_Instance inst) +{ + return SST_Samples(inst->stats); +} + +/* ================================================== */ diff --git a/sources.h b/sources.h index aff800a..d89ce59 100644 --- a/sources.h +++ b/sources.h @@ -165,5 +165,7 @@ typedef enum { extern SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst); +extern int SRC_Samples(SRC_Instance inst); + #endif /* GOT_SOURCES_H */ diff --git a/sourcestats.c b/sourcestats.c index bcd818e..652421f 100644 --- a/sourcestats.c +++ b/sourcestats.c @@ -789,6 +789,14 @@ SST_Skew_Direction SST_LastSkewChange(SST_Stats inst) /* ================================================== */ +int +SST_Samples(SST_Stats inst) +{ + return inst->n_samples; +} + +/* ================================================== */ + void SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct timeval *now) { diff --git a/sourcestats.h b/sourcestats.h index c48af7b..e47287f 100644 --- a/sourcestats.h +++ b/sourcestats.h @@ -153,5 +153,7 @@ typedef enum { extern SST_Skew_Direction SST_LastSkewChange(SST_Stats inst); +extern int SST_Samples(SST_Stats inst); + #endif /* GOT_SOURCESTATS_H */ diff --git a/srcparams.h b/srcparams.h index 9db3806..58395cb 100644 --- a/srcparams.h +++ b/srcparams.h @@ -41,6 +41,7 @@ typedef struct { int presend_minpoll; int iburst; int min_stratum; + int poll_target; unsigned long authkey; double max_delay; double max_delay_ratio; @@ -54,6 +55,7 @@ typedef struct { #define SRC_DEFAULT_MAXDELAY 16.0 #define SRC_DEFAULT_MAXDELAYRATIO 16384.0 #define SRC_DEFAULT_MINSTRATUM 0 +#define SRC_DEFAULT_POLLTARGET 6 #define INACTIVE_AUTHKEY 0UL #endif /* GOT_SRCPARAMS_H */