[or-cvs] [tor/master 3/6] Base our expected bw accounting usage on time before soft limit

nickm at torproject.org nickm at torproject.org
Tue Sep 21 18:33:21 UTC 2010


Author: Nick Mathewson <nickm at torproject.org>
Date: Fri, 3 Sep 2010 14:29:17 -0400
Subject: Base our expected bw accounting usage on time before soft limit
Commit: 2920d8866767e46d6d6999d12fc6acd3547f22f1

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 1f9e6b1..7090ea8 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 7ad272f..9671c34 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 351da93..5f14eb2 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 48641c8..2c72bc2 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. */
-- 
1.7.1




More information about the tor-commits mailing list