<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<meta name="generator" content="HTML Tidy, see www.w3.org">
<title>Clock Cluster Algorithm</title>
-<link href="scripts/style.css" type="text/css" rel="stylesheet">
-</head>
+<link href="scripts/style.css" type="text/css" rel="stylesheet"></head>
<body>
<em></em>
<h3>Clock Cluster Algorithm</h3>
<p>Last update:
- <!-- #BeginDate format:En2m -->04-Oct-2010 2:42<!-- #EndDate -->
+ <!-- #BeginDate format:En2m -->05-Oct-2010 21:29<!-- #EndDate -->
UTC</p>
<hr>
<p>The clock cluster algorithm processes the truechimers produced by the clock select algorithm to produce the survivors used by the mitigation algorithms to discipline the system clock. It operates in a series of rounds, where at each round the truechimer furthest from the offset centroid is pruned from the population. The rounds are continued until a specified termination condition results. This page discusses the algorithm in detail.</p>
<p><em>d<sub>i</sub></em>(<em>j</em>) = <font face="symbol">q</font>(<em>j</em>) - <font face="symbol"> q</font>(<em>i</em>),</p>
</div>
<p> where<font face="symbol"> q</font>(<em>i</em>) is the peer offset of the <em>i</em>th entry and <font face="symbol">q</font>(<em>j</em>) is the peer offset of the <em>j</em>th entry, both produced by the clock filter algorithm. Then, the select jitter <font face="symbol">j</font><sub>S</sub>(<em>i</em>) of the <em>i</em>th entry is the root distance of the <em>i</em>th entry times the RMS sum of <em>d<sub>i</sub></em>(<em>j</em>)<em> </em>as <em>j</em> ranges from 1 to <em>n</em>. For the purpose of notation in the example to follow, let <font face="symbol">j</font><sub>R</sub>(<em>i</em>) be the peer jitter computed by the clock filter algorithm for the <em>i</em>th entry. In general, the <em>expected error</em> statistic for the <em>i</em>th entry is the RMS sum of these two components, but that is not needed by the clock cluster algorithm.</p>
-<p>The object at each round is to prune the entry with the largest select jitter until the termination condition is met. Note that the select jitter must be recomputed at each round, but the peer jitter does not change. At each round the remaining entries on the list represent the survivors of that round. The list is always pruned to the <em>maxclock threshold</em> with default 10, but can be set by the <tt>maxclock</tt> option of the <tt>tos</tt> command. This threshold is useful to limit the number of survivors when automatic server discovery schemes are in use.</p>
-<p>The termination condition has two parts. First, if the number of candidates is not greater than the <em>sane threshold</em> set by the <tt>minsane</tt> option of the <tt>tos</tt> command, or not greater than the <em>minclock threshold</em> set by the <tt>minclock</tt> option of the <tt>tos</tt> command, the pruning process terminates. The <tt>minsane</tt> default is 1 and the <tt>minclock</tt> default is 3. These thresholds can be changed to fit special conditions, as described on the Mitigation Rules and the prefer Keyword page.</p>
+<p>The object at each round is to prune the entry with the largest select jitter until the termination condition is met. Note that the select jitter must be recomputed at each round, but the peer jitter does not change. At each round the remaining entries on the list represent the survivors of that round. While the number of entries on the list is not limited, the list is always pruned to the <em>maxclock threshold</em>. It has default 10, but can be set by the <tt>maxclock</tt> option of the <a href="miscopt.html#tos"><tt>tos</tt></a> command. This threshold is useful to limit the number of survivors when automatic server discovery schemes are in use.</p>
+<p>The termination condition has two parts. First, if the number of candidates is not greater than the<em> </em><em>minclock threshold</em> set by the <tt>minclock</tt> option of the <a href="miscopt.html#tos"><tt>tos</tt></a> command, the pruning process terminates. The<tt> minclock</tt> default is 3, but can be changed to fit special conditions, as described on the <a href="prefer.html">Mitigation Rules and the prefer Keyword</a> page.</p>
<div align="center"><img src="pic/flt7.gif" alt="gif">
<p>Figure 1. Cluster Algorithm</p>
</div>
-<p>The second termination condition is more intricate. Figure 1 shows a round where a candidates of (a) is pruned to yield the candidates of (b). Let <font face="symbol">j</font><sub><em>max</em></sub> be the maximum select jitter and <font face="symbol">j</font><sub><em>min</em></sub> be the minimum peer jitter over all entries on the list. In (a), candidate 1 has the highest select jitter, so <font face="symbol">j</font><sub><em>max</em></sub> = <font face="symbol"> j</font><sub>S</sub>(1). Candidate 4 has the lowest peer jitter, so <font face="symbol">j</font><sub><em>min</em></sub> = <font face="symbol">j</font><sub>R</sub>(4). Since <font face="symbol">j</font><sub><em>max</em></sub> > <font face="symbol">j</font><sub><em>min</em></sub><em>, </em>the algorithm prunes candidate 1 and continues. In (b), <font face="symbol">j</font><sub><em>max</em></sub> = <font face="symbol">j</font><sub>S</sub>(3) and <font face="symbol">j</font><sub><em>min </em></sub>=<font face="symbol"> j</font><sub>R</sub>(4). Since <font face="symbol">j</font><sub><em>max</em></sub> ≤ <font face="symbol">j</font><sub><em>min</em></sub>, pruning additional candidates will not reduce select jitter. So, the algorithm terminates with candidates 2, 3 and 4 as survivors.</p>
+<p>The second termination condition is more intricate. Figure 1 shows a round where a candidate of (a) is pruned to yield the candidates of (b). Let <font face="symbol">j</font><sub><em>max</em></sub> be the maximum select jitter and <font face="symbol">j</font><sub><em>min</em></sub> be the minimum peer jitter over all entries on the list. In (a), candidate 1 has the highest select jitter, so <font face="symbol">j</font><sub><em>max</em></sub> = <font face="symbol"> j</font><sub>S</sub>(1). Candidate 4 has the lowest peer jitter, so <font face="symbol">j</font><sub><em>min</em></sub> = <font face="symbol">j</font><sub>R</sub>(4). Since <font face="symbol">j</font><sub><em>max</em></sub> > <font face="symbol">j</font><sub><em>min</em></sub>, select jitter dominates total jitter,<em> so </em>the algorithm prunes candidate 1. In (b), <font face="symbol">j</font><sub><em>max</em></sub> = <font face="symbol">j</font><sub>S</sub>(3) and <font face="symbol">j</font><sub><em>min </em></sub>=<font face="symbol"> j</font><sub>R</sub>(4). Since <font face="symbol">j</font><sub><em>max</em></sub> < <font face="symbol">j</font><sub><em>min</em></sub>, pruning additional candidates will not significantly reduce total jitter. So, the algorithm terminates with candidates 2, 3 and 4 as survivors.</p>
<hr>
<script type="text/javascript" language="javascript" src="scripts/footer.txt"></script>
</body>
double d, e, f, g;
double high, low;
double seljitter;
- double synch[NTP_MAXASSOC], error[NTP_MAXASSOC];
double orphdist = 1e10;
struct peer *osys_peer = NULL;
struct peer *sys_prefer = NULL; /* prefer peer */
struct peer *typelocal = NULL;
struct peer *typepps = NULL;
#endif /* REFCLOCK */
-
- static int list_alloc = 0;
static struct endpoint *endpoint = NULL;
static int *indx = NULL;
static struct peer **peers = NULL;
+ static double *synch = NULL;
+ static double *error = NULL;
static u_int endpoint_size = 0;
static u_int indx_size = 0;
static u_int peers_size = 0;
+ static u_int synch_size = 0;
+ static u_int error_size = 0;
size_t octets;
/*
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "DOWN", 4);
#endif /* LOCKCLOCK */
- nlist = peer_count;
- if (nlist > list_alloc) {
- while (list_alloc < nlist) {
- list_alloc += 5;
- endpoint_size += 5 * 3 * sizeof(*endpoint);
- indx_size += 5 * 3 * sizeof(*indx);
- peers_size += 5 * sizeof(*peers);
- }
- octets = endpoint_size + indx_size + peers_size;
- endpoint = erealloc(endpoint, octets);
- indx = (int *)((char *)endpoint + endpoint_size);
- peers = (struct peer **)((char *)indx + indx_size);
- }
+
+ /*
+ * Allocate dynamic space depending on the number of
+ * associations.
+ */
+ endpoint_size = peer_count * 3 * sizeof(struct endpoint);
+ indx_size = peer_count * 3 * sizeof(int);
+ peers_size = peer_count * sizeof(struct peer *);
+ synch_size = peer_count * sizeof(double);
+ error_size = peer_count * sizeof(double);
+ octets = endpoint_size + indx_size + peers_size + synch_size +
+ error_size;
+ endpoint = erealloc(endpoint, octets);
+ indx = (int *)((char *)endpoint + endpoint_size);
+ peers = (struct peer **)((char *)indx + indx_size);
+ synch = (double *)((char *)peers + peers_size);
+ error = (double *)((char *)synch + synch_size);
/*
* Initially, we populate the island with all the rifraff peers
/*
* Insert each interval endpoint on the sorted
- * list.
+ * list. This code relies on the endpointd being at
+ * increasing offsets.
*/
- e = peer->offset; /* Upper end */
+ e = peer->offset; /* upper end */
f = root_distance(peer);
e = e + f;
for (i = nl3 - 1; i >= 0; i--) {
if (e >= endpoint[indx[i]].val)
break;
- indx[i + 3] = indx[i];
- }
- indx[i + 3] = nl3;
- endpoint[nl3].type = 1;
- endpoint[nl3++].val = e;
-
- e = e - f; /* Center point */
- for (; i >= 0; i--) {
- if (e >= endpoint[indx[i]].val)
- break;
-
indx[i + 2] = indx[i];
}
indx[i + 2] = nl3;
- endpoint[nl3].type = 0;
+ endpoint[nl3].type = 1;
endpoint[nl3++].val = e;
- e = e - f; /* Lower end */
+ e = e - f - f; /* lower end */
for (; i >= 0; i--) {
if (e >= endpoint[indx[i]].val)
break;
endpoint[indx[i]].type,
endpoint[indx[i]].val);
#endif
+
/*
* This is the actual algorithm that cleaves the truechimers
* from the falsetickers. The original algorithm was described
low = 1e9;
high = -1e9;
for (allow = 0; 2 * allow < nlist; allow++) {
- int found;
/*
- * Bound the interval (low, high) as the largest
- * interval containing points from presumed truechimers.
+ * Bound the interval (low, high) as the smallest
+ * interval containing points from the most sources.
*/
- found = 0;
n = 0;
for (i = 0; i < nl3; i++) {
low = endpoint[indx[i]].val;
n -= endpoint[indx[i]].type;
if (n >= nlist - allow)
break;
- if (endpoint[indx[i]].type == 0)
- found++;
}
n = 0;
for (j = nl3 - 1; j >= 0; j--) {
n += endpoint[indx[j]].type;
if (n >= nlist - allow)
break;
- if (endpoint[indx[j]].type == 0)
- found++;
}
-#if 0
- /*
- * If the number of candidates found outside the
- * interval is greater than the number of falsetickers,
- * then at least one truechimer is outside the interval,
- * so go around again. This is what makes this algorithm
- * different than Marzullo's.
- */
- if (found > allow)
- continue;
-#endif
-
/*
* If an interval containing truechimers is found, stop.
* If not, increase the number of falsetickers and go
/*
* Clustering algorithm. Construct candidate list in order first
- * by stratum then by root distance, but keep only the best
- * NTP_MAXASSOC of them. Scan the list to find falsetickers, who
- * leave the island immediately. The TRUE peer is always a
- * truechimer. We must leave at least one peer to collect the
- * million bucks.
+ * by stratum then by root distance. Scan the list to find
+ * falsetickers, who leave the island immediately. The TRUE peer
+ * is always a truechimer. We must leave at least one peer
+ * to collect the million bucks.
+ *
+ * We assert the correc time is contained in the interval, but
+ * the best offset estimate for the interval might not be
+ * contained in the interval. For this purpose, a truechimer is
+ * defined as the midpoint of an interval that overlaps the
+ * intersection interval.
*/
j = 0;
for (i = 0; i < nlist; i++) {
*/
d = root_distance(peer) + clock_phi * (peer->nextdate -
current_time);
- if (j >= NTP_MAXASSOC) {
- if (d >= synch[j - 1])
- continue;
- else
- j--;
- }
for (k = j; k > 0; k--) {
if (d >= synch[k - 1])
break;
}
}
f = max(f, LOGTOD(sys_precision));
- if (nlist <= sys_minsane || nlist <= sys_minclock) {
+ if (nlist <= sys_minclock) {
break;
} else if (f <= d || peers[k]->flags &