Commit 514671ef authored by juga's avatar juga
Browse files

Move cap to avg bw inside of scale method

also:
* fix missing avg bw after moving functions to methods
* add more attrs to V3BWLine that are going to be used by other
  scaling methods
parent a98787cf
......@@ -33,12 +33,16 @@ LINE_TERMINATOR = TERMINATOR + LINE_SEP
# KeyValue separator in Bandwidth Lines
BW_KEYVALUE_SEP_V110 = ' '
BW_EXTRA_ARG_KEYVALUES = ['master_key_ed25519', 'nick', 'rtt', 'time',
'success', 'error_stream', 'error_circ',
'error_misc']
# not inclding in the files the extra bws for now
BW_KEYVALUES_BASIC = ['node_id', 'bw']
BW_KEYVALUES_FILE = BW_KEYVALUES_BASIC + \
['master_key_ed25519', 'nick', 'rtt', 'time',
'success', 'error_stream', 'error_circ', 'error_misc']
BW_KEYVALUES_EXTRA_BWS = ['bw_bs_median', 'bw_bs_mean', 'desc_avg_bw_bs']
BW_KEYVALUES_EXTRA = BW_KEYVALUES_FILE + BW_KEYVALUES_EXTRA_BWS
BW_KEYVALUES_INT = ['bw', 'rtt', 'success', 'error_stream',
'error_circ', 'error_misc']
BW_KEYVALUES = ['node_id', 'bw'] + BW_EXTRA_ARG_KEYVALUES
'error_circ', 'error_misc'] + BW_KEYVALUES_EXTRA_BWS
BW_KEYVALUES = BW_KEYVALUES_BASIC + BW_KEYVALUES_EXTRA
def num_results_of_type(results, type_str):
......@@ -222,26 +226,43 @@ class V3BWLine(object):
self.node_id = node_id
self.bw = bw
[setattr(self, k, v) for k, v in kwargs.items()
if k in BW_EXTRA_ARG_KEYVALUES]
if k in BW_KEYVALUES_EXTRA]
def __str__(self):
return self.bw_strv110
@classmethod
def from_results(cls, results):
"""Convert sbws results to relays' Bandwidth Lines
``bs`` stands for Bytes/seconds
``bw_bs_mean`` means the bw is obtained from the mean of the all the
downloads' bandwidth.
Downloads' bandwidth are calculated as the amount of data received
divided by the the time it took to received.
bw = data (Bytes) / time (seconds)
"""
success_results = [r for r in results if isinstance(r, ResultSuccess)]
# log.debug('len(success_results) %s', len(success_results))
node_id = '$' + results[0].fingerprint
bw = cls.bw_from_results(success_results)
kwargs = dict()
kwargs['nick'] = results[0].nickname
if getattr(results[0], 'master_key_ed25519'):
kwargs['master_key_ed25519'] = results[0].master_key_ed25519
kwargs['rtt'] = cls.rtt_from_results(success_results)
kwargs['time'] = cls.last_time_from_results(results)
kwargs.update(cls.result_types_from_results(results))
bwl = cls(node_id, bw, **kwargs)
return bwl
# useful args for scaling
if success_results:
# the most recent should be the last
kwargs['desc_avg_bw_bs'] = \
success_results[-1].relay_average_bandwidth
kwargs['rtt'] = cls.rtt_from_results(success_results)
bw = cls.bw_bs_median_from_results(success_results)
kwargs['bw_bs_mean'] = cls.bw_bs_mean_from_results(success_results)
kwargs['bw_bs_median'] = cls.bw_bs_median_from_results(
success_results)
bwl = cls(node_id, bw, **kwargs)
return bwl
return None
@classmethod
def from_data(cls, data, fingerprint):
......@@ -260,6 +281,16 @@ class V3BWLine(object):
bw_line = cls(**kwargs)
return bw_line
@staticmethod
def bw_bs_median_from_results(results):
return max(round(median([dl['amount'] / dl['duration']
for r in results for dl in r.downloads])), 1)
@staticmethod
def bw_bs_mean_from_results(results):
return max(round(mean([dl['amount'] / dl['duration']
for r in results for dl in r.downloads])), 1)
@staticmethod
def last_time_from_results(results):
return unixts_to_isodt_str(round(max([r.time for r in results])))
......@@ -278,32 +309,6 @@ class V3BWLine(object):
for rt in _ResultType])
return rt_dict
@staticmethod
def bw_from_results(results):
median_bw = median([dl['amount'] / dl['duration']
for r in results for dl in r.downloads])
# If a relay has MaxAdvertisedBandwidth set, they may be capable of
# some large amount of bandwidth but prefer if they didn't receive it.
# We also could have managed to measure them faster than their
# {,Relay}BandwidthRate somehow.
#
# See https://github.com/pastly/simple-bw-scanner/issues/155 and
# https://trac.torproject.org/projects/tor/ticket/8494
#
# Note how this isn't some measured-by-us average of bandwidth. It's
# the first value on the 'bandwidth' line in the relay's server
# descriptor.
bw = median_bw
relay_average_bw = [r.relay_average_bandwidth for r in results
if r.relay_average_bandwidth is not None]
if relay_average_bw:
median_relay_average_bw = median(relay_average_bw)
if median_bw > median_relay_average_bw:
bw = median_relay_average_bw
# convert to KB and ensure it's at least 1
bw_kb = max(round(bw / 1024), 1)
return bw_kb
@property
def bw_keyvalue_tuple_ls(self):
"""Return list of KeyValue Bandwidth Line tuples."""
......@@ -393,7 +398,7 @@ class V3BWFile(object):
# min is to limit the bw to descriptor average-bandwidth
# max to avoid bandwidth with 0 value
l.bw = max(round(min(l.desc_avg_bw_bs,
l.bw_bs_median * scale_constant / m)
l.bw * scale_constant / m)
/ 1000), 1)
return sorted(bw_lines_scaled, key=lambda x: x.bw, reverse=reverse)
......
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