mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
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.
This commit is contained in:
parent
d0acaac781
commit
2920d88667
@ -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.
|
||||
|
@ -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),
|
||||
|
@ -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)) ||
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user