summaryrefslogtreecommitdiffstats
path: root/hwclock/adjtime.patch
blob: 81d0430fdd1d9439a6203ae30dbfba2811cd0d25 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
From ao112@rgfn.epcc.edu Fri Mar 19 06:27:26 1999
Received: from rgfn.epcc.edu (rgfn.epcc.edu [208.136.234.19]) by hera.cwi.nl with ESMTP
	id GAA27711 for <Andries.Brouwer@cwi.nl>; Fri, 19 Mar 1999 06:27:23 +0100 (MET)
Received: (from ao112@localhost)
	by rgfn.epcc.edu (8.8.8/8.8.8) id WAA16797;
	Thu, 18 Mar 1999 22:27:19 -0700 (MST)
Date: Thu, 18 Mar 1999 22:27:19 -0700 (MST)
Message-Id: <199903190527.WAA16797@rgfn.epcc.edu>
From: ao112@rgfn.epcc.edu (James P. Rutledge)
To: Andries.Brouwer@cwi.nl
Subject: Re: hwclock patch for drift_factor calculation improvement
Reply-To: ao112@rgfn.epcc.edu
Status: R



>
>Could you perhaps make your patch relative to
>util-linux-2.9n (found in ftp.cwi.nl/pub/aeb/util-linux/util-linux-2.9n.tar.gz)
>?
>
>(The hwclock stuff has changed quite a bit since 2.9g.)
>
>Andries
>

Andries;

Per your request, the patch has been modified for util-linux version
2.9n, from the version for 2.9g.

The program "hwclock" (version 2.4c) could give more accurate
values for the drift factor that it places in the file "/etc/adjtime".

A patch to improve the accuracy is included.

I have incorporated some error sources which were not compensated
for into the drift factor calculation (performed when the "--set"
or the "--systohc" option is used) to make it more accurate.
In particular, the sync delay between the desired set time and the
start of the hardware clock second, and the expected drift since the
last hardware clock adjustment are now accounted for in the drift
factor calculation.

With this patch, if at any time an adjust operation is attempted and
the hardware clock is found to be not valid, then the calibration
and adjustment time is set to zero to insure that if the hardware
clock should coincidentally return to validity, a calibration is not
done with bad history data (hardware clock info bad) and an adjust is
not attempted on bad (but now passing validity test) hardware clock
data.  (With this patch, a previous calibration time of zero causes
the calibration time to initialize with the current time, when the
hardware clock is set, but no change is made to the drift factor,
so in effect, an initial calibration is started over while the previous
drift factor is retained.)

Also, the behavior in the case of an initially missing "/etc/adjtime"
file or such a file produced by the predecessor "clock" program has
been slightly improved as follows: 

    With this patch, if the file exists but was produced by "clock"
    and, thus, is given a zero calibration time, the drift factor is
    not updated upon the first calibration by "hwclock", but is left alone
    and is only changed by subsequent calibrations.

    With this patch, if the file does not exist and, thus, is given
    a zero calibration time, the drift factor is set to zero upon the
    first calibration by "hwclock" and is then changed, as appropriate, by
    subsequent calibrations.

    Also, with this patch, an "--adjust" operation against a non-existent
    "/etc/adjtime" file or one which has zero as the last adjustment
    time will not change the hardware clock setting.

A context diff for a patch to the file "hwclock.c" in the directory
"util-linux-2.9n/clock" is appended.
To use the patch, "cd" to the directory "util-linux-2.9n/clock".
Run "patch < bug-report", where "bug-report" is the file name of
this mail message, to get new file "hwclock.c" which contains the proposed
new version.  This patch is, of course, submitted per the GPL and the
appropriate "NO WARRANTY OF ANY KIND" and "USE AT YOUR OWN RISK"
disclaimers apply.

Note that the patch presumptuously changes the "hwclock.c" version
number from 2.4c to 2.4c1 in "hwclock.c".

Jim

------------------ Patch file follows ----------------------------
*** hwclock.c	Thu Mar 18 22:04:01 1999
--- new-hwclock.c	Thu Mar 18 22:03:18 1999
***************
*** 76,86 ****
  
  #include "clock.h"
  #include "../version.h"
  
  #define MYNAME "hwclock"
! #define VERSION "2.4c"
  
  char *progname = MYNAME;
  
  /* The struct that holds our hardware access routines */
  struct clock_ops *ur;
--- 76,86 ----
  
  #include "clock.h"
  #include "../version.h"
  
  #define MYNAME "hwclock"
! #define VERSION "2.4c1"
  
  char *progname = MYNAME;
  
  /* The struct that holds our hardware access routines */
  struct clock_ops *ur;
***************
*** 581,601 ****
  
  
  static void
  adjust_drift_factor(struct adjtime *adjtime_p,
                      const time_t nowtime, 
!                     const bool hclock_valid, const time_t hclocktime   ) {
  /*---------------------------------------------------------------------------
    Update the drift factor in <*adjtime_p> to reflect the fact that the
    Hardware Clock was calibrated to <nowtime> and before that was set
    to <hclocktime>.
  
-   We assume that the user has been doing regular drift adjustments
-   using the drift factor in the adjtime file, so if <nowtime> and
-   <clocktime> are different, that means the adjustment factor isn't
-   quite right.
- 
    We record in the adjtime file the time at which we last calibrated
    the clock so we can compute the drift rate each time we calibrate.
  
    EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set
    before to anything meaningful and regular adjustments have not been
--- 581,598 ----
  
  
  static void
  adjust_drift_factor(struct adjtime *adjtime_p,
                      const time_t nowtime, 
!                     const bool hclock_valid,
!                     const time_t hclocktime,
!                     const float sync_delay   ) {
  /*---------------------------------------------------------------------------
    Update the drift factor in <*adjtime_p> to reflect the fact that the
    Hardware Clock was calibrated to <nowtime> and before that was set
    to <hclocktime>.
  
    We record in the adjtime file the time at which we last calibrated
    the clock so we can compute the drift rate each time we calibrate.
  
    EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set
    before to anything meaningful and regular adjustments have not been
***************
*** 604,629 ****
  ----------------------------------------------------------------------------*/
    if (!hclock_valid) {
      if (debug)
        printf("Not adjusting drift factor because the Hardware Clock "
               "previously contained garbage.\n");
    } else if ((hclocktime - adjtime_p->last_calib_time) < 23 * 60 * 60) {
      if (debug) 
        printf("Not adjusting drift factor because it has been less than a "
               "day since the last calibration.\n");
    } else {
!     const float factor_adjust = 
!       ((float) (nowtime - hclocktime) 
!        / (hclocktime - adjtime_p->last_calib_time))
!         * 24 * 60 * 60;
  
      if (debug)
!       printf("Clock drifted %d seconds in the past %d seconds "
               "in spite of a drift factor of %f seconds/day.\n"
               "Adjusting drift factor by %f seconds/day\n",
!              (int) (nowtime - hclocktime),
!              (int) (hclocktime - adjtime_p->last_calib_time),
               adjtime_p->drift_factor,
               factor_adjust  );
        
      adjtime_p->drift_factor += factor_adjust;
    }
--- 601,642 ----
  ----------------------------------------------------------------------------*/
    if (!hclock_valid) {
      if (debug)
        printf("Not adjusting drift factor because the Hardware Clock "
               "previously contained garbage.\n");
+   } else if (adjtime_p->last_calib_time == 0) {
+     if (debug)
+       printf("Not adjusting drift factor because last calibration "
+              "time is zero,\nso history is bad and calibration startover "
+              "is necessary.\n");
    } else if ((hclocktime - adjtime_p->last_calib_time) < 23 * 60 * 60) {
      if (debug) 
        printf("Not adjusting drift factor because it has been less than a "
               "day since the last calibration.\n");
    } else {
!     const float sec_per_day = 24.0 * 60.0 * 60.0;
!     float atime_per_htime;  /* adjusted time units per hardware time unit */
!     float adj_days;   /* days since last adjustment (in hardware clock time) */
!     float cal_days;   /* days since last calibration (in hardware clock time) */
!     float exp_drift;  /* expected drift (sec) since last adjustment */
!     float unc_drift;  /* uncorrected drift (sec) since last calibration */
!     float factor_adjust;  /* amount to add to previous drift factor */
!     atime_per_htime = 1.0 + adjtime_p->drift_factor / sec_per_day;
!     adj_days = (float)(hclocktime - adjtime_p->last_adj_time) / sec_per_day;
!     exp_drift = adj_days * adjtime_p->drift_factor + adjtime_p->not_adjusted;
!     unc_drift = (float)(nowtime - hclocktime) + sync_delay - exp_drift;
!     cal_days = ((float)(adjtime_p->last_adj_time - adjtime_p->last_calib_time)
!                  + adjtime_p->not_adjusted) / (sec_per_day * atime_per_htime)
!                + adj_days;
!     factor_adjust = unc_drift / cal_days;
  
      if (debug)
!       printf("Clock drifted %.1f seconds in the past %d seconds "
               "in spite of a drift factor of %f seconds/day.\n"
               "Adjusting drift factor by %f seconds/day\n",
!              unc_drift,
!              (int) (nowtime - adjtime_p->last_calib_time),
               adjtime_p->drift_factor,
               factor_adjust  );
        
      adjtime_p->drift_factor += factor_adjust;
    }
***************
*** 764,773 ****
--- 777,794 ----
  
  ----------------------------------------------------------------------------*/
    if (!hclock_valid) {
      fprintf(stderr, "The Hardware Clock does not contain a valid time, "
              "so we cannot adjust it.\n");
+     adjtime_p->last_calib_time = 0;  /* calibration startover is required */
+     adjtime_p->last_adj_time = 0;
+     adjtime_p->not_adjusted = 0;
+     adjtime_p->dirty = TRUE;
+   } else if (adjtime_p->last_adj_time == 0) {
+     if (debug)
+       printf("Not setting clock because last adjustment time is zero, "
+              "so history is bad.");
    } else {
      int adjustment;
      /* Number of seconds we must insert in the Hardware Clock */
      float retro;   
      /* Fraction of second we have to remove from clock after inserting
***************
*** 878,888 ****
                         time_diff(read_time, startup_time));
            *retcode_p = 0;
          } else if (set) {
            set_hardware_clock_exact(set_time, startup_time, 
  				      universal, testing);
!           adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime);
            *retcode_p = 0;
          } else if (adjust) {
            do_adjustment(&adjtime, hclock_valid, hclocktime, 
                          read_time, universal, testing);
            *retcode_p = 0;
--- 899,910 ----
                         time_diff(read_time, startup_time));
            *retcode_p = 0;
          } else if (set) {
            set_hardware_clock_exact(set_time, startup_time, 
  				      universal, testing);
!           adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime,
!                               time_diff(read_time, startup_time));
            *retcode_p = 0;
          } else if (adjust) {
            do_adjustment(&adjtime, hclock_valid, hclocktime, 
                          read_time, universal, testing);
            *retcode_p = 0;
***************
*** 898,908 ****
            
            set_hardware_clock_exact((time_t) reftime.tv_sec, reftime, 
                                     universal, testing);
            *retcode_p = 0;
            adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid, 
!                               hclocktime);
          } else if (hctosys) {
            rc = set_system_clock(hclock_valid, hclocktime, testing);
            if (rc != 0) {
              printf("Unable to set system clock.\n");
              *retcode_p = 1;
--- 920,930 ----
            
            set_hardware_clock_exact((time_t) reftime.tv_sec, reftime, 
                                     universal, testing);
            *retcode_p = 0;
            adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid, 
!                               hclocktime, (float)(read_time.tv_usec / 1E6));
          } else if (hctosys) {
            rc = set_system_clock(hclock_valid, hclocktime, testing);
            if (rc != 0) {
              printf("Unable to set system clock.\n");
              *retcode_p = 1;