Limit sources included in combining

Combine only sources whose distance is shorter than distance of the
selected source multiplied by the value of combinelimit and their
estimated frequencies are close to the frequency of the selected source.
Add outlyer status for sources which are selectable, but not included in
the combining. The status is displayed as '-' in the chronyc sources
output.
This commit is contained in:
Miroslav Lichvar 2013-06-10 18:37:08 +02:00
parent 18a66a2ba8
commit 52272f4dc5
7 changed files with 91 additions and 8 deletions

View file

@ -1169,6 +1169,7 @@ directives can occur in any order in the file.
* broadcast directive:: Make chronyd act as an NTP broadcast server
* cmdallow directive:: Give control access to chronyc on other computers
* cmddeny directive:: Deny control access to chronyc on other computers
* combinelimit directive:: Limit sources included in combining algorithm
* commandkey directive:: Set runtime command key
* corrtimeratio directive:: Set correction time ratio
* cmdport directive:: Set port to use for runtime commanding
@ -1447,6 +1448,30 @@ The syntax is identical.
There is also a @code{cmddeny all} directive with similar behaviour to the
@code{cmdallow all} directive.
@c }}}
@c {{{ combinelimit
@node combinelimit directive
@subsection combinelimit
When @code{chronyd} has multiple sources available for synchronization, it has
to select one source as the synchronization source. The measured offsets and
frequencies of the system clock relative to the other sources, however, can be
combined with the selected source to improve the accuracy of the system clock.
The @code{combinelimit} directive limits which sources are included in the
combining algorithm. Their synchronization distance has to be shorter than the
distance of the selected source multiplied by the value of the limit. Also,
their measured frequencies have to be close to the frequency of the selected
source.
By default, the limit is 3. Setting the limit to 0 effectively disables the
source combining algorithm and only the selected source will be used to
control the system clock.
The syntax is
@example
combinelimit <limit>
@end example
@c }}}
@c {{{ commandkey
@node commandkey directive
@subsection commandkey
@ -4080,12 +4105,15 @@ reference clock.
@item S
This column indicates the state of the sources. @code{*} indicates the
source to which @code{chronyd} is current synchronised. @code{+} indicates
other acceptable sources. @code{?} indicates sources to which
connectivity has been lost. @code{x} indicates a clock which @code{chronyd}
source to which @code{chronyd} is currently synchronised. @code{+}
indicates acceptable sources which are combined with the selected
source. @code{-} indicates acceptable sources which are excluded by
the combining algorithm. @code{?} indicates sources to which
connectivity has been lost or whose packets don't pass all tests.
@code{x} indicates a clock which @code{chronyd}
thinks is is a falseticker (i.e. its time is inconsistent with a
majority of other sources). @code{~} indicates a source whose time
appears to have too much variability. The @code{~} condition is also
appears to have too much variability. The @code{?} condition is also
shown at start-up, until at least 3 samples have been gathered from it.
@item Name/IP address

View file

@ -1693,8 +1693,8 @@ process_cmd_sources(char *line)
if (verbose) {
printf("\n");
printf(" .-- Source mode '^' = server, '=' = peer, '#' = local clock.\n");
printf(" / .- Source state '*' = current synced, '+' = OK for sync, '?' = unreachable,\n");
printf("| / 'x' = time may be in error, '~' = time is too variable.\n");
printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
printf("| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
printf("|| .- xxxx [ yyyy ] +/- zzzz\n");
printf("|| / xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) -. | yyyy = measured offset,\n");

View file

@ -1050,6 +1050,9 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
case RPT_CANDIDATE:
tx_message->data.source_data.state = htons(RPY_SD_ST_CANDIDATE);
break;
case RPT_OUTLYER:
tx_message->data.source_data.state = htons(RPY_SD_ST_OUTLYER);
break;
}
switch (report.mode) {
case RPT_NTP_CLIENT:

23
conf.c
View file

@ -66,6 +66,7 @@ static void parse_clientloglimit(char *);
static void parse_cmdallow(char *);
static void parse_cmddeny(char *);
static void parse_cmdport(char *);
static void parse_combinelimit(char *);
static void parse_commandkey(char *);
static void parse_corrtimeratio(char *);
static void parse_deny(char *);
@ -126,6 +127,7 @@ static double max_clock_error = 1.0; /* in ppm */
static double reselect_distance = 1e-4;
static double stratum_weight = 1.0;
static double combine_limit = 3.0;
static int cmd_port = DEFAULT_CANDM_PORT;
@ -374,6 +376,8 @@ CNF_ReadFile(const char *filename)
parse_cmddeny(p);
} else if (!strcasecmp(command, "cmdport")) {
parse_cmdport(p);
} else if (!strcasecmp(command, "combinelimit")) {
parse_combinelimit(p);
} else if (!strcasecmp(command, "commandkey")) {
parse_commandkey(p);
} else if (!strcasecmp(command, "corrtimeratio")) {
@ -757,6 +761,17 @@ parse_stratumweight(char *line)
/* ================================================== */
static void
parse_combinelimit(char *line)
{
check_number_of_args(line, 1);
if (sscanf(line, "%lf", &combine_limit) != 1) {
command_parse_error();
}
}
/* ================================================== */
static void
parse_driftfile(char *line)
{
@ -1630,6 +1645,14 @@ CNF_GetStratumWeight(void)
/* ================================================== */
double
CNF_GetCombineLimit(void)
{
return combine_limit;
}
/* ================================================== */
int
CNF_GetManualEnabled(void)
{

1
conf.h
View file

@ -83,6 +83,7 @@ extern double CNF_GetCorrectionTimeRatio(void);
extern double CNF_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void);
extern double CNF_GetCombineLimit(void);
extern int CNF_AllowLocalReference(int *stratum);

View file

@ -37,7 +37,7 @@ typedef struct {
int stratum;
int poll;
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE} state;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE, RPT_OUTLYER} state;
enum {RPT_NORMAL, RPT_PREFER, RPT_NOSELECT} sel_option;
int reachability;

View file

@ -96,6 +96,9 @@ struct SRC_Instance_Record {
/* Reachability register */
int reachability;
/* Updates left before resetting outlyer status */
int outlyer;
/* Flag indicating the status of the source */
SRC_Status status;
@ -138,8 +141,12 @@ static int selected_source_index; /* Which source index is currently
/* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0
/* Number of updates needed to reset the outlyer status */
#define OUTLYER_PENALTY 32
static double reselect_distance;
static double stratum_weight;
static double combine_limit;
/* ================================================== */
/* Forward prototype */
@ -162,6 +169,7 @@ void SRC_Initialise(void) {
selected_source_index = INVALID_SOURCE;
reselect_distance = CNF_GetReselectDistance();
stratum_weight = CNF_GetStratumWeight();
combine_limit = CNF_GetCombineLimit();
initialised = 1;
LCL_AddParameterChangeHandler(slew_sources, NULL);
@ -211,6 +219,7 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOpt
result->ip_addr = addr;
result->selectable = 0;
result->reachability = 0;
result->outlyer = 0;
result->status = SRC_BAD_STATS;
result->type = type;
result->sel_score = 1.0;
@ -431,6 +440,23 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
&src_frequency, &src_skew,
&src_root_delay, &src_root_dispersion);
/* Don't include this source if its distance is longer than the distance of
the selected source multiplied by the limit, their estimated frequencies
are not close, or it was recently marked as outlyer */
if (index != selected_source_index &&
(sources[index]->sel_info.root_distance > combine_limit *
(reselect_distance + sources[selected_source_index]->sel_info.root_distance) ||
fabs(*frequency - src_frequency) >
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
sources[index]->outlyer = OUTLYER_PENALTY;
}
if (sources[index]->outlyer) {
sources[index]->outlyer--;
continue;
}
UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time);
src_offset += elapsed * src_frequency;
weight = 1.0 / sources[index]->sel_info.root_distance;
@ -817,6 +843,7 @@ SRC_SelectSource(uint32_t match_refid)
/* Reset score for non-selectable sources */
if (sources[i]->status != SRC_SELECTABLE) {
sources[i]->sel_score = 1.0;
sources[i]->outlyer = OUTLYER_PENALTY;
continue;
}
@ -880,6 +907,7 @@ SRC_SelectSource(uint32_t match_refid)
/* New source has been selected, reset all scores */
for (i=0; i < n_sources; i++) {
sources[i]->sel_score = 1.0;
sources[i]->outlyer = 0;
}
}
@ -1156,7 +1184,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
report->state = RPT_FALSETICKER;
break;
case SRC_SELECTABLE:
report->state = RPT_CANDIDATE;
report->state = src->outlyer ? RPT_OUTLYER : RPT_CANDIDATE;
break;
default:
assert(0);