aboutsummaryrefslogtreecommitdiff
path: root/src/test/test-timers.c
blob: c80fb1e3051627c1e547c697461ea78db42ecb87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* Copyright 2016-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */

#include "orconfig.h"

#include <math.h>
#include <stdio.h>
#include <string.h>

#include "lib/evloop/compat_libevent.h"
#include "lib/evloop/timers.h"
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/log/util_bug.h"
#include "lib/time/compat_time.h"
#include "lib/wallclock/timeval.h"

#define N_TIMERS 1000
#define MAX_DURATION 30
#define N_DISABLE 5

static struct timeval fire_at[N_TIMERS] = { {0,0} };
static int is_disabled[N_TIMERS] = {0};
static int fired[N_TIMERS] = {0};
static struct timeval difference[N_TIMERS] = { {0,0} };
static tor_timer_t *timers[N_TIMERS] = {NULL};

static int n_active_timers = 0;
static int n_fired = 0;

static monotime_t started_at;
static int64_t delay_usec[N_TIMERS];
static int64_t diffs_mono_usec[N_TIMERS];

static void
timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono)
{
  struct timeval now;

  tor_gettimeofday(&now);
  tor_timer_t **t_ptr = arg;
  tor_assert(*t_ptr == t);
  int idx = (int) (t_ptr - timers);
  ++fired[idx];
  timersub(&now, &fire_at[idx], &difference[idx]);
  diffs_mono_usec[idx] =
    monotime_diff_usec(&started_at, now_mono) -
    delay_usec[idx];
  ++n_fired;

  // printf("%d / %d\n",n_fired, N_TIMERS);
  if (n_fired == n_active_timers) {
    tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
  }
}

int
main(int argc, char **argv)
{
  (void)argc;
  (void)argv;
  tor_libevent_cfg cfg;
  memset(&cfg, 0, sizeof(cfg));
  tor_libevent_initialize(&cfg);
  timers_initialize();
  init_logging(1);

  if (crypto_global_init(0, NULL, NULL) < 0)
    return 1;

  int i;
  int ret;
  struct timeval now;
  tor_gettimeofday(&now);
  monotime_get(&started_at);
  for (i = 0; i < N_TIMERS; ++i) {
    struct timeval delay;
    delay.tv_sec = crypto_rand_int_range(0,MAX_DURATION);
    delay.tv_usec = crypto_rand_int_range(0,1000000);
    delay_usec[i] = delay.tv_sec * 1000000 + delay.tv_usec;
    timeradd(&now, &delay, &fire_at[i]);
    timers[i] = timer_new(timer_cb, &timers[i]);
    timer_schedule(timers[i], &delay);
    ++n_active_timers;
  }

  /* Disable some; we'll make sure they don't trigger. */
  for (i = 0; i < N_DISABLE; ++i) {
    int idx = crypto_rand_int_range(0, N_TIMERS);
    if (is_disabled[idx])
      continue;
    is_disabled[idx] = 1;
    timer_disable(timers[idx]);
    --n_active_timers;
  }

  tor_libevent_run_event_loop(tor_libevent_get_base(), 0);

  int64_t total_difference = 0;
  uint64_t total_square_difference = 0;
  tor_assert(n_fired == n_active_timers);
  for (i = 0; i < N_TIMERS; ++i) {
    if (is_disabled[i]) {
      tor_assert(fired[i] == 0);
      continue;
    }
    tor_assert(fired[i] == 1);
    //int64_t diff = difference[i].tv_usec + difference[i].tv_sec * 1000000;
    int64_t diff = diffs_mono_usec[i];
    total_difference += diff;
    total_square_difference += diff*diff;
  }
  const int64_t mean_diff = total_difference / n_active_timers;
  printf("mean difference: %"PRId64" usec\n",
         (mean_diff));

  const double mean_sq = ((double)total_square_difference)/ n_active_timers;
  const double sq_mean = mean_diff * mean_diff;
  const double stddev = sqrt(mean_sq - sq_mean);
  printf("standard deviation: %lf usec\n", stddev);

#define MAX_DIFF_USEC (500*1000)
#define MAX_STDDEV_USEC (500*1000)
#define ODD_DIFF_USEC (2000)
#define ODD_STDDEV_USEC (2000)

  if (mean_diff < 0 || mean_diff > MAX_DIFF_USEC || stddev > MAX_STDDEV_USEC) {
    printf("Either your system is under ridiculous load, or the "
           "timer backend is broken.\n");
    ret = 1;
  } else if (mean_diff > ODD_DIFF_USEC || stddev > ODD_STDDEV_USEC) {
    printf("Either your system is a bit slow or the "
           "timer backend is odd.\n");
    ret = 0;
  } else {
    printf("Looks good enough.\n");
    ret = 0;
  }

  timer_free_(NULL);

  for (i = 0; i < N_TIMERS; ++i) {
    timer_free(timers[i]);
  }
  timers_shutdown();
  return ret;
}