[rtems commit] pps: Simplify the nsec calculation in pps_event()

Sebastian Huber sebh at rtems.org
Thu Mar 9 06:54:14 UTC 2023


Module:    rtems
Branch:    master
Commit:    d9f5345df6e6c37d6fbe2aafa85f40e6bfb8cd0b
Changeset: http://git.rtems.org/rtems/commit/?id=d9f5345df6e6c37d6fbe2aafa85f40e6bfb8cd0b

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Feb 27 14:49:09 2023 -0700

pps: Simplify the nsec calculation in pps_event()

Let A be the current calculation of the frequency accumulator (pps_fcount)
update in pps_event()

  scale = (uint64_t)1 << 63;
  scale /= captc->tc_frequency;
  scale *= 2;
  bt.sec = 0;
  bt.frac = 0;
  bintime_addx(&bt, scale * tcount);
  bintime2timespec(&bt, &ts);
  hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);

and hardpps(..., delta_nsec):

  u_nsec = delta_nsec;
  if (u_nsec > (NANOSECOND >> 1))
          u_nsec -= NANOSECOND;
  else if (u_nsec < -(NANOSECOND >> 1))
          u_nsec += NANOSECOND;
  pps_fcount += u_nsec;

This change introduces a new calculation which is slightly simpler and more
straight forward.  Name it B.

Consider the following sample values with a tcount of 2000000100 and a
tc_frequency of 2000000000 (2GHz).

For A, the scale is 9223372036.  Then scale * tcount is 18446744994337203600
which is larger than UINT64_MAX (= 18446744073709551615).  The result is
920627651984 == 18446744994337203600 % UINT64_MAX.  Since all operands are
unsigned the result is well defined through modulo arithmetic.  The result of
bintime2timespec(&bt, &ts) is 49.  This is equal to the correct result
1000000049 % NANOSECOND.

In hardpps(), both conditional statements are not executed and pps_fcount is
incremented by 49.

For the new calculation B, we have 1000000000 * tcount is 2000000100000000000
which is less than UINT64_MAX. This yields after the division with tc_frequency
the correct result of 1000000050 for delta_nsec.

In hardpps(), the first conditional statement is executed and pps_fcount is
incremented by 50.

This shows that both methods yield roughly the same results.  However, method B
is easier to understand and requires fewer conditional statements.

Reviewed by: imp
Pull Request: https://github.com/freebsd/freebsd-src/pull/604

---

 cpukit/score/src/kern_ntptime.c | 12 +++---------
 cpukit/score/src/kern_tc.c      | 16 ++++++----------
 2 files changed, 9 insertions(+), 19 deletions(-)

diff --git a/cpukit/score/src/kern_ntptime.c b/cpukit/score/src/kern_ntptime.c
index 44d56cf59e..c6f70079b3 100644
--- a/cpukit/score/src/kern_ntptime.c
+++ b/cpukit/score/src/kern_ntptime.c
@@ -900,16 +900,10 @@ hardpps(struct timespec *tsp, long delta_nsec)
 	pps_tf[0].tv_nsec = u_nsec;
 
 	/*
-	 * Compute the difference between the current and previous
-	 * counter values. If the difference exceeds 0.5 s, assume it
-	 * has wrapped around, so correct 1.0 s.
+	 * Update the frequency accumulator using the difference between the
+	 * current and previous PPS event measured directly by the timecounter.
 	 */
-	u_nsec = delta_nsec;
-	if (u_nsec > (NANOSECOND >> 1))
-		u_nsec -= NANOSECOND;
-	else if (u_nsec < -(NANOSECOND >> 1))
-		u_nsec += NANOSECOND;
-	pps_fcount += u_nsec;
+	pps_fcount += delta_nsec - NANOSECOND;
 	if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ)
 		goto out;
 	time_status &= ~STA_PPSJITTER;
diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c
index 5e43964bf4..0aa0fdd393 100644
--- a/cpukit/score/src/kern_tc.c
+++ b/cpukit/score/src/kern_tc.c
@@ -2161,7 +2161,7 @@ pps_event(struct pps_state *pps, int event)
 	struct timecounter *captc;
 	uint64_t capth_scale;
 	struct bintime bt;
-	struct timespec ts, *tsp, *osp;
+	struct timespec *tsp, *osp;
 	uint32_t tcount, *pcount;
 	int foff;
 	pps_seq_t *pseq;
@@ -2265,7 +2265,7 @@ pps_event(struct pps_state *pps, int event)
 
 #ifdef PPS_SYNC
 	if (fhard) {
-		uint64_t scale;
+		uint64_t delta_nsec;
 
 		/*
 		 * Feed the NTP PLL/FLL.
@@ -2275,14 +2275,10 @@ pps_event(struct pps_state *pps, int event)
 		tcount = pps->capcount - pps->ppscount[2];
 		pps->ppscount[2] = pps->capcount;
 		tcount &= captc->tc_counter_mask;
-		scale = (uint64_t)1 << 63;
-		scale /= captc->tc_frequency;
-		scale *= 2;
-		bt.sec = 0;
-		bt.frac = 0;
-		bintime_addx(&bt, scale * tcount);
-		bintime2timespec(&bt, &ts);
-		hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
+		delta_nsec = 1000000000;
+		delta_nsec *= tcount;
+		delta_nsec /= captc->tc_frequency;
+		hardpps(tsp, (long)delta_nsec);
 	}
 #endif
 



More information about the vc mailing list