From 6d2fb9f782f13258ccede2dd091a2bbec498fdfd Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Thu, 13 Jun 2013 16:23:32 +0200 Subject: [PATCH] Add minsamples and maxsamples directives Allow configuration of the maximum and minimum number of samples per source. --- chrony.texi.in | 28 ++++++++++++++++++++++++++++ conf.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ conf.h | 3 +++ regress.c | 7 ++++++- regress.h | 3 +++ sourcestats.c | 10 +++++++++- 6 files changed, 97 insertions(+), 2 deletions(-) diff --git a/chrony.texi.in b/chrony.texi.in index 108a263..5f9120d 100644 --- a/chrony.texi.in +++ b/chrony.texi.in @@ -1195,7 +1195,9 @@ directives can occur in any order in the file. * maxchange directive:: Set maximum allowed offset * manual directive:: Allow manual entry using chronyc's settime cmd. * maxclockerror directive:: Set maximum frequency error of local clock +* maxsamples directive:: Set maximum number of samples per source * maxupdateskew directive:: Stop bad estimates upsetting machine clock +* minsamples directive:: Set minimum number of samples per source * noclientlog directive:: Prevent chronyd from gathering data about clients * clientloglimit directive:: Set client log memory limit * peer directive:: Specify an NTP peer @@ -2374,6 +2376,19 @@ Typical values for might be 10 for a low quality clock to 0.1 for a high quality clock using a temperature compensated crystal oscillator. @c }}} +@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 syntax is + +@example +maxsamples +@end example +@c }}} @c {{{ maxupdateskew @node maxupdateskew directive @subsection maxupdateskew @@ -2408,6 +2423,19 @@ highly-reliable master estimate and a new estimate is generated which has large error bounds, the existing master estimate will dominate in the new master estimate. @c }}} +@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 syntax is + +@example +minsamples +@end example +@c }}} @c {{{ noclientlog @node noclientlog directive @subsection noclientlog diff --git a/conf.c b/conf.c index 76db3e6..72af3dd 100644 --- a/conf.c +++ b/conf.c @@ -92,7 +92,9 @@ static void parse_makestep(char *); static void parse_manual(char *); static void parse_maxchange(char *); static void parse_maxclockerror(char *); +static void parse_maxsamples(char *line); static void parse_maxupdateskew(char *); +static void parse_minsamples(char *line); static void parse_noclientlog(char *); static void parse_peer(char *); static void parse_pidfile(char *); @@ -173,6 +175,10 @@ static int max_offset_delay = -1; static int max_offset_ignore; static double max_offset; +/* Maximum and minimum number of samples per source */ +static int max_samples = 0; /* no limit */ +static int min_samples = 0; + /* Flag set if we should log to syslog when a time adjustment exceeding the threshold is initiated */ static int do_log_change = 0; @@ -428,8 +434,12 @@ CNF_ReadFile(const char *filename) parse_maxchange(p); } else if (!strcasecmp(command, "maxclockerror")) { parse_maxclockerror(p); + } else if (!strcasecmp(command, "maxsamples")) { + parse_maxsamples(p); } else if (!strcasecmp(command, "maxupdateskew")) { parse_maxupdateskew(p); + } else if (!strcasecmp(command, "minsamples")) { + parse_minsamples(p); } else if (!strcasecmp(command, "noclientlog")) { parse_noclientlog(p); } else if (!strcasecmp(command, "peer")) { @@ -828,6 +838,28 @@ parse_logdir(char *line) /* ================================================== */ +static void +parse_maxsamples(char *line) +{ + check_number_of_args(line, 1); + if (sscanf(line, "%d", &max_samples) != 1) { + command_parse_error(); + } +} + +/* ================================================== */ + +static void +parse_minsamples(char *line) +{ + check_number_of_args(line, 1); + if (sscanf(line, "%d", &min_samples) != 1) { + command_parse_error(); + } +} + +/* ================================================== */ + static void parse_dumpdir(char *line) { @@ -1883,3 +1915,19 @@ CNF_GetUser(void) { return user; } + +/* ================================================== */ + +int +CNF_GetMaxSamples(void) +{ + return max_samples; +} + +/* ================================================== */ + +int +CNF_GetMinSamples(void) +{ + return min_samples; +} diff --git a/conf.h b/conf.h index 2d986e6..d03406b 100644 --- a/conf.h +++ b/conf.h @@ -96,4 +96,7 @@ extern void CNF_GetTempComp(char **file, double *interval, double *T0, double *k extern char *CNF_GetUser(void); +extern int CNF_GetMaxSamples(void); +extern int CNF_GetMinSamples(void); + #endif /* GOT_CONF_H */ diff --git a/regress.c b/regress.c index a0196c1..60e589a 100644 --- a/regress.c +++ b/regress.c @@ -226,6 +226,9 @@ RGR_FindBestRegression int m, /* number of extra samples in x and y arrays (negative index) which can be used to extend runs test */ + int min_samples, /* minimum number of samples to be kept after + changing the starting index to pass the runs + test */ /* And now the results */ @@ -297,7 +300,9 @@ RGR_FindBestRegression /* Count number of runs */ nruns = n_runs_from_residuals(resid, n - resid_start); - if (nruns > critical_runs[n - resid_start] || n - start <= MIN_SAMPLES_FOR_REGRESS) { + if (nruns > critical_runs[n - resid_start] || + n - start <= MIN_SAMPLES_FOR_REGRESS || + n - start <= min_samples) { if (start != resid_start) { /* Ignore extra samples in returned nruns */ nruns = n_runs_from_residuals(resid - resid_start + start, n - start); diff --git a/regress.h b/regress.h index 4c11ca5..b8d0d50 100644 --- a/regress.h +++ b/regress.h @@ -80,6 +80,9 @@ RGR_FindBestRegression int m, /* number of extra samples in x and y arrays (negative index) which can be used to extend runs test */ + int min_samples, /* minimum number of samples to be kept after + changing the starting index to pass the runs + test */ /* And now the results */ diff --git a/sourcestats.c b/sourcestats.c index fa25ab6..616b326 100644 --- a/sourcestats.c +++ b/sourcestats.c @@ -43,6 +43,10 @@ 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) @@ -160,6 +164,8 @@ 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(); } /* ================================================== */ @@ -239,7 +245,8 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time, int n, m; /* Make room for the new sample */ - if (inst->n_samples == MAX_SAMPLES) { + if (inst->n_samples > 0 && + (inst->n_samples == MAX_SAMPLES || inst->n_samples == max_samples)) { prune_register(inst, 1); } @@ -428,6 +435,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, &est_intercept, &est_slope, &est_var, &est_intercept_sd, &est_slope_sd, &best_start, &nruns, °rees_of_freedom);