linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ppc64: xtime <-> gettimeofday can get out of sync
@ 2005-01-10 13:24 Anton Blanchard
  2005-01-13  3:40 ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 2+ messages in thread
From: Anton Blanchard @ 2005-01-10 13:24 UTC (permalink / raw)
  To: akpm; +Cc: paulus, linux-kernel


Ive noticed a problem where xtime and gettimeofday could get out of sync
if interrupts are disabled for too long (eg long kernel code paths or
dropping into the debugger for a while).

We correctly replay lost jiffies but in that loop time_sync_xtime syncs
the intermediate values of xtime up with the current value of
gettimeofday. So xtime jumps by a bunch and from then on it is ahead of
gettimeofday and we never resync the two. I guess this is to avoid xtime
going backwards.

The patch below creates a __do_gettimeofday where you can pass in a tb
value and sync the intermediate values of xtime properly.

Note that the time_sync_xtime check only stops the seconds from going
backwards, the ns component still could couldnt it? Considering this
is hard to get right, should we switch to the time interpolator stuff?
The only problem there is it might be trouble for systemcfg (which
exports stuff to do userspace gettimeofday).

Anton

Signed-off-by: Anton Blanchard <anton@samba.org>

===== arch/ppc64/kernel/time.c 1.44 vs edited =====
--- 1.44/arch/ppc64/kernel/time.c	2005-01-05 13:48:14 +11:00
+++ edited/arch/ppc64/kernel/time.c	2005-01-09 16:37:33 +11:00
@@ -142,16 +142,54 @@
         }
 }
 
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+static inline void __do_gettimeofday(struct timeval *tv, unsigned long tb_val)
+{
+	unsigned long sec, usec, tb_ticks;
+	unsigned long xsec, tb_xsec;
+	struct gettimeofday_vars * temp_varp;
+	unsigned long temp_tb_to_xs, temp_stamp_xsec;
+
+	/*
+	 * These calculations are faster (gets rid of divides)
+	 * if done in units of 1/2^20 rather than microseconds.
+	 * The conversion to microseconds at the end is done
+	 * without a divide (and in fact, without a multiply)
+	 */
+	tb_ticks = tb_val - do_gtod.tb_orig_stamp;
+	temp_varp = do_gtod.varp;
+	temp_tb_to_xs = temp_varp->tb_to_xs;
+	temp_stamp_xsec = temp_varp->stamp_xsec;
+	tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs );
+	xsec = temp_stamp_xsec + tb_xsec;
+	sec = xsec / XSEC_PER_SEC;
+	xsec -= sec * XSEC_PER_SEC;
+	usec = (xsec * USEC_PER_SEC)/XSEC_PER_SEC;
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+	__do_gettimeofday(tv, get_tb());
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
 /* Synchronize xtime with do_gettimeofday */ 
 
-static __inline__ void timer_sync_xtime( unsigned long cur_tb )
+static inline void timer_sync_xtime(unsigned long cur_tb)
 {
 	struct timeval my_tv;
 
-	if ( cur_tb > next_xtime_sync_tb ) {
+	if (cur_tb > next_xtime_sync_tb) {
 		next_xtime_sync_tb = cur_tb + xtime_sync_interval;
-		do_gettimeofday( &my_tv );
-		if ( xtime.tv_sec <= my_tv.tv_sec ) {
+		__do_gettimeofday(&my_tv, cur_tb);
+
+		if (xtime.tv_sec <= my_tv.tv_sec) {
 			xtime.tv_sec = my_tv.tv_sec;
 			xtime.tv_nsec = my_tv.tv_usec * 1000;
 		}
@@ -274,7 +312,7 @@
 			write_seqlock(&xtime_lock);
 			tb_last_stamp = lpaca->next_jiffy_update_tb;
 			do_timer(regs);
-			timer_sync_xtime( cur_tb );
+			timer_sync_xtime(lpaca->next_jiffy_update_tb);
 			timer_check_rtc();
 			write_sequnlock(&xtime_lock);
 			if ( adjusting_time && (time_adjust == 0) )
@@ -312,36 +350,6 @@
 {
 	return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift;
 }
-
-/*
- * This version of gettimeofday has microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-        unsigned long sec, usec, tb_ticks;
-	unsigned long xsec, tb_xsec;
-	struct gettimeofday_vars * temp_varp;
-	unsigned long temp_tb_to_xs, temp_stamp_xsec;
-
-	/* These calculations are faster (gets rid of divides)
-	 * if done in units of 1/2^20 rather than microseconds.
-	 * The conversion to microseconds at the end is done
-	 * without a divide (and in fact, without a multiply) */
-	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
-	temp_varp = do_gtod.varp;
-	temp_tb_to_xs = temp_varp->tb_to_xs;
-	temp_stamp_xsec = temp_varp->stamp_xsec;
-	tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs );
-	xsec = temp_stamp_xsec + tb_xsec;
-	sec = xsec / XSEC_PER_SEC;
-	xsec -= sec * XSEC_PER_SEC;
-	usec = (xsec * USEC_PER_SEC)/XSEC_PER_SEC;
-
-        tv->tv_sec = sec;
-        tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
 
 int do_settimeofday(struct timespec *tv)
 {


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] ppc64: xtime <-> gettimeofday can get out of sync
  2005-01-10 13:24 [PATCH] ppc64: xtime <-> gettimeofday can get out of sync Anton Blanchard
@ 2005-01-13  3:40 ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 2+ messages in thread
From: Benjamin Herrenschmidt @ 2005-01-13  3:40 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: Andrew Morton, Paul Mackerras, Linux Kernel list


> Note that the time_sync_xtime check only stops the seconds from going
> backwards, the ns component still could couldnt it? Considering this
> is hard to get right, should we switch to the time interpolator stuff?
> The only problem there is it might be trouble for systemcfg (which
> exports stuff to do userspace gettimeofday).

My userland implementation in the vDSO also relies on our current
algorithm. It's not merged yet and could be changed of course, but I
ended up quite liking our current code ;) 

The interesting thing with it is we are basically lock-less
(and even barrier-less on reads).

Ben.



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2005-01-13  3:41 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-01-10 13:24 [PATCH] ppc64: xtime <-> gettimeofday can get out of sync Anton Blanchard
2005-01-13  3:40 ` Benjamin Herrenschmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).