]>
Commit | Line | Data |
---|---|---|
7eda085c KZ |
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 | |
13 | Status: R | |
14 | ||
15 | ||
16 | ||
17 | > | |
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) | |
20 | >? | |
21 | > | |
22 | >(The hwclock stuff has changed quite a bit since 2.9g.) | |
23 | > | |
24 | >Andries | |
25 | > | |
26 | ||
27 | Andries; | |
28 | ||
29 | Per your request, the patch has been modified for util-linux version | |
30 | 2.9n, from the version for 2.9g. | |
31 | ||
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". | |
34 | ||
35 | A patch to improve the accuracy is included. | |
36 | ||
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 | |
43 | factor calculation. | |
44 | ||
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.) | |
56 | ||
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: | |
60 | ||
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. | |
65 | ||
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. | |
70 | ||
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. | |
74 | ||
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" | |
82 | disclaimers apply. | |
83 | ||
84 | Note that the patch presumptuously changes the "hwclock.c" version | |
85 | number from 2.4c to 2.4c1 in "hwclock.c". | |
86 | ||
87 | Jim | |
88 | ||
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 | |
92 | *************** | |
93 | *** 76,86 **** | |
94 | ||
95 | #include "clock.h" | |
96 | #include "../version.h" | |
97 | ||
98 | #define MYNAME "hwclock" | |
99 | ! #define VERSION "2.4c" | |
100 | ||
101 | char *progname = MYNAME; | |
102 | ||
103 | /* The struct that holds our hardware access routines */ | |
104 | struct clock_ops *ur; | |
105 | --- 76,86 ---- | |
106 | ||
107 | #include "clock.h" | |
108 | #include "../version.h" | |
109 | ||
110 | #define MYNAME "hwclock" | |
111 | ! #define VERSION "2.4c1" | |
112 | ||
113 | char *progname = MYNAME; | |
114 | ||
115 | /* The struct that holds our hardware access routines */ | |
116 | struct clock_ops *ur; | |
117 | *************** | |
118 | *** 581,601 **** | |
119 | ||
120 | ||
121 | static void | |
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 | |
128 | to <hclocktime>. | |
129 | ||
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 | |
133 | - quite right. | |
134 | - | |
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. | |
137 | ||
138 | EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set | |
139 | before to anything meaningful and regular adjustments have not been | |
140 | --- 581,598 ---- | |
141 | ||
142 | ||
143 | static void | |
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 | |
152 | to <hclocktime>. | |
153 | ||
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. | |
156 | ||
157 | EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set | |
158 | before to anything meaningful and regular adjustments have not been | |
159 | *************** | |
160 | *** 604,629 **** | |
161 | ----------------------------------------------------------------------------*/ | |
162 | if (!hclock_valid) { | |
163 | if (debug) | |
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) { | |
167 | if (debug) | |
168 | printf("Not adjusting drift factor because it has been less than a " | |
169 | "day since the last calibration.\n"); | |
170 | } else { | |
171 | ! const float factor_adjust = | |
172 | ! ((float) (nowtime - hclocktime) | |
173 | ! / (hclocktime - adjtime_p->last_calib_time)) | |
174 | ! * 24 * 60 * 60; | |
175 | ||
176 | if (debug) | |
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, | |
183 | factor_adjust ); | |
184 | ||
185 | adjtime_p->drift_factor += factor_adjust; | |
186 | } | |
187 | --- 601,642 ---- | |
188 | ----------------------------------------------------------------------------*/ | |
189 | if (!hclock_valid) { | |
190 | if (debug) | |
191 | printf("Not adjusting drift factor because the Hardware Clock " | |
192 | "previously contained garbage.\n"); | |
193 | + } else if (adjtime_p->last_calib_time == 0) { | |
194 | + if (debug) | |
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) { | |
199 | if (debug) | |
200 | printf("Not adjusting drift factor because it has been less than a " | |
201 | "day since the last calibration.\n"); | |
202 | } else { | |
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) | |
216 | ! + adj_days; | |
217 | ! factor_adjust = unc_drift / cal_days; | |
218 | ||
219 | if (debug) | |
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", | |
223 | ! unc_drift, | |
224 | ! (int) (nowtime - adjtime_p->last_calib_time), | |
225 | adjtime_p->drift_factor, | |
226 | factor_adjust ); | |
227 | ||
228 | adjtime_p->drift_factor += factor_adjust; | |
229 | } | |
230 | *************** | |
231 | *** 764,773 **** | |
232 | --- 777,794 ---- | |
233 | ||
234 | ----------------------------------------------------------------------------*/ | |
235 | if (!hclock_valid) { | |
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) { | |
243 | + if (debug) | |
244 | + printf("Not setting clock because last adjustment time is zero, " | |
245 | + "so history is bad."); | |
246 | } else { | |
247 | int adjustment; | |
248 | /* Number of seconds we must insert in the Hardware Clock */ | |
249 | float retro; | |
250 | /* Fraction of second we have to remove from clock after inserting | |
251 | *************** | |
252 | *** 878,888 **** | |
253 | time_diff(read_time, startup_time)); | |
254 | *retcode_p = 0; | |
255 | } else if (set) { | |
256 | set_hardware_clock_exact(set_time, startup_time, | |
257 | universal, testing); | |
258 | ! adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime); | |
259 | *retcode_p = 0; | |
260 | } else if (adjust) { | |
261 | do_adjustment(&adjtime, hclock_valid, hclocktime, | |
262 | read_time, universal, testing); | |
263 | *retcode_p = 0; | |
264 | --- 899,910 ---- | |
265 | time_diff(read_time, startup_time)); | |
266 | *retcode_p = 0; | |
267 | } else if (set) { | |
268 | set_hardware_clock_exact(set_time, startup_time, | |
269 | universal, testing); | |
270 | ! adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime, | |
271 | ! time_diff(read_time, startup_time)); | |
272 | *retcode_p = 0; | |
273 | } else if (adjust) { | |
274 | do_adjustment(&adjtime, hclock_valid, hclocktime, | |
275 | read_time, universal, testing); | |
276 | *retcode_p = 0; | |
277 | *************** | |
278 | *** 898,908 **** | |
279 | ||
280 | set_hardware_clock_exact((time_t) reftime.tv_sec, reftime, | |
281 | universal, testing); | |
282 | *retcode_p = 0; | |
283 | adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid, | |
284 | ! hclocktime); | |
285 | } else if (hctosys) { | |
286 | rc = set_system_clock(hclock_valid, hclocktime, testing); | |
287 | if (rc != 0) { | |
288 | printf("Unable to set system clock.\n"); | |
289 | *retcode_p = 1; | |
290 | --- 920,930 ---- | |
291 | ||
292 | set_hardware_clock_exact((time_t) reftime.tv_sec, reftime, | |
293 | universal, testing); | |
294 | *retcode_p = 0; | |
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); | |
299 | if (rc != 0) { | |
300 | printf("Unable to set system clock.\n"); | |
301 | *retcode_p = 1; | |
302 |