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:
parent
18a66a2ba8
commit
52272f4dc5
7 changed files with 91 additions and 8 deletions
|
@ -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
|
||||
|
|
4
client.c
4
client.c
|
@ -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");
|
||||
|
|
3
cmdmon.c
3
cmdmon.c
|
@ -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
23
conf.c
|
@ -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
1
conf.h
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
30
sources.c
30
sources.c
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue