diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index c73f98bb9f..4ef6bfac36 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -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); diff --git a/src/or/control.c b/src/or/control.c index a7e60d55f0..835c3be518 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -3480,13 +3480,13 @@ 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; switch (type) { - case BUILDTIMEOUT_SET_EVENT_COMPUTED: + case BUILDTIMEOUT_SET_EVENT_COMPUTED: type_string = "COMPUTED"; break; case BUILDTIMEOUT_SET_EVENT_RESET: @@ -3513,7 +3513,7 @@ control_event_buildtimeout_set(const circuit_build_times_t *cbt, "650 BUILDTIMEOUT_SET %s TOTAL_TIMES=%lu " "TIMEOUT_MS=%lu XM=%lu ALPHA=%lf CUTOFF_QUANTILE=%lf\r\n", type_string, (unsigned long)cbt->total_build_times, - (unsigned long)cbt->timeout_ms, + (unsigned long)cbt->timeout_ms, (unsigned long)cbt->Xm, cbt->alpha, qnt); return 0; diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 507875ab2a..a507f1be2d 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -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) { diff --git a/src/or/or.h b/src/or/or.h index 24cabb4300..434de7819e 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -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) -#if MAX_RECENT_TIMEOUT_COUNT < 1 || NETWORK_NONLIVE_DISCARD_COUNT < 1 || \ - NETWORK_NONLIVE_TIMEOUT_COUNT < 1 +/** 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 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, diff --git a/src/test/test.c b/src/test/test.c index 8b84290446..760558b65a 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -479,11 +479,12 @@ test_circuit_timeout(void) circuitbuild_running_unit_tests(); #define timeout0 (build_time_t)(30*1000.0) initial.Xm = 750; - circuit_build_times_initial_alpha(&initial, BUILDTIMEOUT_QUANTILE_CUTOFF, + circuit_build_times_initial_alpha(&initial, + CBT_DEFAULT_QUANTILE_CUTOFF/100.0, timeout0); do { int n = 0; - for (i=0; i < MIN_CIRCUITS_TO_OBSERVE; i++) { + for (i=0; i < CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE; i++) { if (circuit_build_times_add_time(&estimate, circuit_build_times_generate_sample(&initial, 0, 1)) == 0) { n++; @@ -491,23 +492,23 @@ test_circuit_timeout(void) } circuit_build_times_update_alpha(&estimate); timeout1 = circuit_build_times_calculate_timeout(&estimate, - BUILDTIMEOUT_QUANTILE_CUTOFF); + CBT_DEFAULT_QUANTILE_CUTOFF/100.0); circuit_build_times_set_timeout(&estimate); log_warn(LD_CIRC, "Timeout is %lf, Xm is %d", timeout1, estimate.Xm); /* XXX: 5% distribution error may not be the right metric */ } while (fabs(circuit_build_times_cdf(&initial, timeout0) - circuit_build_times_cdf(&initial, timeout1)) > 0.05 /* 5% error */ - && estimate.total_build_times < NCIRCUITS_TO_OBSERVE); + && estimate.total_build_times < CBT_NCIRCUITS_TO_OBSERVE); - test_assert(estimate.total_build_times < NCIRCUITS_TO_OBSERVE); + test_assert(estimate.total_build_times < CBT_NCIRCUITS_TO_OBSERVE); circuit_build_times_update_state(&estimate, &state); test_assert(circuit_build_times_parse_state(&final, &state, &msg) == 0); circuit_build_times_update_alpha(&final); timeout2 = circuit_build_times_calculate_timeout(&final, - BUILDTIMEOUT_QUANTILE_CUTOFF); + CBT_DEFAULT_QUANTILE_CUTOFF/100.0); circuit_build_times_set_timeout(&final); log_warn(LD_CIRC, "Timeout is %lf, Xm is %d", timeout2, final.Xm); @@ -519,19 +520,19 @@ test_circuit_timeout(void) int build_times_idx = 0; int total_build_times = 0; - final.timeout_ms = BUILD_TIMEOUT_INITIAL_VALUE; - estimate.timeout_ms = BUILD_TIMEOUT_INITIAL_VALUE; + final.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE; + estimate.timeout_ms = CBT_DEFAULT_TIMEOUT_INITIAL_VALUE; - for (i = 0; i < RECENT_CIRCUITS*2; i++) { + for (i = 0; i < CBT_DEFAULT_RECENT_CIRCUITS*2; i++) { circuit_build_times_network_circ_success(&estimate); circuit_build_times_add_time(&estimate, circuit_build_times_generate_sample(&estimate, 0, - BUILDTIMEOUT_QUANTILE_CUTOFF)); + CBT_DEFAULT_QUANTILE_CUTOFF/100.0)); estimate.have_computed_timeout = 1; circuit_build_times_network_circ_success(&estimate); circuit_build_times_add_time(&final, circuit_build_times_generate_sample(&final, 0, - BUILDTIMEOUT_QUANTILE_CUTOFF)); + CBT_DEFAULT_QUANTILE_CUTOFF/100.0)); final.have_computed_timeout = 1; } @@ -544,7 +545,7 @@ test_circuit_timeout(void) build_times_idx = estimate.build_times_idx; total_build_times = estimate.total_build_times; - for (i = 0; i < NETWORK_NONLIVE_TIMEOUT_COUNT; i++) { + for (i = 0; i < CBT_NETWORK_NONLIVE_TIMEOUT_COUNT; i++) { test_assert(circuit_build_times_network_check_live(&estimate)); test_assert(circuit_build_times_network_check_live(&final)); @@ -559,12 +560,12 @@ test_circuit_timeout(void) test_assert(!circuit_build_times_network_check_live(&estimate)); test_assert(!circuit_build_times_network_check_live(&final)); - for ( ; i < NETWORK_NONLIVE_DISCARD_COUNT; i++) { + for ( ; i < CBT_NETWORK_NONLIVE_DISCARD_COUNT; i++) { if (circuit_build_times_add_timeout(&estimate, 0, (time_t)(approx_time()-estimate.timeout_ms/1000.0-1))) estimate.have_computed_timeout = 1; - if (i < NETWORK_NONLIVE_DISCARD_COUNT-1) { + if (i < CBT_NETWORK_NONLIVE_DISCARD_COUNT-1) { if (circuit_build_times_add_timeout(&final, 0, (time_t)(approx_time()-final.timeout_ms/1000.0-1))) final.have_computed_timeout = 1; @@ -587,11 +588,11 @@ test_circuit_timeout(void) circuit_build_times_network_is_live(&estimate); circuit_build_times_network_is_live(&final); - for (i = 0; i < MAX_RECENT_TIMEOUT_COUNT; i++) { + for (i = 0; i < CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT; i++) { if (circuit_build_times_add_timeout(&estimate, 1, approx_time()-1)) estimate.have_computed_timeout = 1; - if (i < MAX_RECENT_TIMEOUT_COUNT-1) { + if (i < CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1) { if (circuit_build_times_add_timeout(&final, 1, approx_time()-1)) final.have_computed_timeout = 1; } @@ -599,7 +600,7 @@ test_circuit_timeout(void) test_assert(estimate.liveness.after_firsthop_idx == 0); test_assert(final.liveness.after_firsthop_idx == - MAX_RECENT_TIMEOUT_COUNT-1); + CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1); test_assert(circuit_build_times_network_check_live(&estimate)); test_assert(circuit_build_times_network_check_live(&final));