Commit 7750bee2 authored by Mike Perry's avatar Mike Perry
Browse files

Clean up Fallon's partially complete GSoC project.

The code actually isn't that bad. It's a shame she didn't finish.
Using it as the base for this feature.
parent 2dbf5b77
......@@ -12,6 +12,11 @@
#include "or.h"
/********* START VARIABLES **********/
/** Global list of circuit build times */
// XXX: Make this a smartlist..
uint16_t circuit_build_times[NCIRCUITS_TO_OBSERVE];
int build_times_idx = 0;
int total_build_times = 0;
/** A global list of all circuits at this hop. */
extern circuit_t *global_circuitlist;
......@@ -60,6 +65,156 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static void entry_guards_changed(void);
static time_t start_of_month(time_t when);
static int circuit_build_times_add_time(time_t time);
/** circuit_build_times is a circular array, so loop around when
* array is full
*
* time units are milliseconds
*/
static
int
circuit_build_times_add_time(long time)
{
if(time > UINT16_MAX) {
log_notice(LD_CIRC,
"Circuit build time of %dms exceeds max. Capping at 65536ms", time);
time = UINT16_MAX;
}
circuit_build_times[build_times_idx] = time;
build_times_idx = (build_times_idx + 1) % NCIRCUITS_TO_OBSERVE;
if(total_build_times + 1 < NCIRCUITS_TO_OBSERVE)
total_build_times++;
return 0;
}
/**
* Calculate histogram
*/
void
circuit_build_times_create_histogram(uint16_t * histogram)
{
int i, c;
// calculate histogram
for(i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
if(circuit_build_times[i] == 0) continue; /* 0 <-> uninitialized */
c = (circuit_build_times[i] / BUILDTIME_BIN_WIDTH);
histogram[c]++;
}
}
/**
* Find maximum circuit build time
*/
uint16_t
circuit_build_times_max()
{
int i = 0, max_build_time = 0;
for( i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
if(circuit_build_times[i] > max_build_time)
max_build_time = circuit_build_times[i];
}
return max_build_time;
}
uint16_t
circuit_build_times_min()
{
int i = 0;
uint16_t min_build_time = UINT16_MAX;
for( i = 0; i < NCIRCUITS_TO_OBSERVE; i++) {
if(circuit_build_times[i] && /* 0 <-> uninitialized */
circuit_build_times[i] < min_build_time)
min_build_time = circuit_build_times[i];
}
return min_build_time;
}
/**
* output a histogram of current circuit build times
*/
void
circuit_build_times_update_state(or_state_t * state)
{
uint16_t max_build_time = 0, *histogram;
int i = 0, nbins = 0;
config_line_t **next, *line;
max_build_time = circuit_build_times_max();
nbins = 1 + (max_build_time / BUILDTIME_BIN_WIDTH);
histogram = tor_malloc_zero(nbins * sizeof(uint16_t));
circuit_build_times_create_histogram(histogram);
// write to state
config_free_lines(state->BuildtimeHistogram);
next = &state->BuildtimeHistogram;
*next = NULL;
state->TotalBuildTimes = total_build_times;
// total build times?
for(i = 0; i < nbins; i++) {
if(histogram[i] == 0) continue; // compress the histogram by skipping the blanks
*next = line = tor_malloc_zero(sizeof(config_line_t));
line->key = tor_strdup("CircuitBuildTimeBin");
line->value = tor_malloc(20);
tor_snprintf(line->value, 20, "%d %d", i*BUILDTIME_BIN_WIDTH,
histogram[i]);
next = &(line->next);
}
if(!get_options()->AvoidDiskWrites)
or_state_mark_dirty(get_or_state(), 0);
if(histogram) tor_free(histogram);
}
int
find_next_available(int chosen)
{// find index of next open slot in circuit_build_times
int idx = 0;
for(idx = (chosen + 1) % NCIRCUITS_TO_OBSERVE; idx < chosen;
idx = ((idx + 1 ) % NCIRCUITS_TO_OBSERVE)) {
if(circuit_build_times[idx] == 0) {
return idx;
}
}
return 0;
}
/** Load histogram from state */
int
circuit_build_times_parse_state(or_state_t *state, char **msg)
{
config_line_t *line;
msg = NULL;
memset(circuit_build_times, 0, NCIRCUITS_TO_OBSERVE);
total_build_times = state->TotalBuildTimes;
for(line = state->BuildtimeHistogram; line; line = line->next) {
smartlist_t * args = smartlist_create();
smartlist_split_string(args, line->value, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if(smartlist_len(args) < 2) {
*msg = tor_strdup("Unable to parse circuit build times: "
"Too few arguments to CircuitBuildTIme");
break;
} else {
uint16_t ms, count, i;
/* XXX: use tor_strtol */
ms = atol(smartlist_get(args,0));
count = atol(smartlist_get(args,1));
for(i = 0; i < count; i++) {
circuit_build_times_add_time(ms);
}
}
}
return (msg ? -1 : 0);
}
/** Iterate over values of circ_id, starting from conn-\>next_circ_id,
* and with the high bit specified by conn-\>circ_id_type, until we get
* a circ_id that is not in use by any other circuit on that conn.
......@@ -641,8 +796,13 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath);
if (!hop) {
struct timeval end;
tor_gettimeofday(&end);
/* done building the circuit. whew. */
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
circuit_build_times_add_time(tor_mdiff(&circ->_base.timestamp_created,
&end));
circuit_build_times_recompute();
log_info(LD_CIRC,"circuit built!");
circuit_reset_failure_count(0);
if (circ->build_state->onehop_tunnel)
......
......@@ -379,6 +379,7 @@ static void
init_circuit_base(circuit_t *circ)
{
circ->timestamp_created = time(NULL);
tor_gettimeofday(&circ->highres_created);
circ->package_window = circuit_initial_package_window();
circ->deliver_window = CIRCWINDOW_START;
......
......@@ -409,6 +409,11 @@ static config_var_t _state_vars[] = {
V(LastRotatedOnionKey, ISOTIME, NULL),
V(LastWritten, ISOTIME, NULL),
VAR("TotalBuildTimes", UINT, TotalBuildTimes, NULL),
VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL),
VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
......@@ -597,6 +602,10 @@ static config_var_description_t options_description[] = {
/* Hidden service options: HiddenService: dir,excludenodes, nodes,
* options, port. PublishHidServDescriptor */
/* Circuit build time histogram options */
{ "CircuitBuildTimeBin", "Histogram of recent circuit build times"},
{ "TotalBuildTimes", "Total number of buildtimes in histogram"},
/* Nonpersistent options: __LeaveStreamsUnattached, __AllDirActionsPrivate */
{ NULL, NULL },
};
......@@ -5060,6 +5069,13 @@ or_state_set(or_state_t *new_state)
log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
tor_free(err);
}
if(circuit_build_times_parse_state(global_state, &err) < 0) {
log_warn(LD_GENERAL,"%s",err);
tor_free(err);
}
}
/** Reload the persistent state from disk, generating a new state as needed.
......@@ -5192,6 +5208,7 @@ or_state_save(time_t now)
* to avoid redundant writes. */
entry_guards_update_state(global_state);
rep_hist_update_state(global_state);
circuit_build_times_update_state(global_state);
if (accounting_is_enabled(get_options()))
accounting_run_housekeeping(now);
......
......@@ -1884,6 +1884,13 @@ typedef struct crypt_path_t {
DH_KEY_LEN)
#define ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN)
// XXX: Do we want to artifically tweak CircuitIdleTimeout and
// the number of circuits we build at a time if < MIN here?
#define MIN_CIRCUITS_TO_OBSERVE 1000
#define NCIRCUITS_TO_OBSERVE 10000 /* approx 3 weeks worth of circuits */
#define BUILDTIME_BIN_WIDTH 50
/** Information used to build a circuit. */
typedef struct {
/** Intended length of the final circuit. */
......@@ -1977,6 +1984,7 @@ typedef struct circuit_t {
time_t timestamp_created; /**< When was this circuit created? */
time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
* circuit is clean. */
struct timeval highres_created; /**< When exactly was this circuit created? */
uint16_t marked_for_close; /**< Should we close this circuit at the end of
* the main loop? (If true, holds the line number
......@@ -2683,6 +2691,11 @@ typedef struct {
int BWHistoryWriteInterval;
smartlist_t *BWHistoryWriteValues;
/** Build time histogram */
config_line_t * BuildtimeHistogram;
uint16_t TotalBuildTimes;
/** What version of Tor wrote this state file? */
char *TorVersion;
......@@ -2852,6 +2865,11 @@ void bridges_retry_all(void);
void entry_guards_free_all(void);
void circuit_build_times_update_state(or_state_t *state);
int circuit_build_times_parse_state(or_state_t *state, char **msg);
/********************************* circuitlist.c ***********************/
circuit_t * _circuit_get_global_list(void);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment