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--