improve adjtime

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

improve adjtime

Ted Unangst-2
this diff should improve the behavior of adjtime for clocks way out of
whack.  if the adjustment to be made is greater than 4 hours, we crank the
adjustment way up.  if we notice a series of calls to pull the clock in
the same direction, it means we are drifting faster than tickdelta can
correct for, and so we start increasing the delta until it stabilizes.  
finally, because this can lead to some very large tickdeltas, make sure
we are never going over tick / 2.

i'm not positive the increase_skew logic is correct.  i was trying to
avoid ping pong behavior.  in any case, this diff should only affect the
rate at which we arrive at the adjusted time, but not the actual
adjustment itself.


Index: kern_time.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_time.c,v
retrieving revision 1.52
diff -u -r1.52 kern_time.c
--- kern_time.c 28 Nov 2005 00:14:29 -0000 1.52
+++ kern_time.c 17 Dec 2005 04:30:31 -0000
@@ -381,9 +381,11 @@
 
  return (0);
 #else
+ static int increase_skew;
  struct timeval atv;
- long ndelta, ntickdelta, odelta;
+ long secdelta, ndelta, ntickdelta, odelta;
  int s, error;
+ int largeadj = 0;
 
  if ((error = suser(p, 0)))
  return (error);
@@ -398,12 +400,21 @@
  * hardclock(), tickdelta will become zero, lest the correction
  * overshoot and start taking us away from the desired final time.
  */
- if (atv.tv_sec > LONG_MAX / 1000000L)
+ secdelta = atv.tv_sec;
+
+ /* if this is going to take more than 4 hours, speed it up */
+ if (secdelta / 1000000L > 4 * 3600L) {
+ largeadj = 1;
+ ndelta = LONG_MAX;
+ } else if (secdelta / 1000000L < -4 * 3600L) {
+ largeadj = 1;
+ ndelta = LONG_MIN;
+ } else if (secdelta > LONG_MAX / 1000000L) {
  ndelta = LONG_MAX;
- else if (atv.tv_sec < LONG_MIN / 1000000L)
+ } else if (secdelta < LONG_MIN / 1000000L) {
  ndelta = LONG_MIN;
- else {
- ndelta = atv.tv_sec * 1000000L;
+ } else {
+ ndelta = secdelta * 1000000L;
  odelta = ndelta;
  ndelta += atv.tv_usec;
  if (atv.tv_usec > 0 && ndelta <= odelta)
@@ -412,20 +423,41 @@
  ndelta = LONG_MIN;
  }
 
- if (ndelta > bigadj || ndelta < -bigadj)
+ if (largeadj)
+ ntickdelta = 100 * tickadj;
+ else if (ndelta > bigadj || ndelta < -bigadj)
  ntickdelta = 10 * tickadj;
  else
  ntickdelta = tickadj;
+ /* check to see if we are losing the race */
+ if (increase_skew > 5)
+ ntickdelta += increase_skew / 5 * ntickdelta / 2;
+ else if (increase_skew < -5)
+ ntickdelta += -increase_skew / 5 * ntickdelta / 2;
+ if (ntickdelta > tick / 2)
+ ntickdelta = tick / 2;
  if (ndelta % ntickdelta)
  ndelta = ndelta / ntickdelta * ntickdelta;
 
  /*
  * To make hardclock()'s job easier, make the per-tick delta negative
  * if we want time to run slower; then hardclock can simply compute
- * tick + tickdelta, and subtract tickdelta from timedelta.
+ * tick + tickdelta, and subtract tickdelta from timedelta.  If
+ * we notice we are sliding away from where we want to be,
+ * take notice so next time we can increase the adjustment.
  */
- if (ndelta < 0)
+ if (ndelta < 0) {
  ntickdelta = -ntickdelta;
+ if (ndelta < timedelta && increase_skew < 0)
+ increase_skew--;
+ else if (increase_skew > 0)
+ increase_skew--;
+ } else {
+ if (ndelta > timedelta && increase_skew > 0)
+ increase_skew++;
+ else if (increase_skew < 0)
+ increase_skew++;
+ }
  s = splclock();
  odelta = timedelta;
  timedelta = ndelta;


--
die energie aus fleisch und blut        deine sprache und die ganze wut
deine gefuehle die du lebst             und dein herz fuehl wie es bebt
zeitbombe! sie tickt in dir    zeitbombe! sie explodiert in deinem kopf
                                                    - girls under glass