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 * broadcast directive:: Make chronyd act as an NTP broadcast server
* cmdallow directive:: Give control access to chronyc on other computers * cmdallow directive:: Give control access to chronyc on other computers
* cmddeny directive:: Deny 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 * commandkey directive:: Set runtime command key
* corrtimeratio directive:: Set correction time ratio * corrtimeratio directive:: Set correction time ratio
* cmdport directive:: Set port to use for runtime commanding * 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 There is also a @code{cmddeny all} directive with similar behaviour to the
@code{cmdallow all} directive. @code{cmdallow all} directive.
@c }}} @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 @c {{{ commandkey
@node commandkey directive @node commandkey directive
@subsection commandkey @subsection commandkey
@ -4080,12 +4105,15 @@ reference clock.
@item S @item S
This column indicates the state of the sources. @code{*} indicates the This column indicates the state of the sources. @code{*} indicates the
source to which @code{chronyd} is current synchronised. @code{+} indicates source to which @code{chronyd} is currently synchronised. @code{+}
other acceptable sources. @code{?} indicates sources to which indicates acceptable sources which are combined with the selected
connectivity has been lost. @code{x} indicates a clock which @code{chronyd} 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 thinks is is a falseticker (i.e. its time is inconsistent with a
majority of other sources). @code{~} indicates a source whose time 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. shown at start-up, until at least 3 samples have been gathered from it.
@item Name/IP address @item Name/IP address

View file

@ -1693,8 +1693,8 @@ process_cmd_sources(char *line)
if (verbose) { if (verbose) {
printf("\n"); printf("\n");
printf(" .-- Source mode '^' = server, '=' = peer, '#' = local clock.\n"); printf(" .-- Source mode '^' = server, '=' = peer, '#' = local clock.\n");
printf(" / .- Source state '*' = current synced, '+' = OK for sync, '?' = unreachable,\n"); printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
printf("| / 'x' = time may be in error, '~' = time is too variable.\n"); printf("| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
printf("|| .- xxxx [ yyyy ] +/- zzzz\n"); printf("|| .- xxxx [ yyyy ] +/- zzzz\n");
printf("|| / xxxx = adjusted offset,\n"); printf("|| / xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) -. | yyyy = measured 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: case RPT_CANDIDATE:
tx_message->data.source_data.state = htons(RPY_SD_ST_CANDIDATE); tx_message->data.source_data.state = htons(RPY_SD_ST_CANDIDATE);
break; break;
case RPT_OUTLYER:
tx_message->data.source_data.state = htons(RPY_SD_ST_OUTLYER);
break;
} }
switch (report.mode) { switch (report.mode) {
case RPT_NTP_CLIENT: 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_cmdallow(char *);
static void parse_cmddeny(char *); static void parse_cmddeny(char *);
static void parse_cmdport(char *); static void parse_cmdport(char *);
static void parse_combinelimit(char *);
static void parse_commandkey(char *); static void parse_commandkey(char *);
static void parse_corrtimeratio(char *); static void parse_corrtimeratio(char *);
static void parse_deny(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 reselect_distance = 1e-4;
static double stratum_weight = 1.0; static double stratum_weight = 1.0;
static double combine_limit = 3.0;
static int cmd_port = DEFAULT_CANDM_PORT; static int cmd_port = DEFAULT_CANDM_PORT;
@ -374,6 +376,8 @@ CNF_ReadFile(const char *filename)
parse_cmddeny(p); parse_cmddeny(p);
} else if (!strcasecmp(command, "cmdport")) { } else if (!strcasecmp(command, "cmdport")) {
parse_cmdport(p); parse_cmdport(p);
} else if (!strcasecmp(command, "combinelimit")) {
parse_combinelimit(p);
} else if (!strcasecmp(command, "commandkey")) { } else if (!strcasecmp(command, "commandkey")) {
parse_commandkey(p); parse_commandkey(p);
} else if (!strcasecmp(command, "corrtimeratio")) { } 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 static void
parse_driftfile(char *line) parse_driftfile(char *line)
{ {
@ -1630,6 +1645,14 @@ CNF_GetStratumWeight(void)
/* ================================================== */ /* ================================================== */
double
CNF_GetCombineLimit(void)
{
return combine_limit;
}
/* ================================================== */
int int
CNF_GetManualEnabled(void) 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_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void); extern double CNF_GetStratumWeight(void);
extern double CNF_GetCombineLimit(void);
extern int CNF_AllowLocalReference(int *stratum); extern int CNF_AllowLocalReference(int *stratum);

View file

@ -37,7 +37,7 @@ typedef struct {
int stratum; int stratum;
int poll; int poll;
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode; 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; enum {RPT_NORMAL, RPT_PREFER, RPT_NOSELECT} sel_option;
int reachability; int reachability;

View file

@ -96,6 +96,9 @@ struct SRC_Instance_Record {
/* Reachability register */ /* Reachability register */
int reachability; int reachability;
/* Updates left before resetting outlyer status */
int outlyer;
/* Flag indicating the status of the source */ /* Flag indicating the status of the source */
SRC_Status status; 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 */ /* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0 #define SCORE_LIMIT 10.0
/* Number of updates needed to reset the outlyer status */
#define OUTLYER_PENALTY 32
static double reselect_distance; static double reselect_distance;
static double stratum_weight; static double stratum_weight;
static double combine_limit;
/* ================================================== */ /* ================================================== */
/* Forward prototype */ /* Forward prototype */
@ -162,6 +169,7 @@ void SRC_Initialise(void) {
selected_source_index = INVALID_SOURCE; selected_source_index = INVALID_SOURCE;
reselect_distance = CNF_GetReselectDistance(); reselect_distance = CNF_GetReselectDistance();
stratum_weight = CNF_GetStratumWeight(); stratum_weight = CNF_GetStratumWeight();
combine_limit = CNF_GetCombineLimit();
initialised = 1; initialised = 1;
LCL_AddParameterChangeHandler(slew_sources, NULL); 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->ip_addr = addr;
result->selectable = 0; result->selectable = 0;
result->reachability = 0; result->reachability = 0;
result->outlyer = 0;
result->status = SRC_BAD_STATS; result->status = SRC_BAD_STATS;
result->type = type; result->type = type;
result->sel_score = 1.0; 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_frequency, &src_skew,
&src_root_delay, &src_root_dispersion); &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); UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time);
src_offset += elapsed * src_frequency; src_offset += elapsed * src_frequency;
weight = 1.0 / sources[index]->sel_info.root_distance; 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 */ /* Reset score for non-selectable sources */
if (sources[i]->status != SRC_SELECTABLE) { if (sources[i]->status != SRC_SELECTABLE) {
sources[i]->sel_score = 1.0; sources[i]->sel_score = 1.0;
sources[i]->outlyer = OUTLYER_PENALTY;
continue; continue;
} }
@ -880,6 +907,7 @@ SRC_SelectSource(uint32_t match_refid)
/* New source has been selected, reset all scores */ /* New source has been selected, reset all scores */
for (i=0; i < n_sources; i++) { for (i=0; i < n_sources; i++) {
sources[i]->sel_score = 1.0; 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; report->state = RPT_FALSETICKER;
break; break;
case SRC_SELECTABLE: case SRC_SELECTABLE:
report->state = RPT_CANDIDATE; report->state = src->outlyer ? RPT_OUTLYER : RPT_CANDIDATE;
break; break;
default: default:
assert(0); assert(0);