--- /dev/null
+/* We expect a timer to rarely go off, so benchmark that case:
+ * Every 1ms a connection comes in, we set up a 30 second timer for it.
+ * After 8192ms we finish the connection (and thus delete the timer).
+ */
+#include <ccan/timer/timer.h>
+#include <ccan/opt/opt.h>
+#include <ccan/array_size/array_size.h>
+#include <stdio.h>
+
+#define PER_CONN_TIME 8192
+#define CONN_TIMEOUT_MS 30000
+
+int main(int argc, char *argv[])
+{
+ struct timespec start, curr;
+ struct timers timers;
+ struct list_head expired;
+ struct timer t[PER_CONN_TIME];
+ unsigned int i, num;
+ bool check = false;
+
+ opt_register_noarg("-c|--check", opt_set_bool, &check,
+ "Check timer structure during progress");
+
+ opt_parse(&argc, argv, opt_log_stderr_exit);
+
+ num = argv[1] ? atoi(argv[1]) : (check ? 10000 : 1000000);
+
+ list_head_init(&expired);
+ curr = start = time_now();
+ timers_init(&timers, start);
+
+ for (i = 0; i < num; i++) {
+ curr = time_add(curr, time_from_msec(1));
+ if (check)
+ timers_check(&timers, NULL);
+ timers_expire(&timers, curr, &expired);
+ if (check)
+ timers_check(&timers, NULL);
+ assert(list_empty(&expired));
+
+ if (i >= PER_CONN_TIME) {
+ timer_del(&timers, &t[i%PER_CONN_TIME]);
+ if (check)
+ timers_check(&timers, NULL);
+ }
+ timer_add(&timers, &t[i%PER_CONN_TIME],
+ time_add(curr, time_from_msec(CONN_TIMEOUT_MS)));
+ if (check)
+ timers_check(&timers, NULL);
+ }
+ if (num > PER_CONN_TIME) {
+ for (i = 0; i < PER_CONN_TIME; i++)
+ timer_del(&timers, &t[i]);
+ }
+
+ curr = time_sub(time_now(), start);
+ if (check)
+ timers_check(&timers, NULL);
+ timers_cleanup(&timers);
+ opt_free_table();
+
+ for (i = 0; i < ARRAY_SIZE(timers.level); i++)
+ if (!timers.level[i])
+ break;
+
+ printf("%u in %lu.%09lu (%u levels / %zu)\n",
+ num, (long)curr.tv_sec, curr.tv_nsec,
+ i, ARRAY_SIZE(timers.level));
+ return 0;
+}