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.
This commit is contained in:
Miroslav Lichvar 2014-12-01 18:35:35 +01:00
parent 42dd5caa1b
commit 6688f40325
13 changed files with 108 additions and 22 deletions

View file

@ -2375,9 +2375,11 @@ crystal oscillator.
@c {{{ maxsamples @c {{{ maxsamples
@node maxsamples directive @node maxsamples directive
@subsection maxsamples @subsection maxsamples
The @code{maxsamples} directive sets the maximum number of samples The @code{maxsamples} directive sets the default maximum number of samples
@code{chronyd} should keep for each source. The default is 0, which @code{chronyd} should keep for each source. This setting can be overriden for
disables the configurable limit, and the useful range is 4 to 64. 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 The syntax is
@ -2439,9 +2441,11 @@ the new master estimate.
@c {{{ minsamples @c {{{ minsamples
@node minsamples directive @node minsamples directive
@subsection minsamples @subsection minsamples
The @code{minsamples} directive sets the minimum number of samples The @code{minsamples} directive sets the default minimum number of samples
@code{chronyd} should try to keep for each source. The default is 0 and the @code{chronyd} should keep for each source. This setting can be overriden for
useful range is 4 to 64. 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 The syntax is
@ -2669,6 +2673,12 @@ Prefer this source over sources without prefer option.
@item noselect @item noselect
Never select this source. This is useful for monitoring or with sources Never select this source. This is useful for monitoring or with sources
which are not very accurate, but are locked with a PPS refclock. 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 @end table
@c }}} @c }}}
@ -2956,6 +2966,14 @@ Prefer this source over sources without prefer option.
@item noselect @item noselect
Never select this source. This is particularly useful for monitoring. 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 @end table
@c }}} @c }}}
@c {{{ stratumweight @c {{{ stratumweight

View file

@ -965,6 +965,16 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
break; 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); msg->data.ntp_source.port = htonl((unsigned long) data.port);
UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr); UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll); 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: case CPS_BadMaxsources:
fprintf(stderr, "Unreadable maxsources value\n"); fprintf(stderr, "Unreadable maxsources value\n");
break; break;
case CPS_BadMinsamples:
fprintf(stderr, "Unreadable minsamples value\n");
break;
case CPS_BadMaxsamples:
fprintf(stderr, "Unreadable maxsamples value\n");
break;
} }
return result; return result;

View file

@ -61,6 +61,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.poll_target = SRC_DEFAULT_POLLTARGET; src->params.poll_target = SRC_DEFAULT_POLLTARGET;
src->params.version = NTP_VERSION; src->params.version = NTP_VERSION;
src->params.max_sources = SRC_DEFAULT_MAXSOURCES; 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; src->params.sel_option = SRC_SelectNormal;
result = CPS_Success; result = CPS_Success;
@ -184,6 +186,22 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
line += n; 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 { } else {
result = CPS_BadOption; result = CPS_BadOption;
done = 1; done = 1;

View file

@ -46,6 +46,8 @@ typedef enum {
CPS_BadPolltarget, CPS_BadPolltarget,
CPS_BadVersion, CPS_BadVersion,
CPS_BadMaxsources, CPS_BadMaxsources,
CPS_BadMinsamples,
CPS_BadMaxsamples,
} CPS_Status; } CPS_Status;
typedef struct { typedef struct {

18
conf.c
View file

@ -635,6 +635,12 @@ parse_source(char *line, NTP_Source_Type type, int pool)
case CPS_BadMaxsources: case CPS_BadMaxsources:
other_parse_error("Unreadable maxsources"); other_parse_error("Unreadable maxsources");
break; 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 static void
parse_refclock(char *line) 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; uint32_t ref_id, lock_ref_id;
double offset, delay, precision, max_dispersion; double offset, delay, precision, max_dispersion;
char *p, *cmd, *name, *param; char *p, *cmd, *name, *param;
@ -679,6 +685,8 @@ parse_refclock(char *line)
dpoll = 0; dpoll = 0;
filter_length = 64; filter_length = 64;
pps_rate = 0; pps_rate = 0;
min_samples = SRC_DEFAULT_MINSAMPLES;
max_samples = SRC_DEFAULT_MAXSAMPLES;
offset = 0.0; offset = 0.0;
delay = 1e-9; delay = 1e-9;
precision = 0.0; precision = 0.0;
@ -732,6 +740,12 @@ parse_refclock(char *line)
} else if (!strcasecmp(cmd, "rate")) { } else if (!strcasecmp(cmd, "rate")) {
if (sscanf(line, "%d%n", &pps_rate, &n) != 1) if (sscanf(line, "%d%n", &pps_rate, &n) != 1)
break; 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")) { } else if (!strcasecmp(cmd, "offset")) {
if (sscanf(line, "%lf%n", &offset, &n) != 1) if (sscanf(line, "%lf%n", &offset, &n) != 1)
break; break;
@ -768,6 +782,8 @@ parse_refclock(char *line)
refclock->poll = poll; refclock->poll = poll;
refclock->filter_length = filter_length; refclock->filter_length = filter_length;
refclock->pps_rate = pps_rate; refclock->pps_rate = pps_rate;
refclock->min_samples = min_samples;
refclock->max_samples = max_samples;
refclock->offset = offset; refclock->offset = offset;
refclock->delay = delay; refclock->delay = delay;
refclock->precision = precision; refclock->precision = precision;

View file

@ -461,7 +461,10 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
} }
/* Create a source instance for this NTP source */ /* 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->timer_running = 0;
result->timeout_id = 0; result->timeout_id = 0;

View file

@ -260,7 +260,8 @@ RCL_AddRefclock(RefclockParameters *params)
filter_init(&inst->filter, params->filter_length, params->max_dispersion); 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", DEBUG_LOG(LOGF_Refclock, "refclock %s refid=%s poll=%d dpoll=%d filter=%d",
params->driver_name, UTI_RefidToString(inst->ref_id), params->driver_name, UTI_RefidToString(inst->ref_id),

View file

@ -38,6 +38,8 @@ typedef struct {
int poll; int poll;
int filter_length; int filter_length;
int pps_rate; int pps_rate;
int min_samples;
int max_samples;
uint32_t ref_id; uint32_t ref_id;
uint32_t lock_ref_id; uint32_t lock_ref_id;
double offset; double offset;

View file

@ -207,14 +207,19 @@ void SRC_Finalise(void)
/* Function to create a new instance. This would be called by one of /* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */ 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; SRC_Instance result;
assert(initialised); 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 = 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) { if (n_sources == max_n_sources) {
/* Reallocate memory */ /* Reallocate memory */

View file

@ -65,7 +65,7 @@ typedef enum {
/* Function to create a new instance. This would be called by one of /* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */ 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. /* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this This may cause the current reference source to be reselected, if this

View file

@ -43,10 +43,6 @@
to store per source */ to store per source */
#define MAX_SAMPLES 64 #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, /* This is the assumed worst case bound on an unknown frequency,
2000ppm, which would be pretty bad */ 2000ppm, which would be pretty bad */
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6) #define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
@ -68,6 +64,10 @@ struct SST_Stats_Record {
uint32_t refid; uint32_t refid;
IPAddr *ip_addr; 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 /* Number of samples currently stored. The samples are stored in circular
buffer. */ buffer. */
int n_samples; int n_samples;
@ -163,8 +163,6 @@ SST_Initialise(void)
logfileid = CNF_GetLogStatistics() ? LOG_FileOpen("statistics", 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") " Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr")
: -1; : -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 */ /* This function creates a new instance of the statistics handler */
SST_Stats 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; SST_Stats inst;
inst = MallocNew(struct SST_Stats_Record); inst = MallocNew(struct SST_Stats_Record);
inst->min_samples = min_samples;
inst->max_samples = max_samples;
SST_SetRefid(inst, refid, addr); SST_SetRefid(inst, refid, addr);
SST_ResetInstance(inst); SST_ResetInstance(inst);
@ -262,7 +263,7 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
/* Make room for the new sample */ /* Make room for the new sample */
if (inst->n_samples > 0 && 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); prune_register(inst, 1);
} }
@ -447,7 +448,7 @@ SST_DoNewRegression(SST_Stats inst)
inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples, inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples,
offsets + inst->runs_samples, weights, offsets + inst->runs_samples, weights,
inst->n_samples, inst->runs_samples, inst->n_samples, inst->runs_samples,
min_samples, inst->min_samples,
&est_intercept, &est_slope, &est_var, &est_intercept, &est_slope, &est_var,
&est_intercept_sd, &est_slope_sd, &est_intercept_sd, &est_slope_sd,
&best_start, &nruns, &degrees_of_freedom); &best_start, &nruns, &degrees_of_freedom);

View file

@ -38,7 +38,7 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void); extern void SST_Finalise(void);
/* This function creates a new instance of the statistics handler */ /* 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. */ /* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst); extern void SST_DeleteInstance(SST_Stats inst);

View file

@ -40,6 +40,8 @@ typedef struct {
int poll_target; int poll_target;
int version; int version;
int max_sources; int max_sources;
int min_samples;
int max_samples;
uint32_t authkey; uint32_t authkey;
double max_delay; double max_delay;
double max_delay_ratio; double max_delay_ratio;
@ -57,6 +59,8 @@ typedef struct {
#define SRC_DEFAULT_MINSTRATUM 0 #define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6 #define SRC_DEFAULT_POLLTARGET 6
#define SRC_DEFAULT_MAXSOURCES 4 #define SRC_DEFAULT_MAXSOURCES 4
#define SRC_DEFAULT_MINSAMPLES (-1)
#define SRC_DEFAULT_MAXSAMPLES (-1)
#define INACTIVE_AUTHKEY 0 #define INACTIVE_AUTHKEY 0
#endif /* GOT_SRCPARAMS_H */ #endif /* GOT_SRCPARAMS_H */