test-timers.c (4023B)
1 /* Copyright 2016-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 #include "orconfig.h" 5 6 #include <math.h> 7 #include <stdio.h> 8 #include <string.h> 9 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" 17 18 #define N_TIMERS 1000 19 #define MAX_DURATION 30 20 #define N_DISABLE 5 21 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}; 27 28 static int n_active_timers = 0; 29 static int n_fired = 0; 30 31 static monotime_t started_at; 32 static int64_t delay_usec[N_TIMERS]; 33 static int64_t diffs_mono_usec[N_TIMERS]; 34 35 static void 36 timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono) 37 { 38 struct timeval now; 39 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; 50 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()); 54 } 55 } 56 57 int 58 main(int argc, char **argv) 59 { 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); 67 68 if (crypto_global_init(0, NULL, NULL) < 0) 69 return 1; 70 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; 85 } 86 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; 95 } 96 97 tor_libevent_run_event_loop(tor_libevent_get_base(), 0); 98 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; 106 } 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; 112 } 113 const int64_t mean_diff = total_difference / n_active_timers; 114 printf("mean difference: %"PRId64" usec\n", 115 (mean_diff)); 116 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); 121 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) 126 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; 138 } 139 140 timer_free_(NULL); 141 142 for (i = 0; i < N_TIMERS; ++i) { 143 timer_free(timers[i]); 144 } 145 timers_shutdown(); 146 return ret; 147 }