[ntp:questions] Configuring two PPS sources is awkward

linux at horizon.com linux at horizon.com
Thu Oct 26 15:19:24 UTC 2006


I've been using a GPS clock with the TSIP PARSE and ATOM (PPS) drivers
for a while.

Then I got a chance at a surplus Acutime 2000, which can use the Palisade
driver, so I hooked it up as well.  Just for good measure, I connected its
PPS output, even though the Palisade driver supports PPS-like resolution
via the serial time code.

(It can take a PPS-like signal as input, timestamps it in hardware,
and sends back the event time.)

So I have three sub-microsecond time sources coming in, as well as a
rather noisy serial time code:

     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
o127.127.22.1    .PPS.            0 l    3    4  377    0.000    0.001   0.004
+127.127.22.0    .PPS.            0 l    2    4  377    0.000    0.003   0.004
-127.127.8.1     .GPS.            0 l   11   16  377    0.000   -1.796   6.985
+127.127.29.0    .PALI.           0 l   16   16  377    0.000    0.002   0.004

The last digits identify corresponding clocks and PPS sources.  I'm just
now collecting statistics to fudge out the microsecond-level systematic
offsets.  I might also configure the Acutime 2000's PPS output to occur
500 ms off to avoid interrupt pile-up on the second.

But I notice in ntp_proto.c:clock_select() (ntpd 4.2.2 and 4.2.3p59) that:

- If there are multiple prefer or pps peers, the order in the peer
  list matters.  This order comes from scanning the peer_hash[] table,
  which is a series of lists that peers are prepended to as they are added.
- If I have multiple prefer peers, the last one that survives the
  intersection algorithm wil be sys_prefer.
- The ATOM driver will not generate outout unless sys_prefer is available.
  Thus, sys_pps is only set if sys_prefer is.
- If I have multiple REFCLOCK_ATOM_PPS peers, the last one gets picked
  as sys_pps.
- If sys_pps (and sys_prefer) is set, then it is chosen as the system
  peer and its offset is used as sys_offset, period.

In particular, if there's a sys_prefer (and possibly a sys_pps too),
then clock_combine() is never called, while I'd think that combining the
multiple clocks would offer some benefit.

The only problem is that doing that in the obvious way would expose
a problem in the way the prefer flag does double duty.  If I mark the
noisy serial time code (127.127.8.1) as prefer, then it is guaranteed
to survive clustering and pollute the combined average.

The current lack of combining in this case reduces the effect of
the clustering pass to an opportunity to cast out the PPS source.

If I don't mark it as prefer (only the Palisade driver), then a dropout
on the Palisade receiver will kill both PPS sources.

I've worked around the issue by marking .29.0 and .22.1 as prefer, so
after startup, the PARSE clock's PPS can "sync to itself" and free-run
without an external time code as long as is stays within reasonable
bounds, but .8.1 is not marked as prefer, so it can't start up without
the Palisade.

Has there been any thought of revising this?


A couple other things I came across while reviewing the code:

1) Despite the driver22.html docs which say that flag4 is "not used by
   this driver", flag4 does have a useful effect (enabling logging of
   each PPS) as described in refclock_atom.c.

2) I have to say, the variable name "typesystem" seems completely
   unrelated to its actual function in the code.

3) Could I suggest a small work-saving patch to ntp_proto.c?
   (Patch placed in the public domain, copyright abandoned, have fun.)

--- a/ntpd/ntp_proto.c
+++ b/ntpd/ntp_proto.c
@@ -2080,7 +2080,7 @@
 	 * discard a TRUE or PREFER  peer, who of course has the
 	 * immunity idol.
 	 */
-	while (1) {
+	while (nlist > sys_minclock) {
 		d = 1e9;
 		e = -1e9;
 		f = g = 0;
@@ -2102,8 +2102,7 @@
 			}
 		}
 		f = max(f, LOGTOD(sys_precision));
-		if (nlist <= sys_minclock || f <= d ||
-		    peer_list[k]->flags & (FLAG_TRUE | FLAG_PREFER))
+		if (f <= d || peer_list[k]->flags & (FLAG_TRUE | FLAG_PREFER))
 			break;
 #ifdef DEBUG
 		if (debug > 2)





More information about the questions mailing list