From 17ebddbbdca2cd3731171f275262761826e7d09c Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 3 Sep 2010 14:09:45 -0400 Subject: Remove an obsolete comment from hibernate.c --- src/or/hibernate.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/or/hibernate.c b/src/or/hibernate.c index d50d05ed5..30f1ad224 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -591,10 +591,6 @@ read_bandwidth_usage(void) if (!state) return -1; - /* Okay; it looks like the state file is more up-to-date than the - * bw_accounting file, or the bw_accounting file is nonexistent, - * or the bw_accounting file is corrupt. - */ log_info(LD_ACCT, "Reading bandwidth accounting data from state file"); n_bytes_read_in_interval = state->AccountingBytesReadInInterval; n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval; -- cgit v1.2.3 From d0acaac781f766a51c869f503af5a431748b55b9 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 3 Sep 2010 13:43:59 -0400 Subject: Use a more sophisticated soft-hibernation-limit calculation This should help address bug 1789. --- changes/bug1789 | 8 ++++++++ src/or/hibernate.c | 23 +++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 changes/bug1789 diff --git a/changes/bug1789 b/changes/bug1789 new file mode 100644 index 000000000..1f9e6b15b --- /dev/null +++ b/changes/bug1789 @@ -0,0 +1,8 @@ + o Minor features: + - Be more generous with how much bandwidth we'd use up (with + accounting enabled) before entering "soft hibernation". + Previously, we'd hibernate once we'd used up 95% of our allotment. + Now, we use up 95% of our allotment, AND make sure that we have + no more than 500MB/3 hours of traffic remaining before we enter + soft hibernation. + diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 30f1ad224..351da93cd 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -637,8 +637,27 @@ hibernate_hard_limit_reached(void) static int hibernate_soft_limit_reached(void) { - uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(get_options()->AccountingMax) - * .95); + const uint64_t acct_max = get_options()->AccountingMax; +#define SOFT_LIM_PCT (.95) +#define SOFT_LIM_BYTES (500*1024*1024) +#define SOFT_LIM_MINUTES (3*60) + /* The 'soft limit' is a fair bit more complicated now than once it was. + * We want to stop accepting connections when ALL of the following are true: + * - We expect to use up the remaining bytes in under 3 hours + * - We have used up 95% of our bytes. + * - We have less than 500MB of bytes left. + */ + uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT); + if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) { + soft_limit = acct_max - SOFT_LIM_BYTES; + } + if (expected_bandwidth_usage) { + const uint64_t expected_usage = + expected_bandwidth_usage * SOFT_LIM_MINUTES; + if (acct_max > expected_usage && acct_max - expected_usage > soft_limit) + soft_limit = acct_max - expected_usage; + } + if (!soft_limit) return 0; return n_bytes_read_in_interval >= soft_limit -- cgit v1.2.3 From 2920d8866767e46d6d6999d12fc6acd3547f22f1 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 3 Sep 2010 14:29:17 -0400 Subject: Base our expected bw accounting usage on time before soft limit Previously, we were also considering the time spent in soft-hibernation. If this was a long time, we would wind up underestimating our bandwidth by a lot, and skewing our wakeup time towards the start of the accounting interval. This patch also makes us store a few more fields in the state file, including the time at which we entered soft hibernation. Fixes bug 1789. Bugfix on 0.0.9pre5. --- changes/bug1789 | 8 +++++++ src/or/config.c | 3 +++ src/or/hibernate.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++------ src/or/or.h | 3 +++ 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/changes/bug1789 b/changes/bug1789 index 1f9e6b15b..7090ea8f7 100644 --- a/changes/bug1789 +++ b/changes/bug1789 @@ -6,3 +6,11 @@ no more than 500MB/3 hours of traffic remaining before we enter soft hibernation. + o Minor bugfixes: + - For bandwidth accounting, calculate our expected bandwidth rate + based on the time during which we were active and not in + soft-hibernation during the last interval. Previously, we were + also considering the time spent in soft-hibernation. If this + was a long time, we would wind up underestimating our bandwidth + by a lot, and skewing our wakeup time towards the start of the + accounting interval. Fixes bug 1789. Bugfix on 0.0.9pre5. diff --git a/src/or/config.c b/src/or/config.c index 7ad272f74..9671c3440 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -428,6 +428,9 @@ static config_var_t _state_vars[] = { V(AccountingExpectedUsage, MEMUNIT, NULL), V(AccountingIntervalStart, ISOTIME, NULL), V(AccountingSecondsActive, INTERVAL, NULL), + V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL), + V(AccountingSoftLimitHitAt, ISOTIME, NULL), + V(AccountingBytesAtSoftLimit, MEMUNIT, NULL), VAR("EntryGuard", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL), diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 351da93cd..5f14eb23c 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -95,6 +95,13 @@ static uint64_t n_bytes_read_in_interval = 0; static uint64_t n_bytes_written_in_interval = 0; /** How many seconds have we been running this interval? */ static uint32_t n_seconds_active_in_interval = 0; +/** How many seconds were we active in this interval before we hit our soft + * limit? */ +static int n_seconds_to_hit_soft_limit = 0; +/** When in this interval was the soft limit hit. */ +static time_t soft_limit_hit_at = 0; +/** How many bytes had we read/written when we hit the soft limit? */ +static uint64_t n_bytes_at_soft_limit = 0; /** When did this accounting interval start? */ static time_t interval_start_time = 0; /** When will this accounting interval end? */ @@ -377,20 +384,34 @@ update_expected_bandwidth(void) uint64_t used, expected; uint64_t max_configured = (get_options()->BandwidthRate * 60); - if (n_seconds_active_in_interval < 1800) { +#define MIN_TIME_FOR_MEASUREMENT (1800) + + if (soft_limit_hit_at > interval_start_time && n_bytes_at_soft_limit && + (soft_limit_hit_at - interval_start_time) > MIN_TIME_FOR_MEASUREMENT) { + /* If we hit our soft limit last time, only count the bytes up to that + * time. This is a better predictor of our actual bandwidth than + * considering the entirety of the last interval, since we likely started + * using bytes very slowly once we hit our soft limit. */ + expected = n_bytes_at_soft_limit / + (soft_limit_hit_at - interval_start_time); + expected /= 60; + } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) { + /* Otherwise, we either measured enough time in the last interval but + * never hit our soft limit, or we're using a state file from a Tor that + * doesn't know to store soft-limit info. Just take the + */ + used = MAX(n_bytes_written_in_interval, n_bytes_read_in_interval); + expected = used / (n_seconds_active_in_interval / 60); + } else { /* If we haven't gotten enough data last interval, set 'expected' * to 0. This will set our wakeup to the start of the interval. * Next interval, we'll choose our starting time based on how much * we sent this interval. */ expected = 0; - } else { - used = n_bytes_written_in_interval < n_bytes_read_in_interval ? - n_bytes_read_in_interval : n_bytes_written_in_interval; - expected = used / (n_seconds_active_in_interval / 60); - if (expected > max_configured) - expected = max_configured; } + if (expected > max_configured) + expected = max_configured; expected_bandwidth_usage = expected; } @@ -408,6 +429,9 @@ reset_accounting(time_t now) n_bytes_read_in_interval = 0; n_bytes_written_in_interval = 0; n_seconds_active_in_interval = 0; + n_bytes_at_soft_limit = 0; + soft_limit_hit_at = 0; + n_seconds_to_hit_soft_limit = 0; } /** Return true iff we should save our bandwidth usage to disk. */ @@ -568,6 +592,10 @@ accounting_record_bandwidth_usage(time_t now, or_state_t *state) state->AccountingSecondsActive = n_seconds_active_in_interval; state->AccountingExpectedUsage = expected_bandwidth_usage; + state->AccountingSecondsToReachSoftLimit = n_seconds_to_hit_soft_limit; + state->AccountingSoftLimitHitAt = soft_limit_hit_at; + state->AccountingBytesAtSoftLimit = n_bytes_at_soft_limit; + or_state_mark_dirty(state, now+(get_options()->AvoidDiskWrites ? 7200 : 60)); @@ -598,6 +626,21 @@ read_bandwidth_usage(void) interval_start_time = state->AccountingIntervalStart; expected_bandwidth_usage = state->AccountingExpectedUsage; + /* Older versions of Tor (before 0.2.2.16-alpha) didn't generate these + * fields. If you switch back and forth, you might get an + * AccountingSoftLimitHitAt value from long before the most recent + * interval_start_time. If that's so, then ignore the softlimit-related + * values. */ + if (state->AccountingSoftLimitHitAt > interval_start_time) { + soft_limit_hit_at = state->AccountingSoftLimitHitAt; + n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit; + n_seconds_to_hit_soft_limit = state->AccountingSoftLimitHitAt; + } else { + soft_limit_hit_at = 0; + n_bytes_at_soft_limit = 0; + n_seconds_to_hit_soft_limit = 0; + } + { char tbuf1[ISO_TIME_LEN+1]; char tbuf2[ISO_TIME_LEN+1]; @@ -682,6 +725,14 @@ hibernate_begin(hibernate_state_t new_state, time_t now) exit(0); } + if (new_state == HIBERNATE_STATE_LOWBANDWIDTH && + hibernate_state == HIBERNATE_STATE_LIVE) { + soft_limit_hit_at = now; + n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; + n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, + n_bytes_written_in_interval); + } + /* close listeners. leave control listener(s). */ while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) || (conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) || diff --git a/src/or/or.h b/src/or/or.h index 48641c811..2c72bc2bf 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2828,6 +2828,9 @@ typedef struct { uint64_t AccountingBytesReadInInterval; uint64_t AccountingBytesWrittenInInterval; int AccountingSecondsActive; + int AccountingSecondsToReachSoftLimit; + time_t AccountingSoftLimitHitAt; + uint64_t AccountingBytesAtSoftLimit; uint64_t AccountingExpectedUsage; /** A list of Entry Guard-related configuration lines. */ -- cgit v1.2.3 From bc081c254afaac4203037653850befb0b114171d Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Wed, 15 Sep 2010 21:13:17 +0200 Subject: How many seconds until != timestamp of that date --- src/or/hibernate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 5f14eb23c..8f72c6982 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -634,7 +634,7 @@ read_bandwidth_usage(void) if (state->AccountingSoftLimitHitAt > interval_start_time) { soft_limit_hit_at = state->AccountingSoftLimitHitAt; n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit; - n_seconds_to_hit_soft_limit = state->AccountingSoftLimitHitAt; + n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit; } else { soft_limit_hit_at = 0; n_bytes_at_soft_limit = 0; -- cgit v1.2.3 From 144d92d5384a42ca133c463bfe834431e2611c11 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 15 Sep 2010 15:41:32 -0400 Subject: finish a comment, lower a variable --- src/or/hibernate.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 8f72c6982..25c81de8e 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -381,7 +381,7 @@ configure_accounting(time_t now) static void update_expected_bandwidth(void) { - uint64_t used, expected; + uint64_t expected; uint64_t max_configured = (get_options()->BandwidthRate * 60); #define MIN_TIME_FOR_MEASUREMENT (1800) @@ -398,9 +398,11 @@ update_expected_bandwidth(void) } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) { /* Otherwise, we either measured enough time in the last interval but * never hit our soft limit, or we're using a state file from a Tor that - * doesn't know to store soft-limit info. Just take the + * doesn't know to store soft-limit info. Just take rate at which + * we were reading/writing in the last interval as our expected rate. */ - used = MAX(n_bytes_written_in_interval, n_bytes_read_in_interval); + uint64_t used = MAX(n_bytes_written_in_interval, + n_bytes_read_in_interval); expected = used / (n_seconds_active_in_interval / 60); } else { /* If we haven't gotten enough data last interval, set 'expected' -- cgit v1.2.3 From 9cba61eb8c76480316fb149b1a90ef3abb6818fb Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 21 Sep 2010 14:02:04 -0400 Subject: Bug1789 cleanups suggested by arma The significant one is that we look at RelayBandwidthRate if it is set. --- changes/bug1789 | 8 ++++---- src/or/hibernate.c | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/changes/bug1789 b/changes/bug1789 index 7090ea8f7..9292aa924 100644 --- a/changes/bug1789 +++ b/changes/bug1789 @@ -1,10 +1,10 @@ o Minor features: - Be more generous with how much bandwidth we'd use up (with accounting enabled) before entering "soft hibernation". - Previously, we'd hibernate once we'd used up 95% of our allotment. - Now, we use up 95% of our allotment, AND make sure that we have - no more than 500MB/3 hours of traffic remaining before we enter - soft hibernation. + Previously, we'd hibernate once we'd used up 95% of our + allotment. Now, we use up 95% of our allotment, AND make sure + that we have no more than 500MB (or 3 hours of expected traffic, + whichever is lower) remaining before we enter soft hibernation. o Minor bugfixes: - For bandwidth accounting, calculate our expected bandwidth rate diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 25c81de8e..d0d09798c 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -382,7 +382,10 @@ static void update_expected_bandwidth(void) { uint64_t expected; - uint64_t max_configured = (get_options()->BandwidthRate * 60); + or_options_t *options= get_options(); + uint64_t max_configured = (options->RelayBandwidthRate > 0 ? + options->RelayBandwidthRate : + options->BandwidthRate) * 60; #define MIN_TIME_FOR_MEASUREMENT (1800) @@ -628,7 +631,7 @@ read_bandwidth_usage(void) interval_start_time = state->AccountingIntervalStart; expected_bandwidth_usage = state->AccountingExpectedUsage; - /* Older versions of Tor (before 0.2.2.16-alpha) didn't generate these + /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these * fields. If you switch back and forth, you might get an * AccountingSoftLimitHitAt value from long before the most recent * interval_start_time. If that's so, then ignore the softlimit-related @@ -732,7 +735,7 @@ hibernate_begin(hibernate_state_t new_state, time_t now) soft_limit_hit_at = now; n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, - n_bytes_written_in_interval); + n_bytes_written_in_interval); } /* close listeners. leave control listener(s). */ -- cgit v1.2.3