TOR_VEGAS: Implement Prop#324 TOR_VEGAS.
[tor.git] / src / test / test-timers.c
blobb2ba58b9dd6feb19894e051dcc0be3aeb5009763
1 /* Copyright 2016-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include "orconfig.h"
6 #include <math.h>
7 #include <stdio.h>
8 #include <string.h>
10 #include "lib/evloop/compat_libevent.h"
11 #include "lib/evloop/timers.h"
12 #include "lib/crypt_ops/crypto_init.h"
13 #include "lib/crypt_ops/crypto_rand.h"
14 #include "lib/log/util_bug.h"
15 #include "lib/time/compat_time.h"
16 #include "lib/wallclock/timeval.h"
18 #define N_TIMERS 1000
19 #define MAX_DURATION 30
20 #define N_DISABLE 5
22 static struct timeval fire_at[N_TIMERS] = { {0,0} };
23 static int is_disabled[N_TIMERS] = {0};
24 static int fired[N_TIMERS] = {0};
25 static struct timeval difference[N_TIMERS] = { {0,0} };
26 static tor_timer_t *timers[N_TIMERS] = {NULL};
28 static int n_active_timers = 0;
29 static int n_fired = 0;
31 static monotime_t started_at;
32 static int64_t delay_usec[N_TIMERS];
33 static int64_t diffs_mono_usec[N_TIMERS];
35 static void
36 timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono)
38 struct timeval now;
40 tor_gettimeofday(&now);
41 tor_timer_t **t_ptr = arg;
42 tor_assert(*t_ptr == t);
43 int idx = (int) (t_ptr - timers);
44 ++fired[idx];
45 timersub(&now, &fire_at[idx], &difference[idx]);
46 diffs_mono_usec[idx] =
47 monotime_diff_usec(&started_at, now_mono) -
48 delay_usec[idx];
49 ++n_fired;
51 // printf("%d / %d\n",n_fired, N_TIMERS);
52 if (n_fired == n_active_timers) {
53 tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
57 int
58 main(int argc, char **argv)
60 (void)argc;
61 (void)argv;
62 tor_libevent_cfg_t cfg;
63 memset(&cfg, 0, sizeof(cfg));
64 tor_libevent_initialize(&cfg);
65 timers_initialize();
66 init_logging(1);
68 if (crypto_global_init(0, NULL, NULL) < 0)
69 return 1;
71 int i;
72 int ret;
73 struct timeval now;
74 tor_gettimeofday(&now);
75 monotime_get(&started_at);
76 for (i = 0; i < N_TIMERS; ++i) {
77 struct timeval delay;
78 delay.tv_sec = crypto_rand_int_range(0,MAX_DURATION);
79 delay.tv_usec = crypto_rand_int_range(0,1000000);
80 delay_usec[i] = delay.tv_sec * 1000000 + delay.tv_usec;
81 timeradd(&now, &delay, &fire_at[i]);
82 timers[i] = timer_new(timer_cb, &timers[i]);
83 timer_schedule(timers[i], &delay);
84 ++n_active_timers;
87 /* Disable some; we'll make sure they don't trigger. */
88 for (i = 0; i < N_DISABLE; ++i) {
89 int idx = crypto_rand_int_range(0, N_TIMERS);
90 if (is_disabled[idx])
91 continue;
92 is_disabled[idx] = 1;
93 timer_disable(timers[idx]);
94 --n_active_timers;
97 tor_libevent_run_event_loop(tor_libevent_get_base(), 0);
99 int64_t total_difference = 0;
100 uint64_t total_square_difference = 0;
101 tor_assert(n_fired == n_active_timers);
102 for (i = 0; i < N_TIMERS; ++i) {
103 if (is_disabled[i]) {
104 tor_assert(fired[i] == 0);
105 continue;
107 tor_assert(fired[i] == 1);
108 //int64_t diff = difference[i].tv_usec + difference[i].tv_sec * 1000000;
109 int64_t diff = diffs_mono_usec[i];
110 total_difference += diff;
111 total_square_difference += diff*diff;
113 const int64_t mean_diff = total_difference / n_active_timers;
114 printf("mean difference: %"PRId64" usec\n",
115 (mean_diff));
117 const double mean_sq = ((double)total_square_difference)/ n_active_timers;
118 const double sq_mean = mean_diff * mean_diff;
119 const double stddev = sqrt(mean_sq - sq_mean);
120 printf("standard deviation: %lf usec\n", stddev);
122 #define MAX_DIFF_USEC (500*1000)
123 #define MAX_STDDEV_USEC (500*1000)
124 #define ODD_DIFF_USEC (2000)
125 #define ODD_STDDEV_USEC (2000)
127 if (mean_diff < 0 || mean_diff > MAX_DIFF_USEC || stddev > MAX_STDDEV_USEC) {
128 printf("Either your system is under ridiculous load, or the "
129 "timer backend is broken.\n");
130 ret = 1;
131 } else if (mean_diff > ODD_DIFF_USEC || stddev > ODD_STDDEV_USEC) {
132 printf("Either your system is a bit slow or the "
133 "timer backend is odd.\n");
134 ret = 0;
135 } else {
136 printf("Looks good enough.\n");
137 ret = 0;
140 timer_free_(NULL);
142 for (i = 0; i < N_TIMERS; ++i) {
143 timer_free(timers[i]);
145 timers_shutdown();
146 return ret;