diff options
author | Roman Zippel <zippel@linux-m68k.org> | 2006-06-26 03:25:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:21 -0400 |
commit | 19923c190e0932bf0ac1e1d06a48f5c3678dd0de (patch) | |
tree | 2a32f5f16b3bbebd74c0f4910493c7f28a70fd84 /include/linux/clocksource.h | |
parent | 6415ce9a922a1446e7ee0ac9b016082232ebe373 (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/linux/clocksource.h')
-rw-r--r-- | include/linux/clocksource.h | 113 |
1 files changed, 9 insertions, 104 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 | */ |
52 | struct clocksource { | 52 | struct 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 | */ | ||
191 | static 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 | */ | ||
242 | static 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 | ||