]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Documentation and code cleanup from Dave Mills. No more NTP_MAXASSOC.
authorHarlan Stenn <stenn@ntp.org>
Wed, 6 Oct 2010 04:17:06 +0000 (00:17 -0400)
committerHarlan Stenn <stenn@ntp.org>
Wed, 6 Oct 2010 04:17:06 +0000 (00:17 -0400)
bk: 4cabf842OHYqolr77TI6u6pWKWBh7g

ChangeLog
html/cluster.html
include/ntp.h
ntpd/ntp_proto.c

index d140898eef6e669e4e8e060c608b730177024324..9cefcdb878f5ca068a3103ada410ce03d8d38eb9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+* Documentation and code cleanup from Dave Mills. No more NTP_MAXASSOC.
 (4.2.7p60) 2010/10/04 Released by Harlan Stenn <stenn@ntp.org>
 * Documentation updates from Dave Mills.
 (4.2.7p59) 2010/10/02 Released by Harlan Stenn <stenn@ntp.org>
index d96f44a67a32fa41b6e776f7f3147f1019c03801..123860442621f574ac88791c2a43d53dd1db0161 100644 (file)
@@ -4,13 +4,12 @@
 <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> &gt; <font face="symbol">j</font><sub><em>min</em></sub><em>, </em>the algorithm prunes candidate 1 and continues.&#13; 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> &le;  <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> &gt; <font face="symbol">j</font><sub><em>min</em></sub>, select jitter dominates  total jitter,<em> so </em>the algorithm prunes candidate 1.&#13; 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> &lt;  <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>
index 9ecee5d4b78287e5a100601a8736164a431342a7..d37b56057732fa3e931856bbcb7ec78495cad363 100644 (file)
@@ -126,7 +126,6 @@ typedef char s_char;
  */
 #define        NTP_MINCLOCK    3       /* min survivors */
 #define        NTP_MAXCLOCK    10      /* max candidates */
-#define        NTP_MAXASSOC    50      /* max associations */
 #define MINDISPERSE    .001    /* min distance */
 #define MAXDISTANCE    1.5     /* max root distance (select threshold) */
 #define CLOCK_SGATE    3.      /* popcorn spike gate */
index b261c8b34be35a724bb00b9e3dd15826bbc2cf96..97b4109f538e9c9ddabee0147be7a8ec57ba0b41 100644 (file)
@@ -2270,7 +2270,6 @@ clock_select(void)
        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 */
@@ -2281,14 +2280,16 @@ clock_select(void)
        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;
 
        /*
@@ -2303,19 +2304,23 @@ clock_select(void)
        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
@@ -2384,33 +2389,23 @@ clock_select(void)
 
                /*
                 * 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;
@@ -2428,6 +2423,7 @@ clock_select(void)
                           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
@@ -2453,21 +2449,17 @@ clock_select(void)
        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--) {
@@ -2475,22 +2467,8 @@ clock_select(void)
                        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
@@ -2502,11 +2480,16 @@ clock_select(void)
 
        /*
         * 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++) {
@@ -2537,12 +2520,6 @@ clock_select(void)
                 */
                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;
@@ -2625,7 +2602,7 @@ clock_select(void)
                        }
                }
                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 &