Line data Source code
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 995 : timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono) 37 : { 38 995 : struct timeval now; 39 : 40 995 : tor_gettimeofday(&now); 41 995 : tor_timer_t **t_ptr = arg; 42 995 : tor_assert(*t_ptr == t); 43 995 : int idx = (int) (t_ptr - timers); 44 995 : ++fired[idx]; 45 995 : timersub(&now, &fire_at[idx], &difference[idx]); 46 1990 : diffs_mono_usec[idx] = 47 995 : monotime_diff_usec(&started_at, now_mono) - 48 995 : delay_usec[idx]; 49 995 : ++n_fired; 50 : 51 : // printf("%d / %d\n",n_fired, N_TIMERS); 52 995 : if (n_fired == n_active_timers) { 53 1 : tor_libevent_exit_loop_after_callback(tor_libevent_get_base()); 54 : } 55 995 : } 56 : 57 : int 58 1 : main(int argc, char **argv) 59 : { 60 1 : (void)argc; 61 1 : (void)argv; 62 1 : tor_libevent_cfg_t cfg; 63 1 : memset(&cfg, 0, sizeof(cfg)); 64 1 : tor_libevent_initialize(&cfg); 65 1 : timers_initialize(); 66 1 : init_logging(1); 67 : 68 1 : if (crypto_global_init(0, NULL, NULL) < 0) 69 : return 1; 70 : 71 1 : int i; 72 1 : int ret; 73 1 : struct timeval now; 74 1 : tor_gettimeofday(&now); 75 1 : monotime_get(&started_at); 76 1002 : for (i = 0; i < N_TIMERS; ++i) { 77 1000 : struct timeval delay; 78 1000 : delay.tv_sec = crypto_rand_int_range(0,MAX_DURATION); 79 1000 : delay.tv_usec = crypto_rand_int_range(0,1000000); 80 1000 : delay_usec[i] = delay.tv_sec * 1000000 + delay.tv_usec; 81 1000 : timeradd(&now, &delay, &fire_at[i]); 82 1000 : timers[i] = timer_new(timer_cb, &timers[i]); 83 1000 : timer_schedule(timers[i], &delay); 84 1000 : ++n_active_timers; 85 : } 86 : 87 : /* Disable some; we'll make sure they don't trigger. */ 88 6 : for (i = 0; i < N_DISABLE; ++i) { 89 5 : int idx = crypto_rand_int_range(0, N_TIMERS); 90 5 : if (is_disabled[idx]) 91 0 : continue; 92 5 : is_disabled[idx] = 1; 93 5 : timer_disable(timers[idx]); 94 5 : --n_active_timers; 95 : } 96 : 97 1 : tor_libevent_run_event_loop(tor_libevent_get_base(), 0); 98 : 99 1 : int64_t total_difference = 0; 100 1 : uint64_t total_square_difference = 0; 101 1 : tor_assert(n_fired == n_active_timers); 102 1001 : for (i = 0; i < N_TIMERS; ++i) { 103 1000 : if (is_disabled[i]) { 104 5 : tor_assert(fired[i] == 0); 105 5 : continue; 106 : } 107 995 : tor_assert(fired[i] == 1); 108 : //int64_t diff = difference[i].tv_usec + difference[i].tv_sec * 1000000; 109 995 : int64_t diff = diffs_mono_usec[i]; 110 995 : total_difference += diff; 111 995 : total_square_difference += diff*diff; 112 : } 113 1 : const int64_t mean_diff = total_difference / n_active_timers; 114 1 : printf("mean difference: %"PRId64" usec\n", 115 : (mean_diff)); 116 : 117 1 : const double mean_sq = ((double)total_square_difference)/ n_active_timers; 118 1 : const double sq_mean = mean_diff * mean_diff; 119 1 : const double stddev = sqrt(mean_sq - sq_mean); 120 1 : 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 1 : if (mean_diff < 0 || mean_diff > MAX_DIFF_USEC || stddev > MAX_STDDEV_USEC) { 128 0 : printf("Either your system is under ridiculous load, or the " 129 : "timer backend is broken.\n"); 130 0 : ret = 1; 131 1 : } else if (mean_diff > ODD_DIFF_USEC || stddev > ODD_STDDEV_USEC) { 132 1 : printf("Either your system is a bit slow or the " 133 : "timer backend is odd.\n"); 134 1 : ret = 0; 135 : } else { 136 0 : printf("Looks good enough.\n"); 137 0 : ret = 0; 138 : } 139 : 140 1 : timer_free_(NULL); 141 : 142 1002 : for (i = 0; i < N_TIMERS; ++i) { 143 1000 : timer_free(timers[i]); 144 : } 145 1 : timers_shutdown(); 146 1 : return ret; 147 : }