}
#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