Subject: Re: Strange numbers from gettimeofday(2)
To: None <jdev@panix.com>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: port-xen
Date: 01/14/2006 17:29:01
--NextPart-20060114170529-0369700
Content-Type: Text/Plain; charset=us-ascii

> Sometimes, gettimeofday(2) will return large negative numbers for the
> tv_usec field; this has been happening spontaneously, but I've been
> able to reproduce it by either pausing or ddb-breaking a domU for a
> few seconds (the exact interval varies on different hardware).

cc_microtime assumes that both of timer and tsc is somewhat stable.
however, both of them can be unstable on xen.

i think that the attached patch eases the problem.
but i agree that cc_microtime is not suitable for xen anyway.

YAMAMOTO Takashi

--NextPart-20060114170529-0369700
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="a.diff"

Index: kern_microtime.c
===================================================================
--- kern_microtime.c	(revision 1464)
+++ kern_microtime.c	(working copy)
@@ -144,9 +144,11 @@ cc_microtime(struct timeval *tvp)
 		usec += 1000000;
 		sec--;
 	}
+	KASSERT(usec >= 0);
+	KASSERT(usec < 1000000);
 	if (sec == 0 && usec > 0)  {
 		t.tv_usec += usec + 1;
-		if (t.tv_usec >= 1000000) {
+		while (t.tv_usec >= 1000000) {
 			t.tv_usec -= 1000000;
 			t.tv_sec++;
 		}
@@ -199,7 +201,28 @@ cc_microset(struct cpu_info *ci)
 	    (t.tv_usec - ci->ci_cc_time.tv_usec);
 
 	ci->ci_cc_time = t;
+
 	/*
+	 * check if our cpu frequency is sane.
+	 */
+
+	if (delta != 0) {
+		uint64_t freq = cpu_frequency(ci);
+		uint64_t ourfreq;
+
+		ourfreq = denom * 1000000 / delta;
+		if (__predict_false(ourfreq > freq * 2 || ourfreq * 2 < freq)) {
+#if 0
+			printf("%s[%d]: ourfreq=%" PRIu64 ", freq=%"
+			    PRIu64 ", delta=%" PRId64 ", denom=%" PRId64 "\n",
+			    __func__, (int)ci->ci_cpuid,
+			    ourfreq, freq, delta, denom);
+#endif
+			goto insane;
+		}
+	}
+
+	/*
 	 * Make sure it's within .5 to 1.5 seconds -- otherwise,
 	 * the time is probably be frobbed with by the timekeeper
 	 * or the human.
@@ -212,6 +235,7 @@ cc_microset(struct cpu_info *ci)
 		    ", denom %" PRId64 "\n", ci->ci_cpuid, delta, denom);
 #endif
 	} else {
+insane:
 #if 0
 		printf("cc_microset[%lu]: delta %" PRId64 ", resetting state\n",
 		       (u_long)ci->ci_cpuid, delta);

--NextPart-20060114170529-0369700--