aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2006-06-26 03:25:18 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:21 -0400
commit19923c190e0932bf0ac1e1d06a48f5c3678dd0de (patch)
tree2a32f5f16b3bbebd74c0f4910493c7f28a70fd84 /include
parent6415ce9a922a1446e7ee0ac9b016082232ebe373 (diff)
[PATCH] fix and optimize clock source update
This fixes the clock source updates in update_wall_time() to correctly track the time coming in via current_tick_length(). Optimize the fast paths to be as short as possible to keep the overhead low. Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Acked-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/clocksource.h113
-rw-r--r--include/linux/timex.h4
2 files changed, 12 insertions, 105 deletions
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 4bc94282c364..d852024ed095 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -46,8 +46,8 @@ typedef u64 cycle_t;
46 * @shift: cycle to nanosecond divisor (power of two) 46 * @shift: cycle to nanosecond divisor (power of two)
47 * @update_callback: called when safe to alter clocksource values 47 * @update_callback: called when safe to alter clocksource values
48 * @is_continuous: defines if clocksource is free-running. 48 * @is_continuous: defines if clocksource is free-running.
49 * @interval_cycles: Used internally by timekeeping core, please ignore. 49 * @cycle_interval: Used internally by timekeeping core, please ignore.
50 * @interval_snsecs: Used internally by timekeeping core, please ignore. 50 * @xtime_interval: Used internally by timekeeping core, please ignore.
51 */ 51 */
52struct clocksource { 52struct clocksource {
53 char *name; 53 char *name;
@@ -61,8 +61,9 @@ struct clocksource {
61 int is_continuous; 61 int is_continuous;
62 62
63 /* timekeeping specific data, ignore */ 63 /* timekeeping specific data, ignore */
64 cycle_t interval_cycles; 64 cycle_t cycle_last, cycle_interval;
65 u64 interval_snsecs; 65 u64 xtime_nsec, xtime_interval;
66 s64 error;
66}; 67};
67 68
68/* simplify initialization of mask field */ 69/* simplify initialization of mask field */
@@ -168,107 +169,11 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
168 tmp += c->mult/2; 169 tmp += c->mult/2;
169 do_div(tmp, c->mult); 170 do_div(tmp, c->mult);
170 171
171 c->interval_cycles = (cycle_t)tmp; 172 c->cycle_interval = (cycle_t)tmp;
172 if(c->interval_cycles == 0) 173 if (c->cycle_interval == 0)
173 c->interval_cycles = 1; 174 c->cycle_interval = 1;
174 175
175 c->interval_snsecs = (u64)c->interval_cycles * c->mult; 176 c->xtime_interval = (u64)c->cycle_interval * c->mult;
176}
177
178
179/**
180 * error_aproximation - calculates an error adjustment for a given error
181 *
182 * @error: Error value (unsigned)
183 * @unit: Adjustment unit
184 *
185 * For a given error value, this function takes the adjustment unit
186 * and uses binary approximation to return a power of two adjustment value.
187 *
188 * This function is only for use by the the make_ntp_adj() function
189 * and you must hold a write on the xtime_lock when calling.
190 */
191static inline int error_aproximation(u64 error, u64 unit)
192{
193 static int saved_adj = 0;
194 u64 adjusted_unit = unit << saved_adj;
195
196 if (error > (adjusted_unit * 2)) {
197 /* large error, so increment the adjustment factor */
198 saved_adj++;
199 } else if (error > adjusted_unit) {
200 /* just right, don't touch it */
201 } else if (saved_adj) {
202 /* small error, so drop the adjustment factor */
203 saved_adj--;
204 return 0;
205 }
206
207 return saved_adj;
208}
209
210
211/**
212 * make_ntp_adj - Adjusts the specified clocksource for a given error
213 *
214 * @clock: Pointer to clock to be adjusted
215 * @cycles_delta: Current unacounted cycle delta
216 * @error: Pointer to current error value
217 *
218 * Returns clock shifted nanosecond adjustment to be applied against
219 * the accumulated time value (ie: xtime).
220 *
221 * If the error value is large enough, this function calulates the
222 * (power of two) adjustment value, and adjusts the clock's mult and
223 * interval_snsecs values accordingly.
224 *
225 * However, since there may be some unaccumulated cycles, to avoid
226 * time inconsistencies we must adjust the accumulation value
227 * accordingly.
228 *
229 * This is not very intuitive, so the following proof should help:
230 * The basic timeofday algorithm: base + cycle * mult
231 * Thus:
232 * new_base + cycle * new_mult = old_base + cycle * old_mult
233 * new_base = old_base + cycle * old_mult - cycle * new_mult
234 * new_base = old_base + cycle * (old_mult - new_mult)
235 * new_base - old_base = cycle * (old_mult - new_mult)
236 * base_delta = cycle * (old_mult - new_mult)
237 * base_delta = cycle * (mult_delta)
238 *
239 * Where mult_delta is the adjustment value made to mult
240 *
241 */
242static inline s64 make_ntp_adj(struct clocksource *clock,
243 cycles_t cycles_delta, s64* error)
244{
245 s64 ret = 0;
246 if (*error > ((s64)clock->interval_cycles+1)/2) {
247 /* calculate adjustment value */
248 int adjustment = error_aproximation(*error,
249 clock->interval_cycles);
250 /* adjust clock */
251 clock->mult += 1 << adjustment;
252 clock->interval_snsecs += clock->interval_cycles << adjustment;
253
254 /* adjust the base and error for the adjustment */
255 ret = -(cycles_delta << adjustment);
256 *error -= clock->interval_cycles << adjustment;
257 /* XXX adj error for cycle_delta offset? */
258 } else if ((-(*error)) > ((s64)clock->interval_cycles+1)/2) {
259 /* calculate adjustment value */
260 int adjustment = error_aproximation(-(*error),
261 clock->interval_cycles);
262 /* adjust clock */
263 clock->mult -= 1 << adjustment;
264 clock->interval_snsecs -= clock->interval_cycles << adjustment;
265
266 /* adjust the base and error for the adjustment */
267 ret = cycles_delta << adjustment;
268 *error += clock->interval_cycles << adjustment;
269 /* XXX adj error for cycle_delta offset? */
270 }
271 return ret;
272} 177}
273 178
274 179
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 1ba3071fcb82..19bb6538b49e 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -303,8 +303,10 @@ time_interpolator_reset(void)
303 303
304#endif /* !CONFIG_TIME_INTERPOLATION */ 304#endif /* !CONFIG_TIME_INTERPOLATION */
305 305
306#define TICK_LENGTH_SHIFT 32
307
306/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */ 308/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
307extern u64 current_tick_length(long); 309extern u64 current_tick_length(void);
308 310
309extern int do_adjtimex(struct timex *); 311extern int do_adjtimex(struct timex *);
310 312