From 6688f4032585e2a0d59e711f8074b926fa3cc177 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Mon, 1 Dec 2014 18:35:35 +0100 Subject: [PATCH] sources: allow setting minsamples and maxsamples for each source The minsamples and maxsamples directives now set the default value, which can be overriden for individual sources in the server/peer/pool and refclock directives. --- chrony.texi.in | 30 ++++++++++++++++++++++++------ client.c | 16 ++++++++++++++++ cmdparse.c | 18 ++++++++++++++++++ cmdparse.h | 2 ++ conf.c | 18 +++++++++++++++++- ntp_core.c | 5 ++++- refclock.c | 3 ++- refclock.h | 2 ++ sources.c | 9 +++++++-- sources.h | 2 +- sourcestats.c | 19 ++++++++++--------- sourcestats.h | 2 +- srcparams.h | 4 ++++ 13 files changed, 108 insertions(+), 22 deletions(-) diff --git a/chrony.texi.in b/chrony.texi.in index 6f195f3..cb81ef1 100644 --- a/chrony.texi.in +++ b/chrony.texi.in @@ -2375,9 +2375,11 @@ crystal oscillator. @c {{{ maxsamples @node maxsamples directive @subsection maxsamples -The @code{maxsamples} directive sets the maximum number of samples -@code{chronyd} should keep for each source. The default is 0, which -disables the configurable limit, and the useful range is 4 to 64. +The @code{maxsamples} directive sets the default maximum number of samples +@code{chronyd} should keep for each source. This setting can be overriden for +individual sources in the @code{server} and @code{refclock} directives +(@pxref{server directive}, @pxref{refclock directive}). The default value is +0, which disables the configurable limit. The useful range is 4 to 64. The syntax is @@ -2439,9 +2441,11 @@ the new master estimate. @c {{{ minsamples @node minsamples directive @subsection minsamples -The @code{minsamples} directive sets the minimum number of samples -@code{chronyd} should try to keep for each source. The default is 0 and the -useful range is 4 to 64. +The @code{minsamples} directive sets the default minimum number of samples +@code{chronyd} should keep for each source. This setting can be overriden for +individual sources in the @code{server} and @code{refclock} directives +(@pxref{server directive}, @pxref{refclock directive}). The default value is +0. The useful range is 4 to 64. The syntax is @@ -2669,6 +2673,12 @@ Prefer this source over sources without prefer option. @item noselect Never select this source. This is useful for monitoring or with sources which are not very accurate, but are locked with a PPS refclock. +@item minsamples +Set the minimum number of samples kept for this source. This overrides the +@code{minsamples} directive (@pxref{minsamples directive}). +@item maxsamples +Set the maximum number of samples kept for this source. This overrides the +@code{maxsamples} directive (@pxref{maxsamples directive}). @end table @c }}} @@ -2956,6 +2966,14 @@ Prefer this source over sources without prefer option. @item noselect Never select this source. This is particularly useful for monitoring. +@item minsamples +Set the minimum number of samples kept for this source. This overrides the +@code{minsamples} directive (@pxref{minsamples directive}). + +@item maxsamples +Set the maximum number of samples kept for this source. This overrides the +@code{maxsamples} directive (@pxref{maxsamples directive}). + @end table @c }}} @c {{{ stratumweight diff --git a/client.c b/client.c index 0a390c0..3822dd4 100644 --- a/client.c +++ b/client.c @@ -965,6 +965,16 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) break; } + if (data.params.min_samples != SRC_DEFAULT_MINSAMPLES) { + fprintf(stderr, "Option minsamples not supported\n"); + break; + } + + if (data.params.max_samples != SRC_DEFAULT_MAXSAMPLES) { + fprintf(stderr, "Option maxsamples not supported\n"); + break; + } + msg->data.ntp_source.port = htonl((unsigned long) data.port); UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr); msg->data.ntp_source.minpoll = htonl(data.params.minpoll); @@ -1024,6 +1034,12 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) case CPS_BadMaxsources: fprintf(stderr, "Unreadable maxsources value\n"); break; + case CPS_BadMinsamples: + fprintf(stderr, "Unreadable minsamples value\n"); + break; + case CPS_BadMaxsamples: + fprintf(stderr, "Unreadable maxsamples value\n"); + break; } return result; diff --git a/cmdparse.c b/cmdparse.c index 88f98c2..0a54772 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -61,6 +61,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src) src->params.poll_target = SRC_DEFAULT_POLLTARGET; src->params.version = NTP_VERSION; src->params.max_sources = SRC_DEFAULT_MAXSOURCES; + src->params.min_samples = SRC_DEFAULT_MINSAMPLES; + src->params.max_samples = SRC_DEFAULT_MAXSAMPLES; src->params.sel_option = SRC_SelectNormal; result = CPS_Success; @@ -184,6 +186,22 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src) line += n; } + } else if (!strcasecmp(cmd, "minsamples")) { + if (sscanf(line, "%d%n", &src->params.min_samples, &n) != 1) { + result = CPS_BadMinsamples; + done = 1; + } else { + line += n; + } + + } else if (!strcasecmp(cmd, "maxsamples")) { + if (sscanf(line, "%d%n", &src->params.max_samples, &n) != 1) { + result = CPS_BadMaxsamples; + done = 1; + } else { + line += n; + } + } else { result = CPS_BadOption; done = 1; diff --git a/cmdparse.h b/cmdparse.h index ae863b1..75cce91 100644 --- a/cmdparse.h +++ b/cmdparse.h @@ -46,6 +46,8 @@ typedef enum { CPS_BadPolltarget, CPS_BadVersion, CPS_BadMaxsources, + CPS_BadMinsamples, + CPS_BadMaxsamples, } CPS_Status; typedef struct { diff --git a/conf.c b/conf.c index 3c26342..d6f1764 100644 --- a/conf.c +++ b/conf.c @@ -635,6 +635,12 @@ parse_source(char *line, NTP_Source_Type type, int pool) case CPS_BadMaxsources: other_parse_error("Unreadable maxsources"); break; + case CPS_BadMinsamples: + other_parse_error("Unreadable minsamples"); + break; + case CPS_BadMaxsamples: + other_parse_error("Unreadable maxsamples"); + break; } } @@ -667,7 +673,7 @@ parse_pool(char *line) static void parse_refclock(char *line) { - int n, poll, dpoll, filter_length, pps_rate; + int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples; uint32_t ref_id, lock_ref_id; double offset, delay, precision, max_dispersion; char *p, *cmd, *name, *param; @@ -679,6 +685,8 @@ parse_refclock(char *line) dpoll = 0; filter_length = 64; pps_rate = 0; + min_samples = SRC_DEFAULT_MINSAMPLES; + max_samples = SRC_DEFAULT_MAXSAMPLES; offset = 0.0; delay = 1e-9; precision = 0.0; @@ -732,6 +740,12 @@ parse_refclock(char *line) } else if (!strcasecmp(cmd, "rate")) { if (sscanf(line, "%d%n", &pps_rate, &n) != 1) break; + } else if (!strcasecmp(cmd, "minsamples")) { + if (sscanf(line, "%d%n", &min_samples, &n) != 1) + break; + } else if (!strcasecmp(cmd, "maxsamples")) { + if (sscanf(line, "%d%n", &max_samples, &n) != 1) + break; } else if (!strcasecmp(cmd, "offset")) { if (sscanf(line, "%lf%n", &offset, &n) != 1) break; @@ -768,6 +782,8 @@ parse_refclock(char *line) refclock->poll = poll; refclock->filter_length = filter_length; refclock->pps_rate = pps_rate; + refclock->min_samples = min_samples; + refclock->max_samples = max_samples; refclock->offset = offset; refclock->delay = delay; refclock->precision = precision; diff --git a/ntp_core.c b/ntp_core.c index 686f640..050d87e 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -461,7 +461,10 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar } /* Create a source instance for this NTP source */ - result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), SRC_NTP, params->sel_option, &result->remote_addr.ip_addr); + result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), + SRC_NTP, params->sel_option, + &result->remote_addr.ip_addr, + params->min_samples, params->max_samples); result->timer_running = 0; result->timeout_id = 0; diff --git a/refclock.c b/refclock.c index e667a80..5b728eb 100644 --- a/refclock.c +++ b/refclock.c @@ -260,7 +260,8 @@ RCL_AddRefclock(RefclockParameters *params) filter_init(&inst->filter, params->filter_length, params->max_dispersion); - inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL); + inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL, + params->min_samples, params->max_samples); DEBUG_LOG(LOGF_Refclock, "refclock %s refid=%s poll=%d dpoll=%d filter=%d", params->driver_name, UTI_RefidToString(inst->ref_id), diff --git a/refclock.h b/refclock.h index b2122d3..08996a7 100644 --- a/refclock.h +++ b/refclock.h @@ -38,6 +38,8 @@ typedef struct { int poll; int filter_length; int pps_rate; + int min_samples; + int max_samples; uint32_t ref_id; uint32_t lock_ref_id; double offset; diff --git a/sources.c b/sources.c index ba18bb5..007190a 100644 --- a/sources.c +++ b/sources.c @@ -207,14 +207,19 @@ void SRC_Finalise(void) /* Function to create a new instance. This would be called by one of the individual source-type instance creation routines. */ -SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr) +SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr, int min_samples, int max_samples) { SRC_Instance result; assert(initialised); + if (min_samples == SRC_DEFAULT_MINSAMPLES) + min_samples = CNF_GetMinSamples(); + if (max_samples == SRC_DEFAULT_MAXSAMPLES) + max_samples = CNF_GetMaxSamples(); + result = MallocNew(struct SRC_Instance_Record); - result->stats = SST_CreateInstance(ref_id, addr); + result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples); if (n_sources == max_n_sources) { /* Reallocate memory */ diff --git a/sources.h b/sources.h index 654b3c1..8c6027b 100644 --- a/sources.h +++ b/sources.h @@ -65,7 +65,7 @@ typedef enum { /* Function to create a new instance. This would be called by one of the individual source-type instance creation routines. */ -extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr); +extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr, int min_samples, int max_samples); /* Function to get rid of a source when it is being unconfigured. This may cause the current reference source to be reselected, if this diff --git a/sourcestats.c b/sourcestats.c index de5f312..7e97085 100644 --- a/sourcestats.c +++ b/sourcestats.c @@ -43,10 +43,6 @@ to store per source */ #define MAX_SAMPLES 64 -/* User defined maximum and minimum number of samples */ -int max_samples; -int min_samples; - /* This is the assumed worst case bound on an unknown frequency, 2000ppm, which would be pretty bad */ #define WORST_CASE_FREQ_BOUND (2000.0/1.0e6) @@ -68,6 +64,10 @@ struct SST_Stats_Record { uint32_t refid; IPAddr *ip_addr; + /* User defined minimum and maximum number of samples */ + int min_samples; + int max_samples; + /* Number of samples currently stored. The samples are stored in circular buffer. */ int n_samples; @@ -163,8 +163,6 @@ SST_Initialise(void) logfileid = CNF_GetLogStatistics() ? LOG_FileOpen("statistics", " Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr") : -1; - max_samples = CNF_GetMaxSamples(); - min_samples = CNF_GetMinSamples(); } /* ================================================== */ @@ -178,11 +176,14 @@ SST_Finalise(void) /* This function creates a new instance of the statistics handler */ SST_Stats -SST_CreateInstance(uint32_t refid, IPAddr *addr) +SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples) { SST_Stats inst; inst = MallocNew(struct SST_Stats_Record); + inst->min_samples = min_samples; + inst->max_samples = max_samples; + SST_SetRefid(inst, refid, addr); SST_ResetInstance(inst); @@ -262,7 +263,7 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time, /* Make room for the new sample */ if (inst->n_samples > 0 && - (inst->n_samples == MAX_SAMPLES || inst->n_samples == max_samples)) { + (inst->n_samples == MAX_SAMPLES || inst->n_samples == inst->max_samples)) { prune_register(inst, 1); } @@ -447,7 +448,7 @@ SST_DoNewRegression(SST_Stats inst) inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples, offsets + inst->runs_samples, weights, inst->n_samples, inst->runs_samples, - min_samples, + inst->min_samples, &est_intercept, &est_slope, &est_var, &est_intercept_sd, &est_slope_sd, &best_start, &nruns, °rees_of_freedom); diff --git a/sourcestats.h b/sourcestats.h index ad9f5d8..cba0a65 100644 --- a/sourcestats.h +++ b/sourcestats.h @@ -38,7 +38,7 @@ extern void SST_Initialise(void); extern void SST_Finalise(void); /* This function creates a new instance of the statistics handler */ -extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr); +extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples); /* This function deletes an instance of the statistics handler. */ extern void SST_DeleteInstance(SST_Stats inst); diff --git a/srcparams.h b/srcparams.h index fdf0abb..fefdcc2 100644 --- a/srcparams.h +++ b/srcparams.h @@ -40,6 +40,8 @@ typedef struct { int poll_target; int version; int max_sources; + int min_samples; + int max_samples; uint32_t authkey; double max_delay; double max_delay_ratio; @@ -57,6 +59,8 @@ typedef struct { #define SRC_DEFAULT_MINSTRATUM 0 #define SRC_DEFAULT_POLLTARGET 6 #define SRC_DEFAULT_MAXSOURCES 4 +#define SRC_DEFAULT_MINSAMPLES (-1) +#define SRC_DEFAULT_MAXSAMPLES (-1) #define INACTIVE_AUTHKEY 0 #endif /* GOT_SRCPARAMS_H */