Commit 2258125e authored by Mike Perry's avatar Mike Perry
Browse files

Move CBT params into consensus.

parent f459388c
Loading
Loading
Loading
Loading
+147 −53
Original line number Diff line number Diff line
@@ -79,6 +79,92 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);

static void entry_guards_changed(void);

static int32_t
circuit_build_times_max_timeouts(void)
{
  int32_t num = networkstatus_get_param(NULL, "cbtmaxtimeouts",
          CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT);
  return num;
}

static int32_t
circuit_build_times_min_circs_to_observe(void)
{
  int32_t num = networkstatus_get_param(NULL, "cbtmincircs",
                CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE);
  return num;
}

double
circuit_build_times_quantile_cutoff(void)
{
  int32_t num = networkstatus_get_param(NULL, "cbtquantile",
                CBT_DEFAULT_QUANTILE_CUTOFF);
  return num/100.0;
}

static int32_t
circuit_build_times_test_frequency(void)
{
  int32_t num = networkstatus_get_param(NULL, "cbttestfreq",
                CBT_DEFAULT_TEST_FREQUENCY);
  return num;
}

static int32_t
circuit_build_times_min_timeout(void)
{
  int32_t num = networkstatus_get_param(NULL, "cbtmintimeout",
                CBT_DEFAULT_TIMEOUT_MIN_VALUE);
  return num;
}

int32_t
circuit_build_times_initial_timeout(void)
{
  int32_t num = networkstatus_get_param(NULL, "cbtinitialtimeout",
                CBT_DEFAULT_TIMEOUT_INITIAL_VALUE);
  return num;
}

static int32_t
circuit_build_times_recent_circuit_count(void)
{
  int32_t num = networkstatus_get_param(NULL, "cbtrecentcount",
                CBT_DEFAULT_RECENT_CIRCUITS);
  return num;
}

void
circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
                                         networkstatus_t *ns)
{
  int32_t num = networkstatus_get_param(ns, "cbtrecentcount",
                   CBT_DEFAULT_RECENT_CIRCUITS);

  if (num != cbt->liveness.num_recent_circs) {
    int8_t *recent_circs;
    log_notice(LD_CIRC, "Changing recent timeout size from %d to %d",
               cbt->liveness.num_recent_circs, num);

    tor_assert(num > 0);
    tor_assert(cbt->liveness.timeouts_after_firsthop);
    recent_circs = tor_malloc_zero(sizeof(int8_t)*num);
    memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop,
           sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs));

    // Adjust the index if it needs it.
    if (num < cbt->liveness.num_recent_circs) {
      cbt->liveness.after_firsthop_idx = MIN(num-1,
              cbt->liveness.after_firsthop_idx);
    }

    tor_free(cbt->liveness.timeouts_after_firsthop);
    cbt->liveness.timeouts_after_firsthop = recent_circs;
    cbt->liveness.num_recent_circs = num;
  }
}

/** Make a note that we're running unit tests (rather than running Tor
 * itself), so we avoid clobbering our state file. */
void
@@ -96,13 +182,13 @@ circuit_build_times_get_initial_timeout(void)
  double timeout;
  if (!unit_tests && get_options()->CircuitBuildTimeout) {
    timeout = get_options()->CircuitBuildTimeout*1000;
    if (timeout < BUILD_TIMEOUT_MIN_VALUE) {
    if (timeout < circuit_build_times_min_timeout()) {
      log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
               BUILD_TIMEOUT_MIN_VALUE/1000);
      timeout = BUILD_TIMEOUT_MIN_VALUE;
               circuit_build_times_min_timeout()/1000);
      timeout = circuit_build_times_min_timeout();
    }
  } else {
    timeout = BUILD_TIMEOUT_INITIAL_VALUE;
    timeout = circuit_build_times_initial_timeout();
  }
  return timeout;
}
@@ -133,6 +219,9 @@ void
circuit_build_times_init(circuit_build_times_t *cbt)
{
  memset(cbt, 0, sizeof(*cbt));
  cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count();
  cbt->liveness.timeouts_after_firsthop = tor_malloc_zero(sizeof(int8_t)*
                                      cbt->liveness.num_recent_circs);
  cbt->timeout_ms = circuit_build_times_get_initial_timeout();
  control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
}
@@ -162,10 +251,11 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
  }

  cbt->build_times_idx -= n;
  cbt->build_times_idx %= NCIRCUITS_TO_OBSERVE;
  cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE;

  for (i = 0; i < n; i++) {
    cbt->circuit_build_times[(i+cbt->build_times_idx)%NCIRCUITS_TO_OBSERVE]=0;
    cbt->circuit_build_times[(i+cbt->build_times_idx)
                             %CBT_NCIRCUITS_TO_OBSERVE]=0;
  }

  if (cbt->total_build_times > n) {
@@ -189,7 +279,7 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
int
circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
{
  tor_assert(time <= BUILD_TIME_MAX);
  tor_assert(time <= CBT_BUILD_TIME_MAX);
  if (time <= 0) {
    log_warn(LD_CIRC, "Circuit build time is %u!", time);
    return -1;
@@ -199,11 +289,11 @@ circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
  log_info(LD_CIRC, "Adding circuit build time %u", time);

  cbt->circuit_build_times[cbt->build_times_idx] = time;
  cbt->build_times_idx = (cbt->build_times_idx + 1) % NCIRCUITS_TO_OBSERVE;
  if (cbt->total_build_times < NCIRCUITS_TO_OBSERVE)
  cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE;
  if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
    cbt->total_build_times++;

  if ((cbt->total_build_times % BUILD_TIMES_SAVE_STATE_EVERY) == 0) {
  if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) {
    /* Save state every n circuit builds */
    if (!unit_tests && !get_options()->AvoidDiskWrites)
      or_state_mark_dirty(get_or_state(), 0);
@@ -220,7 +310,7 @@ circuit_build_times_max(circuit_build_times_t *cbt)
{
  int i = 0;
  build_time_t max_build_time = 0;
  for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
  for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
    if (cbt->circuit_build_times[i] > max_build_time)
      max_build_time = cbt->circuit_build_times[i];
  }
@@ -233,14 +323,14 @@ build_time_t
circuit_build_times_min(circuit_build_times_t *cbt)
{
  int i = 0;
  build_time_t min_build_time = BUILD_TIME_MAX;
  for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
  build_time_t min_build_time = CBT_BUILD_TIME_MAX;
  for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
    if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */
        cbt->circuit_build_times[i] < min_build_time)
      min_build_time = cbt->circuit_build_times[i];
  }
  if (min_build_time == BUILD_TIME_MAX) {
    log_warn(LD_CIRC, "No build times less than BUILD_TIME_MAX!");
  if (min_build_time == CBT_BUILD_TIME_MAX) {
    log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!");
  }
  return min_build_time;
}
@@ -250,7 +340,7 @@ circuit_build_times_min(circuit_build_times_t *cbt)
 * Calculate and return a histogram for the set of build times.
 *
 * Returns an allocated array of histrogram bins representing
 * the frequency of index*BUILDTIME_BIN_WIDTH millisecond
 * the frequency of index*CBT_BIN_WIDTH millisecond
 * build times. Also outputs the number of bins in nbins.
 *
 * The return value must be freed by the caller.
@@ -263,14 +353,14 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt,
  build_time_t max_build_time = circuit_build_times_max(cbt);
  int i, c;

  *nbins = 1 + (max_build_time / BUILDTIME_BIN_WIDTH);
  *nbins = 1 + (max_build_time / CBT_BIN_WIDTH);
  histogram = tor_malloc_zero(*nbins * sizeof(build_time_t));

  // calculate histogram
  for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
  for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
    if (cbt->circuit_build_times[i] == 0) continue; /* 0 <-> uninitialized */

    c = (cbt->circuit_build_times[i] / BUILDTIME_BIN_WIDTH);
    c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH);
    histogram[c]++;
  }

@@ -278,7 +368,7 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt,
}

/**
 * Return the most frequent build time (rounded to BUILDTIME_BIN_WIDTH ms).
 * Return the most frequent build time (rounded to CBT_BIN_WIDTH ms).
 *
 * Ties go in favor of the slower time.
 */
@@ -296,7 +386,7 @@ circuit_build_times_mode(circuit_build_times_t *cbt)

  tor_free(histogram);

  return max_bin*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2;
  return max_bin*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2;
}

/**
@@ -327,7 +417,7 @@ circuit_build_times_update_state(circuit_build_times_t *cbt,
    line->key = tor_strdup("CircuitBuildTimeBin");
    line->value = tor_malloc(25);
    tor_snprintf(line->value, 25, "%d %d",
            i*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2, histogram[i]);
            i*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2, histogram[i]);
    next = &(line->next);
  }

@@ -350,9 +440,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
                                            int num_times)
{
  int n = num_times;
  if (num_times > NCIRCUITS_TO_OBSERVE) {
  if (num_times > CBT_NCIRCUITS_TO_OBSERVE) {
    log_notice(LD_CIRC, "Decreasing circuit_build_times size from %d to %d",
               num_times, NCIRCUITS_TO_OBSERVE);
               num_times, CBT_NCIRCUITS_TO_OBSERVE);
  }

  /* This code can only be run on a compact array */
@@ -363,9 +453,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
    raw_times[n] = tmp;
  }

  /* Since the times are now shuffled, take a random NCIRCUITS_TO_OBSERVE
   * subset (ie the first NCIRCUITS_TO_OBSERVE values) */
  for (n = 0; n < MIN(num_times, NCIRCUITS_TO_OBSERVE); n++) {
  /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE
   * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */
  for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) {
    circuit_build_times_add_time(cbt, raw_times[n]);
  }
}
@@ -407,7 +497,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
      build_time_t ms;
      int ok;
      ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0,
                                         BUILD_TIME_MAX, &ok, NULL);
                                         CBT_BUILD_TIME_MAX, &ok, NULL);
      if (!ok) {
        *msg = tor_strdup("Unable to parse circuit build times: "
                          "Unparsable bin number");
@@ -453,7 +543,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
  circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt);

  /* Verify that we didn't overwrite any indexes */
  for (i=0; i < NCIRCUITS_TO_OBSERVE; i++) {
  for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
    if (!cbt->circuit_build_times[i])
      break;
    tot_values++;
@@ -462,7 +552,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
           "Loaded %d/%d values from %d lines in circuit time histogram",
           tot_values, cbt->total_build_times, N);
  tor_assert(cbt->total_build_times == tot_values);
  tor_assert(cbt->total_build_times <= NCIRCUITS_TO_OBSERVE);
  tor_assert(cbt->total_build_times <= CBT_NCIRCUITS_TO_OBSERVE);
  circuit_build_times_set_timeout(cbt);
  tor_free(loaded_times);
  return *msg ? -1 : 0;
@@ -489,7 +579,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
   * and less frechet-like. */
  cbt->Xm = circuit_build_times_mode(cbt);

  for (i=0; i< NCIRCUITS_TO_OBSERVE; i++) {
  for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) {
    if (!x[i]) {
      continue;
    }
@@ -598,18 +688,18 @@ circuit_build_times_add_timeout_worker(circuit_build_times_t *cbt,
  // Keep getting values for the largest timeout bucket over and over
  // again... Probably because alpha is very very large in that case..
  build_time_t gentime = circuit_build_times_generate_sample(cbt,
              quantile_cutoff, MAX_SYNTHETIC_QUANTILE);
              quantile_cutoff, CBT_MAX_SYNTHETIC_QUANTILE);

  if (gentime < (build_time_t)tor_lround(cbt->timeout_ms)) {
    log_warn(LD_CIRC,
             "Generated a synthetic timeout LESS than the current timeout: "
             "%ums vs %lfms using Xm: %d a: %lf, q: %lf",
             gentime, cbt->timeout_ms, cbt->Xm, cbt->alpha, quantile_cutoff);
  } else if (gentime > BUILD_TIME_MAX) {
  } else if (gentime > CBT_BUILD_TIME_MAX) {
    log_info(LD_CIRC,
             "Generated a synthetic timeout larger than the max: %u",
             gentime);
    gentime = BUILD_TIME_MAX;
    gentime = CBT_BUILD_TIME_MAX;
  } else {
    log_info(LD_CIRC, "Generated synthetic circuit build time %u for timeout",
            gentime);
@@ -653,7 +743,7 @@ circuit_build_times_count_pretimeouts(circuit_build_times_t *cbt)
          ((double)cbt->pre_timeouts)/
                    (cbt->pre_timeouts+cbt->total_build_times);
    /* Make sure it doesn't exceed the synthetic max */
    timeout_quantile *= MAX_SYNTHETIC_QUANTILE;
    timeout_quantile *= CBT_MAX_SYNTHETIC_QUANTILE;
    cbt->Xm = circuit_build_times_mode(cbt);
    tor_assert(cbt->Xm > 0);
    /* Use current timeout to get an estimate on alpha */
@@ -673,7 +763,7 @@ int
circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
{
  /* Return true if < MIN_CIRCUITS_TO_OBSERVE */
  if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE)
  if (cbt->total_build_times < circuit_build_times_min_circs_to_observe())
    return 1;
  return 0;
}
@@ -686,7 +776,7 @@ int
circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt)
{
  return circuit_build_times_needs_circuits(cbt) &&
    approx_time()-cbt->last_circ_at > BUILD_TIMES_TEST_FREQUENCY;
    approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency();
}

/**
@@ -712,7 +802,7 @@ circuit_build_times_network_circ_success(circuit_build_times_t *cbt)
{
  cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] = 0;
  cbt->liveness.after_firsthop_idx++;
  cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS;
  cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
}

/**
@@ -743,7 +833,7 @@ circuit_build_times_network_timeout(circuit_build_times_t *cbt,
    /* Count a one-hop timeout */
    cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]=1;
    cbt->liveness.after_firsthop_idx++;
    cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS;
    cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs;
  }
}

@@ -758,7 +848,7 @@ int
circuit_build_times_network_check_live(circuit_build_times_t *cbt)
{
  time_t now = approx_time();
  if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_DISCARD_COUNT) {
  if (cbt->liveness.nonlive_timeouts >= CBT_NETWORK_NONLIVE_DISCARD_COUNT) {
    if (!cbt->liveness.nonlive_discarded) {
      cbt->liveness.nonlive_discarded = 1;
      log_notice(LD_CIRC, "Network is no longer live (too many recent "
@@ -766,11 +856,13 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt)
                (long int)(now - cbt->liveness.network_last_live));
      /* Only discard NETWORK_NONLIVE_TIMEOUT_COUNT-1 because we stopped
       * counting after that */
      circuit_build_times_rewind_history(cbt, NETWORK_NONLIVE_TIMEOUT_COUNT-1);
      circuit_build_times_rewind_history(cbt,
                     CBT_NETWORK_NONLIVE_TIMEOUT_COUNT-1);
      control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_DISCARD);
    }
    return 0;
  } else if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_TIMEOUT_COUNT) {
  } else if (cbt->liveness.nonlive_timeouts >=
                CBT_NETWORK_NONLIVE_TIMEOUT_COUNT) {
    if (cbt->timeout_ms < circuit_build_times_get_initial_timeout()) {
      log_notice(LD_CIRC,
                "Network is flaky. No activity for %ld seconds. "
@@ -812,19 +904,20 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)

  /* how many of our recent circuits made it to the first hop but then
   * timed out? */
  for (i = 0; i < RECENT_CIRCUITS; i++) {
  for (i = 0; i < cbt->liveness.num_recent_circs; i++) {
    timeout_count += cbt->liveness.timeouts_after_firsthop[i];
  }

  /* If 80% of our recent circuits are timing out after the first hop,
   * we need to re-estimate a new initial alpha and timeout. */
  if (timeout_count < MAX_RECENT_TIMEOUT_COUNT) {
  if (timeout_count < circuit_build_times_max_timeouts()) {
    return 0;
  }

  circuit_build_times_reset(cbt);
  memset(cbt->liveness.timeouts_after_firsthop, 0,
          sizeof(cbt->liveness.timeouts_after_firsthop));
          sizeof(*cbt->liveness.timeouts_after_firsthop)*
          cbt->liveness.num_recent_circs);
  cbt->liveness.after_firsthop_idx = 0;

  /* Check to see if this has happened before. If so, double the timeout
@@ -875,13 +968,14 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt,
    cbt->pre_timeouts++;
    log_info(LD_CIRC,
             "Not enough circuits yet to calculate a new build timeout."
             " Need %d more.",
             MIN_CIRCUITS_TO_OBSERVE-cbt->total_build_times);
             " Need %d more.", circuit_build_times_min_circs_to_observe()
                               - cbt->total_build_times);
    return 0;
  }

  circuit_build_times_count_pretimeouts(cbt);
  circuit_build_times_add_timeout_worker(cbt, BUILDTIMEOUT_QUANTILE_CUTOFF);
  circuit_build_times_add_timeout_worker(cbt,
           circuit_build_times_quantile_cutoff());

  return 1;
}
@@ -893,7 +987,7 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt,
void
circuit_build_times_set_timeout(circuit_build_times_t *cbt)
{
  if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE) {
  if (cbt->total_build_times < circuit_build_times_min_circs_to_observe()) {
    return;
  }

@@ -901,14 +995,14 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
  circuit_build_times_update_alpha(cbt);

  cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt,
                                BUILDTIMEOUT_QUANTILE_CUTOFF);
                                circuit_build_times_quantile_cutoff());

  cbt->have_computed_timeout = 1;

  if (cbt->timeout_ms < BUILD_TIMEOUT_MIN_VALUE) {
  if (cbt->timeout_ms < circuit_build_times_min_timeout()) {
    log_warn(LD_CIRC, "Set buildtimeout to low value %lfms. Setting to %dms",
             cbt->timeout_ms, BUILD_TIMEOUT_MIN_VALUE);
    cbt->timeout_ms = BUILD_TIMEOUT_MIN_VALUE;
             cbt->timeout_ms, circuit_build_times_min_timeout());
    cbt->timeout_ms = circuit_build_times_min_timeout();
  }

  control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
+3 −3
Original line number Diff line number Diff line
@@ -3480,7 +3480,7 @@ control_event_buildtimeout_set(const circuit_build_times_t *cbt,
                        buildtimeout_set_event_t type)
{
  const char *type_string = NULL;
  double qnt = BUILDTIMEOUT_QUANTILE_CUTOFF;
  double qnt = circuit_build_times_quantile_cutoff();

  if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET))
    return 0;
+1 −0
Original line number Diff line number Diff line
@@ -1680,6 +1680,7 @@ networkstatus_set_current_consensus(const char *consensus,
    dirvote_recalculate_timing(get_options(), now);
    routerstatus_list_update_named_server_map();
    cell_ewma_set_scale_factor(get_options(), current_consensus);
    circuit_build_times_new_consensus_params(&circ_times, current_consensus);
  }

  if (!from_cache) {
+46 −38
Original line number Diff line number Diff line
@@ -3002,49 +3002,27 @@ void entry_guards_free_all(void);

/* Circuit Build Timeout "public" functions and structures. */

/** Total size of the circuit timeout history to accumulate.
 * 1000 is approx 2.5 days worth of continual-use circuits. */
#define CBT_NCIRCUITS_TO_OBSERVE 1000

/** Maximum quantile to use to generate synthetic timeouts.
 *  We want to stay a bit short of 1.0, because longtail is
 *  loooooooooooooooooooooooooooooooooooooooooooooooooooong. */
#define MAX_SYNTHETIC_QUANTILE 0.985

/** Minimum circuits before estimating a timeout */
#define MIN_CIRCUITS_TO_OBSERVE 20

/** Total size of the circuit timeout history to accumulate.
 * 5000 is approx 1.5 weeks worth of continual-use circuits. */
#define NCIRCUITS_TO_OBSERVE 5000
#define CBT_MAX_SYNTHETIC_QUANTILE 0.985

/** Width of the histogram bins in milliseconds */
#define BUILDTIME_BIN_WIDTH ((build_time_t)50)

/** Cutoff point on the CDF for our timeout estimation.
 * TODO: This should be moved to the consensus */
#define BUILDTIMEOUT_QUANTILE_CUTOFF 0.8
#define CBT_BIN_WIDTH ((build_time_t)50)

/** A build_time_t is milliseconds */
typedef uint32_t build_time_t;
#define BUILD_TIME_MAX ((build_time_t)(INT32_MAX))

/** Lowest allowable value for CircuitBuildTimeout in milliseconds */
#define BUILD_TIMEOUT_MIN_VALUE (3*1000)

/** Initial circuit build timeout in milliseconds */
#define BUILD_TIMEOUT_INITIAL_VALUE (60*1000)

/** How often in seconds should we build a test circuit */
#define BUILD_TIMES_TEST_FREQUENCY 60
#define CBT_BUILD_TIME_MAX ((build_time_t)(INT32_MAX))

/** Save state every 10 circuits */
#define BUILD_TIMES_SAVE_STATE_EVERY 1
#define CBT_SAVE_STATE_EVERY 10

/* Circuit Build Timeout network liveness constants */

/**
 * How many circuits count as recent when considering if the
 * connection has gone gimpy or changed.
 */
#define RECENT_CIRCUITS 20

/**
 * Have we received a cell in the last N circ attempts?
 *
@@ -3053,7 +3031,7 @@ typedef uint32_t build_time_t;
 * at which point we switch back to computing the timeout from
 * our saved history.
 */
#define NETWORK_NONLIVE_TIMEOUT_COUNT (RECENT_CIRCUITS*3/20)
#define CBT_NETWORK_NONLIVE_TIMEOUT_COUNT (3)

/**
 * This tells us when to toss out the last streak of N timeouts.
@@ -3061,7 +3039,15 @@ typedef uint32_t build_time_t;
 * If instead we start getting cells, we switch back to computing the timeout
 * from our saved history.
 */
#define NETWORK_NONLIVE_DISCARD_COUNT (NETWORK_NONLIVE_TIMEOUT_COUNT*2)
#define CBT_NETWORK_NONLIVE_DISCARD_COUNT (CBT_NETWORK_NONLIVE_TIMEOUT_COUNT*2)

/* Circuit build times consensus parameters */

/**
 * How many circuits count as recent when considering if the
 * connection has gone gimpy or changed.
 */
#define CBT_DEFAULT_RECENT_CIRCUITS 20

/**
 * Maximum count of timeouts that finish the first hop in the past
@@ -3070,10 +3056,28 @@ typedef uint32_t build_time_t;
 * This tells us to abandon timeout history and set
 * the timeout back to BUILD_TIMEOUT_INITIAL_VALUE.
 */
#define MAX_RECENT_TIMEOUT_COUNT (RECENT_CIRCUITS*4/5)
#define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10)

/** Minimum circuits before estimating a timeout */
#define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100

/** Cutoff percentile on the CDF for our timeout estimation. */
#define CBT_DEFAULT_QUANTILE_CUTOFF 80
double circuit_build_times_quantile_cutoff(void);

/** How often in seconds should we build a test circuit */
#define CBT_DEFAULT_TEST_FREQUENCY 60

/** Lowest allowable value for CircuitBuildTimeout in milliseconds */
#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (2*1000)

/** Initial circuit build timeout in milliseconds */
#define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000)
int32_t circuit_build_times_initial_timeout(void);

#if MAX_RECENT_TIMEOUT_COUNT < 1 || NETWORK_NONLIVE_DISCARD_COUNT < 1 || \
  NETWORK_NONLIVE_TIMEOUT_COUNT < 1
#if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < 1 || \
    CBT_NETWORK_NONLIVE_DISCARD_COUNT < 1 || \
    CBT_NETWORK_NONLIVE_TIMEOUT_COUNT < 1
#error "RECENT_CIRCUITS is set too low."
#endif

@@ -3087,7 +3091,9 @@ typedef struct {
  int nonlive_discarded;
  /** Circular array of circuits that have made it to the first hop. Slot is
   * 1 if circuit timed out, 0 if circuit succeeded */
  int8_t timeouts_after_firsthop[RECENT_CIRCUITS];
  int8_t *timeouts_after_firsthop;
  /** Number of elements allocated for the above array */
  int num_recent_circs;
  /** Index into circular array. */
  int after_firsthop_idx;
  /** The network is not live. Timeout gathering is suspended */
@@ -3097,10 +3103,10 @@ typedef struct {
/** Structure for circuit build times history */
typedef struct {
  /** The circular array of recorded build times in milliseconds */
  build_time_t circuit_build_times[NCIRCUITS_TO_OBSERVE];
  build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE];
  /** Current index in the circuit_build_times circular array */
  int build_times_idx;
  /** Total number of build times accumulated. Maxes at NCIRCUITS_TO_OBSERVE */
  /** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */
  int total_build_times;
  /** Information about the state of our local network connection */
  network_liveness_t liveness;
@@ -3132,6 +3138,8 @@ int circuit_build_times_add_time(circuit_build_times_t *cbt,
int circuit_build_times_needs_circuits(circuit_build_times_t *cbt);
int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt);
void circuit_build_times_init(circuit_build_times_t *cbt);
void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
                                              networkstatus_t *ns);

#ifdef CIRCUIT_PRIVATE
double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
+18 −17

File changed.

Preview size limit exceeded, changes collapsed.