1 From ao112@rgfn.epcc.edu Fri Mar 19 06:27:26 1999
2 Received: from rgfn.epcc.edu (rgfn.epcc.edu [208.136.234.19]) by hera.cwi.nl with ESMTP
3 id GAA27711 for <Andries.Brouwer@cwi.nl>; Fri, 19 Mar 1999 06:27:23 +0100 (MET)
4 Received: (from ao112@localhost)
5 by rgfn.epcc.edu (8.8.8/8.8.8) id WAA16797;
6 Thu, 18 Mar 1999 22:27:19 -0700 (MST)
7 Date: Thu, 18 Mar 1999 22:27:19 -0700 (MST)
8 Message-Id: <199903190527.WAA16797@rgfn.epcc.edu>
9 From: ao112@rgfn.epcc.edu (James P. Rutledge)
10 To: Andries.Brouwer@cwi.nl
11 Subject: Re: hwclock patch for drift_factor calculation improvement
12 Reply-To: ao112@rgfn.epcc.edu
18 >Could you perhaps make your patch relative to
19 >util-linux-2.9n (found in ftp.cwi.nl/pub/aeb/util-linux/util-linux-2.9n.tar.gz)
22 >(The hwclock stuff has changed quite a bit since 2.9g.)
29 Per your request, the patch has been modified for util-linux version
30 2.9n, from the version for 2.9g.
32 The program "hwclock" (version 2.4c) could give more accurate
33 values for the drift factor that it places in the file "/etc/adjtime".
35 A patch to improve the accuracy is included.
37 I have incorporated some error sources which were not compensated
38 for into the drift factor calculation (performed when the "--set"
39 or the "--systohc" option is used) to make it more accurate.
40 In particular, the sync delay between the desired set time and the
41 start of the hardware clock second, and the expected drift since the
42 last hardware clock adjustment are now accounted for in the drift
45 With this patch, if at any time an adjust operation is attempted and
46 the hardware clock is found to be not valid, then the calibration
47 and adjustment time is set to zero to insure that if the hardware
48 clock should coincidentally return to validity, a calibration is not
49 done with bad history data (hardware clock info bad) and an adjust is
50 not attempted on bad (but now passing validity test) hardware clock
51 data. (With this patch, a previous calibration time of zero causes
52 the calibration time to initialize with the current time, when the
53 hardware clock is set, but no change is made to the drift factor,
54 so in effect, an initial calibration is started over while the previous
55 drift factor is retained.)
57 Also, the behavior in the case of an initially missing "/etc/adjtime"
58 file or such a file produced by the predecessor "clock" program has
59 been slightly improved as follows:
61 With this patch, if the file exists but was produced by "clock"
62 and, thus, is given a zero calibration time, the drift factor is
63 not updated upon the first calibration by "hwclock", but is left alone
64 and is only changed by subsequent calibrations.
66 With this patch, if the file does not exist and, thus, is given
67 a zero calibration time, the drift factor is set to zero upon the
68 first calibration by "hwclock" and is then changed, as appropriate, by
69 subsequent calibrations.
71 Also, with this patch, an "--adjust" operation against a non-existent
72 "/etc/adjtime" file or one which has zero as the last adjustment
73 time will not change the hardware clock setting.
75 A context diff for a patch to the file "hwclock.c" in the directory
76 "util-linux-2.9n/clock" is appended.
77 To use the patch, "cd" to the directory "util-linux-2.9n/clock".
78 Run "patch < bug-report", where "bug-report" is the file name of
79 this mail message, to get new file "hwclock.c" which contains the proposed
80 new version. This patch is, of course, submitted per the GPL and the
81 appropriate "NO WARRANTY OF ANY KIND" and "USE AT YOUR OWN RISK"
84 Note that the patch presumptuously changes the "hwclock.c" version
85 number from 2.4c to 2.4c1 in "hwclock.c".
89 ------------------ Patch file follows ----------------------------
90 *** hwclock.c Thu Mar 18 22:04:01 1999
91 --- new-hwclock.c Thu Mar 18 22:03:18 1999
96 #include "../version.h"
98 #define MYNAME "hwclock"
99 ! #define VERSION "2.4c"
101 char *progname = MYNAME;
103 /* The struct that holds our hardware access routines */
104 struct clock_ops *ur;
108 #include "../version.h"
110 #define MYNAME "hwclock"
111 ! #define VERSION "2.4c1"
113 char *progname = MYNAME;
115 /* The struct that holds our hardware access routines */
116 struct clock_ops *ur;
122 adjust_drift_factor(struct adjtime *adjtime_p,
123 const time_t nowtime,
124 ! const bool hclock_valid, const time_t hclocktime ) {
125 /*---------------------------------------------------------------------------
126 Update the drift factor in <*adjtime_p> to reflect the fact that the
127 Hardware Clock was calibrated to <nowtime> and before that was set
130 - We assume that the user has been doing regular drift adjustments
131 - using the drift factor in the adjtime file, so if <nowtime> and
132 - <clocktime> are different, that means the adjustment factor isn't
135 We record in the adjtime file the time at which we last calibrated
136 the clock so we can compute the drift rate each time we calibrate.
138 EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set
139 before to anything meaningful and regular adjustments have not been
144 adjust_drift_factor(struct adjtime *adjtime_p,
145 const time_t nowtime,
146 ! const bool hclock_valid,
147 ! const time_t hclocktime,
148 ! const float sync_delay ) {
149 /*---------------------------------------------------------------------------
150 Update the drift factor in <*adjtime_p> to reflect the fact that the
151 Hardware Clock was calibrated to <nowtime> and before that was set
154 We record in the adjtime file the time at which we last calibrated
155 the clock so we can compute the drift rate each time we calibrate.
157 EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set
158 before to anything meaningful and regular adjustments have not been
161 ----------------------------------------------------------------------------*/
164 printf("Not adjusting drift factor because the Hardware Clock "
165 "previously contained garbage.\n");
166 } else if ((hclocktime - adjtime_p->last_calib_time) < 23 * 60 * 60) {
168 printf("Not adjusting drift factor because it has been less than a "
169 "day since the last calibration.\n");
171 ! const float factor_adjust =
172 ! ((float) (nowtime - hclocktime)
173 ! / (hclocktime - adjtime_p->last_calib_time))
177 ! printf("Clock drifted %d seconds in the past %d seconds "
178 "in spite of a drift factor of %f seconds/day.\n"
179 "Adjusting drift factor by %f seconds/day\n",
180 ! (int) (nowtime - hclocktime),
181 ! (int) (hclocktime - adjtime_p->last_calib_time),
182 adjtime_p->drift_factor,
185 adjtime_p->drift_factor += factor_adjust;
188 ----------------------------------------------------------------------------*/
191 printf("Not adjusting drift factor because the Hardware Clock "
192 "previously contained garbage.\n");
193 + } else if (adjtime_p->last_calib_time == 0) {
195 + printf("Not adjusting drift factor because last calibration "
196 + "time is zero,\nso history is bad and calibration startover "
197 + "is necessary.\n");
198 } else if ((hclocktime - adjtime_p->last_calib_time) < 23 * 60 * 60) {
200 printf("Not adjusting drift factor because it has been less than a "
201 "day since the last calibration.\n");
203 ! const float sec_per_day = 24.0 * 60.0 * 60.0;
204 ! float atime_per_htime; /* adjusted time units per hardware time unit */
205 ! float adj_days; /* days since last adjustment (in hardware clock time) */
206 ! float cal_days; /* days since last calibration (in hardware clock time) */
207 ! float exp_drift; /* expected drift (sec) since last adjustment */
208 ! float unc_drift; /* uncorrected drift (sec) since last calibration */
209 ! float factor_adjust; /* amount to add to previous drift factor */
210 ! atime_per_htime = 1.0 + adjtime_p->drift_factor / sec_per_day;
211 ! adj_days = (float)(hclocktime - adjtime_p->last_adj_time) / sec_per_day;
212 ! exp_drift = adj_days * adjtime_p->drift_factor + adjtime_p->not_adjusted;
213 ! unc_drift = (float)(nowtime - hclocktime) + sync_delay - exp_drift;
214 ! cal_days = ((float)(adjtime_p->last_adj_time - adjtime_p->last_calib_time)
215 ! + adjtime_p->not_adjusted) / (sec_per_day * atime_per_htime)
217 ! factor_adjust = unc_drift / cal_days;
220 ! printf("Clock drifted %.1f seconds in the past %d seconds "
221 "in spite of a drift factor of %f seconds/day.\n"
222 "Adjusting drift factor by %f seconds/day\n",
224 ! (int) (nowtime - adjtime_p->last_calib_time),
225 adjtime_p->drift_factor,
228 adjtime_p->drift_factor += factor_adjust;
234 ----------------------------------------------------------------------------*/
236 fprintf(stderr, "The Hardware Clock does not contain a valid time, "
237 "so we cannot adjust it.\n");
238 + adjtime_p->last_calib_time = 0; /* calibration startover is required */
239 + adjtime_p->last_adj_time = 0;
240 + adjtime_p->not_adjusted = 0;
241 + adjtime_p->dirty = TRUE;
242 + } else if (adjtime_p->last_adj_time == 0) {
244 + printf("Not setting clock because last adjustment time is zero, "
245 + "so history is bad.");
248 /* Number of seconds we must insert in the Hardware Clock */
250 /* Fraction of second we have to remove from clock after inserting
253 time_diff(read_time, startup_time));
256 set_hardware_clock_exact(set_time, startup_time,
258 ! adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime);
261 do_adjustment(&adjtime, hclock_valid, hclocktime,
262 read_time, universal, testing);
265 time_diff(read_time, startup_time));
268 set_hardware_clock_exact(set_time, startup_time,
270 ! adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime,
271 ! time_diff(read_time, startup_time));
274 do_adjustment(&adjtime, hclock_valid, hclocktime,
275 read_time, universal, testing);
280 set_hardware_clock_exact((time_t) reftime.tv_sec, reftime,
283 adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid,
285 } else if (hctosys) {
286 rc = set_system_clock(hclock_valid, hclocktime, testing);
288 printf("Unable to set system clock.\n");
292 set_hardware_clock_exact((time_t) reftime.tv_sec, reftime,
295 adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid,
296 ! hclocktime, (float)(read_time.tv_usec / 1E6));
297 } else if (hctosys) {
298 rc = set_system_clock(hclock_valid, hclocktime, testing);
300 printf("Unable to set system clock.\n");