aboutsummaryrefslogtreecommitdiff
path: root/src/or/hibernate.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2010-09-03 14:29:17 -0400
committerNick Mathewson <nickm@torproject.org>2010-09-03 14:29:17 -0400
commit2920d8866767e46d6d6999d12fc6acd3547f22f1 (patch)
tree60fe1d67cfdad5b565cb0776bfe9e386e8b3464a /src/or/hibernate.c
parentd0acaac781f766a51c869f503af5a431748b55b9 (diff)
downloadtor-2920d8866767e46d6d6999d12fc6acd3547f22f1.tar
tor-2920d8866767e46d6d6999d12fc6acd3547f22f1.tar.gz
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.
Diffstat (limited to 'src/or/hibernate.c')
-rw-r--r--src/or/hibernate.c65
1 files changed, 58 insertions, 7 deletions
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)) ||