]> git.ozlabs.org Git - ccan/blob - ccan/timer/timer.c
timer: simple optimization for large number of timers.
[ccan] / ccan / timer / timer.c
1 /* LGPL (v2.1 or any later version) - see LICENSE file for details */
2 #include <ccan/timer/timer.h>
3 #include <ccan/array_size/array_size.h>
4 #include <ccan/ilog/ilog.h>
5 #include <ccan/likely/likely.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8
9 #define PER_LEVEL (1ULL << TIMER_LEVEL_BITS)
10
11 struct timer_level {
12         struct list_head list[PER_LEVEL];
13 };
14
15 static uint64_t time_to_grains(struct timeabs t)
16 {
17         return t.ts.tv_sec * ((uint64_t)1000000000 / TIMER_GRANULARITY)
18                 + (t.ts.tv_nsec / TIMER_GRANULARITY);
19 }
20
21 static struct timeabs grains_to_time(uint64_t grains)
22 {
23         struct timeabs t;
24
25         t.ts.tv_sec = grains / (1000000000 / TIMER_GRANULARITY);
26         t.ts.tv_nsec = (grains % (1000000000 / TIMER_GRANULARITY))
27                 * TIMER_GRANULARITY;
28         return t;
29 }
30
31 void timers_init(struct timers *timers, struct timeabs start)
32 {
33         unsigned int i;
34
35         list_head_init(&timers->far);
36         timers->base = time_to_grains(start);
37         timers->first = -1ULL;
38         memset(timers->firsts, 0xFF, sizeof(timers->firsts));
39         for (i = 0; i < ARRAY_SIZE(timers->level); i++)
40                 timers->level[i] = NULL;
41 }
42
43 static unsigned int level_of(const struct timers *timers, uint64_t time)
44 {
45         uint64_t diff;
46
47         /* Level depends how far away it is. */
48         diff = time - timers->base;
49         return ilog64(diff / 2) / TIMER_LEVEL_BITS;
50 }
51
52 static void timer_add_raw(struct timers *timers, struct timer *t)
53 {
54         struct list_head *l;
55         unsigned int level = level_of(timers, t->time);
56         uint64_t *first;
57
58         if (!timers->level[level]) {
59                 l = &timers->far;
60                 first = &timers->firsts[ARRAY_SIZE(timers->level)];
61         } else {
62                 int off = (t->time >> (level*TIMER_LEVEL_BITS)) & (PER_LEVEL-1);
63                 l = &timers->level[level]->list[off];
64                 first = &timers->firsts[level];
65         }
66
67         list_add_tail(l, &t->list);
68         if (t->time < *first)
69                 *first = t->time;
70 }
71
72 void timer_init(struct timer *t)
73 {
74         list_node_init(&t->list);
75 }
76
77 static bool list_node_initted(const struct list_node *n)
78 {
79         return n->prev == n;
80 }
81
82 void timer_add(struct timers *timers, struct timer *t, struct timeabs when)
83 {
84         assert(list_node_initted(&t->list));
85
86         t->time = time_to_grains(when);
87
88         /* Added in the past?  Treat it as imminent. */
89         if (t->time < timers->base)
90                 t->time = timers->base;
91         if (t->time < timers->first)
92                 timers->first = t->time;
93
94         timer_add_raw(timers, t);
95 }
96
97 /* FIXME: inline */
98 void timer_del(struct timers *timers, struct timer *t)
99 {
100         list_del_init(&t->list);
101 }
102
103 static void timers_far_get(struct timers *timers,
104                            struct list_head *list,
105                            uint64_t when)
106 {
107         struct timer *i, *next;
108
109         list_for_each_safe(&timers->far, i, next, list) {
110                 if (i->time <= when) {
111                         list_del_from(&timers->far, &i->list);
112                         list_add_tail(list, &i->list);
113                 }
114         }
115 }
116
117 static void add_level(struct timers *timers, unsigned int level)
118 {
119         struct timer_level *l;
120         struct timer *t;
121         unsigned int i;
122         struct list_head from_far;
123
124         l = malloc(sizeof(*l));
125         if (!l)
126                 return;
127
128         for (i = 0; i < ARRAY_SIZE(l->list); i++)
129                 list_head_init(&l->list[i]);
130         timers->level[level] = l;
131
132         list_head_init(&from_far);
133         timers_far_get(timers, &from_far,
134                        timers->base + (1ULL << ((level+1)*TIMER_LEVEL_BITS)) - 1);
135
136         while ((t = list_pop(&from_far, struct timer, list)) != NULL)
137                 timer_add_raw(timers, t);
138 }
139
140 /* We don't need to search past the first at level 0, since the
141  * bucket range is 1; they're all the same. */
142 static const struct timer *find_first(const struct list_head *list,
143                                       unsigned int level,
144                                       const struct timer *prev)
145 {
146         struct timer *t;
147
148         list_for_each(list, t, list) {
149                 if (!prev || t->time < prev->time)
150                         prev = t;
151                 if (level == 0)
152                         break;
153         }
154         return prev;
155 }
156
157 /* Update level's first watermark, and return overall first. */
158 static const struct timer *first_for_level(struct timers *timers,
159                                            size_t level,
160                                            const struct timer *level_first,
161                                            const struct timer *first)
162 {
163         if (level_first) {
164                 timers->firsts[level] = level_first->time;
165                 if (!first || level_first->time < first->time)
166                         first = level_first;
167         } else {
168                 timers->firsts[level] = -1ULL;
169         }
170         return first;
171 }
172
173 static bool level_may_beat(const struct timers *timers, size_t level,
174                            const struct timer *first)
175 {
176         return !first || timers->firsts[level] < first->time;
177 }
178
179 /* FIXME: Suboptimal */
180 static const struct timer *brute_force_first(struct timers *timers)
181 {
182         unsigned int l, i;
183         const struct timer *found = NULL;
184
185         for (l = 0; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) {
186                 const struct timer *t = NULL;
187
188                 /* Do we know they don't have a better one? */
189                 if (!level_may_beat(timers, l, found))
190                         continue;
191
192                 /* Find first timer on this level. */
193                 for (i = 0; i < PER_LEVEL; i++)
194                         t = find_first(&timers->level[l]->list[i], l, t);
195
196                 found = first_for_level(timers, l, t, found);
197         }
198
199         /* Check (and update) far list if there's a chance. */
200         l = ARRAY_SIZE(timers->level);
201         if (level_may_beat(timers, l, found)) {
202                 const struct timer *t = find_first(&timers->far, l, NULL);
203                 found = first_for_level(timers, l, t, found);
204         }
205
206         return found;
207 }
208
209 static const struct timer *get_first(struct timers *timers)
210 {
211         /* We can have just far timers, for example. */
212         if (timers->level[0]) {
213                 /* First search rest of lower buckets; we've already spilled
214                  * so if we find one there we don't need to search further. */
215                 unsigned int i, off = timers->base % PER_LEVEL;
216
217                 for (i = off; i < PER_LEVEL; i++) {
218                         struct list_head *h = &timers->level[0]->list[i];
219                         if (!list_empty(h))
220                                 return find_first(h, 0, NULL);
221                 }
222         }
223
224         /* From here on, we're searching non-normalized parts of the
225          * data structure, which is much subtler.
226          *
227          * So we brute force. */
228         return brute_force_first(timers);
229 }
230
231 static bool update_first(struct timers *timers)
232 {
233         const struct timer *found = get_first(timers);
234
235         if (!found) {
236                 timers->first = -1ULL;
237                 return false;
238         }
239
240         timers->first = found->time;
241         return true;
242 }
243
244 bool timer_earliest(struct timers *timers, struct timeabs *first)
245 {
246         if (!update_first(timers))
247                 return false;
248
249         *first = grains_to_time(timers->first);
250         return true;
251 }
252
253 /* Assume no timers before 'time', cascade down and update base time. */
254 static void timer_fast_forward(struct timers *timers, uint64_t time)
255 {
256         unsigned int level, changed;
257         int need_level = -1;
258         struct list_head list;
259         struct timer *i;
260
261         /* How many bits changed between base and time?
262          * Each time we wrap, we need to empty buckets from above. */
263         if (time == timers->base)
264                 return;
265
266         changed = ilog64_nz(time ^ timers->base);
267         level = (changed - 1) / TIMER_LEVEL_BITS;
268
269         /* Buckets always empty downwards, so we could cascade manually,
270          * but it's rarely very many so we just remove and re-add */
271         list_head_init(&list);
272
273         do {
274                 if (!timers->level[level]) {
275                         /* We need any which belong on this level. */
276                         timers_far_get(timers, &list,
277                                        timers->base
278                                        + (1ULL << ((level+1)*TIMER_LEVEL_BITS))-1);
279                         need_level = level;
280                 } else {
281                         unsigned src;
282
283                         /* Get all timers from this bucket. */
284                         src = (time >> (level * TIMER_LEVEL_BITS)) % PER_LEVEL;
285                         list_append_list(&list,
286                                          &timers->level[level]->list[src]);
287                 }
288         } while (level--);
289
290         /* Did we hit the last level?  If so, add. */
291         if (need_level != -1)
292                 add_level(timers, need_level);
293
294         /* Fast-forward the time, and re-add everyone. */
295         timers->base = time;
296         while ((i = list_pop(&list, struct timer, list)) != NULL)
297                 timer_add_raw(timers, i);
298 }
299
300 /* Returns an expired timer. */
301 struct timer *timers_expire(struct timers *timers, struct timeabs expire)
302 {
303         uint64_t now = time_to_grains(expire);
304         unsigned int off;
305         struct timer *t;
306
307         assert(now >= timers->base);
308
309         if (!timers->level[0]) {
310                 if (list_empty(&timers->far))
311                         return NULL;
312                 add_level(timers, 0);
313         }
314
315         do {
316                 if (timers->first > now) {
317                         timer_fast_forward(timers, now);
318                         return NULL;
319                 }
320
321                 timer_fast_forward(timers, timers->first);
322                 off = timers->base % PER_LEVEL;
323
324                 /* This *may* be NULL, if we deleted the first timer */
325                 t = list_pop(&timers->level[0]->list[off], struct timer, list);
326                 if (t)
327                         list_node_init(&t->list);
328         } while (!t && update_first(timers));
329
330         return t;
331 }
332
333 static bool timer_list_check(const struct list_head *l,
334                              uint64_t min, uint64_t max, uint64_t first,
335                              const char *abortstr)
336 {
337         const struct timer *t;
338
339         if (!list_check(l, abortstr))
340                 return false;
341
342         list_for_each(l, t, list) {
343                 if (t->time < min || t->time > max) {
344                         if (abortstr) {
345                                 fprintf(stderr,
346                                         "%s: timer %p %llu not %llu-%llu\n",
347                                         abortstr, t, (long long)t->time,
348                                         (long long)min, (long long)max);
349                                 abort();
350                         }
351                         return false;
352                 }
353                 if (t->time < first) {
354                         if (abortstr) {
355                                 fprintf(stderr,
356                                         "%s: timer %p %llu < minimum %llu\n",
357                                         abortstr, t, (long long)t->time,
358                                         (long long)first);
359                                 abort();
360                         }
361                         return false;
362                 }
363         }
364         return true;
365 }
366
367 struct timers *timers_check(const struct timers *timers, const char *abortstr)
368 {
369         unsigned int l, i, off;
370         uint64_t base;
371
372         l = 0;
373         if (!timers->level[0])
374                 goto past_levels;
375
376         /* First level is simple. */
377         off = timers->base % PER_LEVEL;
378         for (i = 0; i < PER_LEVEL; i++) {
379                 struct list_head *h;
380
381                 h = &timers->level[l]->list[(i+off) % PER_LEVEL];
382                 if (!timer_list_check(h, timers->base + i, timers->base + i,
383                                       timers->firsts[l], abortstr))
384                         return NULL;
385         }
386
387         /* For other levels, "current" bucket has been emptied, and may contain
388          * entries for the current + level_size bucket. */
389         for (l = 1; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) {
390                 uint64_t per_bucket = 1ULL << (TIMER_LEVEL_BITS * l);
391
392                 off = ((timers->base >> (l*TIMER_LEVEL_BITS)) % PER_LEVEL);
393                 /* We start at *next* bucket. */
394                 base = (timers->base & ~(per_bucket - 1)) + per_bucket;
395
396                 for (i = 1; i <= PER_LEVEL; i++) {
397                         struct list_head *h;
398
399                         h = &timers->level[l]->list[(i+off) % PER_LEVEL];
400                         if (!timer_list_check(h, base, base + per_bucket - 1,
401                                               timers->firsts[l], abortstr))
402                                 return NULL;
403                         base += per_bucket;
404                 }
405         }
406
407 past_levels:
408         base = (timers->base & ~((1ULL << (TIMER_LEVEL_BITS * l)) - 1))
409                 + (1ULL << (TIMER_LEVEL_BITS * l)) - 1;
410         if (!timer_list_check(&timers->far, base, -1ULL,
411                               timers->firsts[ARRAY_SIZE(timers->level)],
412                               abortstr))
413                 return NULL;
414
415         return (struct timers *)timers;
416 }
417
418 #ifdef CCAN_TIMER_DEBUG
419 static void dump_bucket_stats(FILE *fp, const struct list_head *h)
420 {
421         unsigned long long min, max, num;
422         struct timer *t;
423
424         if (list_empty(h)) {
425                 printf("\n");
426                 return;
427         }
428
429         min = -1ULL;
430         max = 0;
431         num = 0;
432         list_for_each(h, t, list) {
433                 if (t->time < min)
434                         min = t->time;
435                 if (t->time > max)
436                         max = t->time;
437                 num++;
438         }
439         fprintf(fp, " %llu (%llu-%llu)\n",
440                 num, min, max);
441 }
442
443 void timers_dump(const struct timers *timers, FILE *fp)
444 {
445         unsigned int l, i, off;
446         unsigned long long base;
447
448         if (!fp)
449                 fp = stderr;
450
451         fprintf(fp, "Base: %llu\n", (unsigned long long)timers->base);
452
453         if (!timers->level[0])
454                 goto past_levels;
455
456         fprintf(fp, "Level 0:\n");
457
458         /* First level is simple. */
459         off = timers->base % PER_LEVEL;
460         for (i = 0; i < PER_LEVEL; i++) {
461                 const struct list_head *h;
462
463                 fprintf(fp, "  Bucket %llu (%lu):",
464                         (i+off) % PER_LEVEL, timers->base + i);
465                 h = &timers->level[0]->list[(i+off) % PER_LEVEL];
466                 dump_bucket_stats(fp, h);
467         }
468
469         /* For other levels, "current" bucket has been emptied, and may contain
470          * entries for the current + level_size bucket. */
471         for (l = 1; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) {
472                 uint64_t per_bucket = 1ULL << (TIMER_LEVEL_BITS * l);
473
474                 off = ((timers->base >> (l*TIMER_LEVEL_BITS)) % PER_LEVEL);
475                 /* We start at *next* bucket. */
476                 base = (timers->base & ~(per_bucket - 1)) + per_bucket;
477
478                 fprintf(fp, "Level %u:\n", l);
479                 for (i = 1; i <= PER_LEVEL; i++) {
480                         const struct list_head *h;
481
482                         fprintf(fp, "  Bucket %llu (%llu - %llu):",
483                                 (i+off) % PER_LEVEL,
484                                 base, base + per_bucket - 1);
485
486                         h = &timers->level[l]->list[(i+off) % PER_LEVEL];
487                         dump_bucket_stats(fp, h);
488                         base += per_bucket;
489                 }
490         }
491
492 past_levels:
493         if (!list_empty(&timers->far)) {
494                 fprintf(fp, "Far timers:");
495                 dump_bucket_stats(fp, &timers->far);
496         }
497 }
498 #endif
499
500 void timers_cleanup(struct timers *timers)
501 {
502         unsigned int l;
503
504         for (l = 0; l < ARRAY_SIZE(timers->level); l++)
505                 free(timers->level[l]);
506 }