]> git.ozlabs.org Git - ccan/blobdiff - ccan/timer/timer.c
timer: better dump code.
[ccan] / ccan / timer / timer.c
index 0d7deb127748b3130a1270f75ebc6ecec1fbf583..f0e017ba6ed8decba4ac4abcf0ecce07f01abf48 100644 (file)
@@ -389,50 +389,84 @@ past_levels:
 }
 
 #ifdef CCAN_TIMER_DEBUG
-void timers_dump(const struct timers *timers, FILE *fp)
+static void dump_bucket_stats(FILE *fp, const struct list_head *h)
 {
-       unsigned int l, i;
-       uint64_t min, max, num;
+       unsigned long long min, max, num;
        struct timer *t;
 
-       if (!fp)
-               fp = stderr;
-
-       fprintf(fp, "Base: %llu\n", timers->base);
-
-       for (l = 0; timers->level[l] && l < ARRAY_SIZE(timers->level); l++) {
-               fprintf(fp, "Level %i (+%llu):\n",
-                       l, (uint64_t)1 << (TIMER_LEVEL_BITS * l));
-               for (i = 0; i < (1 << TIMER_LEVEL_BITS); i++) {
-
-                       if (list_empty(&timers->level[l]->list[i]))
-                               continue;
-                       min = -1ULL;
-                       max = 0;
-                       num = 0;
-                       list_for_each(&timers->level[l]->list[i], t, list) {
-                               if (t->time < min)
-                                       min = t->time;
-                               if (t->time > max)
-                                       max = t->time;
-                               num++;
-                       }
-                       fprintf(stderr, "  %llu (+%llu-+%llu)\n",
-                               num, min - timers->base, max - timers->base);
-               }
+       if (list_empty(h)) {
+               printf("\n");
+               return;
        }
 
        min = -1ULL;
        max = 0;
        num = 0;
-       list_for_each(&timers->far, t, list) {
+       list_for_each(h, t, list) {
                if (t->time < min)
                        min = t->time;
                if (t->time > max)
                        max = t->time;
                num++;
        }
-       fprintf(stderr, "Far: %llu (%llu-%llu)\n", num, min, max);
+       fprintf(fp, " %llu (%llu-%llu)\n",
+               num, min, max);
+}
+
+void timers_dump(const struct timers *timers, FILE *fp)
+{
+       unsigned int l, i, off;
+       unsigned long long base;
+
+       if (!fp)
+               fp = stderr;
+
+       fprintf(fp, "Base: %llu\n", (unsigned long long)timers->base);
+
+       if (!timers->level[0])
+               goto past_levels;
+
+       fprintf(fp, "Level 0:\n");
+
+       /* First level is simple. */
+       off = timers->base % PER_LEVEL;
+       for (i = 0; i < PER_LEVEL; i++) {
+               const struct list_head *h;
+
+               fprintf(fp, "  Bucket %llu (%lu):",
+                       (i+off) % PER_LEVEL, timers->base + i);
+               h = &timers->level[0]->list[(i+off) % PER_LEVEL];
+               dump_bucket_stats(fp, h);
+       }
+
+       /* For other levels, "current" bucket has been emptied, and may contain
+        * entries for the current + level_size bucket. */
+       for (l = 1; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) {
+               uint64_t per_bucket = 1ULL << (TIMER_LEVEL_BITS * l);
+
+               off = ((timers->base >> (l*TIMER_LEVEL_BITS)) % PER_LEVEL);
+               /* We start at *next* bucket. */
+               base = (timers->base & ~(per_bucket - 1)) + per_bucket;
+
+               fprintf(fp, "Level %u:\n", l);
+               for (i = 1; i <= PER_LEVEL; i++) {
+                       const struct list_head *h;
+
+                       fprintf(fp, "  Bucket %llu (%llu - %llu):",
+                               (i+off) % PER_LEVEL,
+                               base, base + per_bucket - 1);
+
+                       h = &timers->level[l]->list[(i+off) % PER_LEVEL];
+                       dump_bucket_stats(fp, h);
+                       base += per_bucket;
+               }
+       }
+
+past_levels:
+       if (!list_empty(&timers->far)) {
+               fprintf(fp, "Far timers:");
+               dump_bucket_stats(fp, &timers->far);
+       }
 }
 #endif