def __init__(self, external_add_task, config, set_option,
                       get_remote_endpoints, get_rates):
        self.external_add_task = external_add_task
        self.config = config
        self.set_option = set_option
        self.get_rates = get_rates
        def got_new_rtt(rtt):
            self.external_add_task(0, self._inspect_rates, rtt)
        self.rttmonitor = RTTMonitor(got_new_rtt)
        self.nodefeeder = NodeFeeder(external_add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = None

        self.max_samples = 10 # hmm...
        self.u = SizedList(self.max_samples)
        self.d = SizedList(self.max_samples)
        self.t = SizedList(self.max_samples * 10)
        self.ur = SizedList(self.max_samples)
        self.dr = SizedList(self.max_samples)

        self.current_std = 0.001        
        self.max_std = 0.001

        self.max_rates = {}
        self.max_rates["upload"] = 1.0
        self.max_rates["download"] = 1.0
        self.max_p = 1.0
        self.min_p = 2**500
        self.mid_p = ((self.max_p - self.min_p) / 2.0) + self.min_p
        self.old_p = None
    def __init__(self, external_add_task, config, set_option,
                       get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."
        self.external_add_task = external_add_task
        self.config = config
        self.set_option = set_option
        self.get_rates = get_rates
        # Next few lines were added by David Harrison to use RTTMonitor2
        #if os.name == 'nt':
        #    icmp_impl = Win32Icmp()
        #elif os.name == 'posix':
        #    icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])
        def got_new_rtt(rtt):
            self.external_add_task(0, self._inspect_rates, rtt)
        #self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.rttmonitor = RTTMonitor(got_new_rtt)
        self.nodefeeder = NodeFeeder(external_add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = None

        self.max_samples = 10 # hmm...
        self.u = SizedList(self.max_samples)
        self.d = SizedList(self.max_samples)
        self.t = SizedList(self.max_samples * 10)
        self.ur = SizedList(self.max_samples)
        self.dr = SizedList(self.max_samples)

        self.current_std = 0.001        
        self.max_std = 0.001

        self.max_rates = {}
        self.max_rates["upload"] = 1.0
        self.max_rates["download"] = 1.0
        self.max_p = 1.0
        self.min_p = 2**500
        self.mid_p = ((self.max_p - self.min_p) / 2.0) + self.min_p
        self.old_p = None

        # I pulled these numbers out of my ass.

        if stats:
            tmp_dir = platform.get_temp_dir()
            timestr = "%d_%d_%d_%d_%d" % time.localtime()[1:6]
            stats_dir = os.path.join( tmp_dir, "bittorrent%s_%d" %
                (timestr, os.getpid()) )
            os.mkdir(stats_dir)
            if debug: print "BandwidthManager: stats_dir = %s" % stats_dir
            rate_vs_time = os.path.join( stats_dir, "rate_vs_time.plotdata" )
            self.rfp = open( rate_vs_time, "w" )
            delay_vs_time = os.path.join( stats_dir, "delay_vs_time.plotdata" )
            self.dfp = open( delay_vs_time, "w" )
            sdev_vs_time = os.path.join( stats_dir, 
                "stddev_vs_time.plotdata" )
            self.sdevfp = open( sdev_vs_time, "w" )
Example #3
0
    def __init__(self, external_add_task, config, set_config,
                 get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."

        self.external_add_task = external_add_task
        self.config = config
        self.set_config = set_config
        self.get_rates = get_rates
        if os.name == 'nt':
            icmp_impl = Win32Icmp()
        elif os.name == 'posix':
            icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])

        def got_new_rtt(rtt):
            print "got_new_rtt, rtt=", rtt
            self.external_add_task(0, self._inspect_rates, rtt)

        self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.nodefeeder = NodeFeeder(add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = bttime()

        if config['control_law'] == 'aimd':
            self.control_law = AIMDControlLaw(config['increase_delta'],
                                              config['decrease_factor'])
        elif config['control_law'] == 'aiad':
            self.control_law = AIADControlLaw(config['increase_delta'],
                                              config['decrease_delta'])

        # This configurability is temporary during testing/tuning.  --Dave
        if config['congestion_estimator'] == "chebyshev":
            self.congestion_estimator = ChebyshevCongestionEstimator(
                config['window_size'], config['drop_every_nth'],
                config['cheby_max_probability'],
                config['cheby_max_consecutive'], config['cheby_max_threshold'],
                config['ewma'])

        elif config['congestion_estimator'] == "variance":
            self.congestion_estimator = VarianceCongestionEstimator(
                config['window_size'])
        elif config['congestion_estimator'] == "vegasish":
            self.congestion_estimator = VegasishCongestionEstimator(
                config['window_size'], config['drop_every_nth'])
        else:
            raise BTFailure(
                _("Unrecognized congestion estimator '%s'.") %
                config['congestion_estimator'])

        self.starvation_prevention = FixedStarvationPrevention(
            config['min_upload_rate_limit'])

        if stats:
            rlimit_vs_time = \
                           os.path.join( stats_dir, "rlimit_vs_time.plotdata" )
            fp = open(rlimit_vs_time, "w")
            self.control_law = StreamTracer(self.control_law, fp)
            _copy_gnuplot("rlimit_vs_time.gnuplot")

            # samples are max(min_upload_rate_limit,rate).
            slimit_vs_time = \
                           os.path.join( stats_dir, "slimit_vs_time.plotdata" )
            fp = open(slimit_vs_time, "w")
            self.starvation_prevention = StreamTracer(
                self.starvation_prevention, fp)

            delay_vs_time = os.path.join(stats_dir, "delay_vs_time.plotdata")
            self.dfp = open(delay_vs_time, "w")
            _copy_gnuplot("delay_vs_time.gnuplot")
Example #4
0
class BandwidthManager(object):
    """Controls allocation of bandwidth between foreground and background
       traffic.  Currently all BitTorrent traffic is considered background.
       Background traffic is subjected to a global rate limit that is
       reduced during congestion to allow foreground traffic to takeover.

       A 'starvation prevention' building block applies a lower bound.
       """
    def __init__(self, external_add_task, config, set_config,
                 get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."

        self.external_add_task = external_add_task
        self.config = config
        self.set_config = set_config
        self.get_rates = get_rates
        if os.name == 'nt':
            icmp_impl = Win32Icmp()
        elif os.name == 'posix':
            icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])

        def got_new_rtt(rtt):
            print "got_new_rtt, rtt=", rtt
            self.external_add_task(0, self._inspect_rates, rtt)

        self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.nodefeeder = NodeFeeder(add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = bttime()

        if config['control_law'] == 'aimd':
            self.control_law = AIMDControlLaw(config['increase_delta'],
                                              config['decrease_factor'])
        elif config['control_law'] == 'aiad':
            self.control_law = AIADControlLaw(config['increase_delta'],
                                              config['decrease_delta'])

        # This configurability is temporary during testing/tuning.  --Dave
        if config['congestion_estimator'] == "chebyshev":
            self.congestion_estimator = ChebyshevCongestionEstimator(
                config['window_size'], config['drop_every_nth'],
                config['cheby_max_probability'],
                config['cheby_max_consecutive'], config['cheby_max_threshold'],
                config['ewma'])

        elif config['congestion_estimator'] == "variance":
            self.congestion_estimator = VarianceCongestionEstimator(
                config['window_size'])
        elif config['congestion_estimator'] == "vegasish":
            self.congestion_estimator = VegasishCongestionEstimator(
                config['window_size'], config['drop_every_nth'])
        else:
            raise BTFailure(
                _("Unrecognized congestion estimator '%s'.") %
                config['congestion_estimator'])

        self.starvation_prevention = FixedStarvationPrevention(
            config['min_upload_rate_limit'])

        if stats:
            rlimit_vs_time = \
                           os.path.join( stats_dir, "rlimit_vs_time.plotdata" )
            fp = open(rlimit_vs_time, "w")
            self.control_law = StreamTracer(self.control_law, fp)
            _copy_gnuplot("rlimit_vs_time.gnuplot")

            # samples are max(min_upload_rate_limit,rate).
            slimit_vs_time = \
                           os.path.join( stats_dir, "slimit_vs_time.plotdata" )
            fp = open(slimit_vs_time, "w")
            self.starvation_prevention = StreamTracer(
                self.starvation_prevention, fp)

            delay_vs_time = os.path.join(stats_dir, "delay_vs_time.plotdata")
            self.dfp = open(delay_vs_time, "w")
            _copy_gnuplot("delay_vs_time.gnuplot")

    #def congestion_estimator_vegas_greg(self, rtt, rate):
    #
    #    middle_rtt = ((self.propagation_estimator(rtt) +
    #                   self.delay_on_full_estimator(rtt)) / 2.0 )
    #    if t > middle_rtt and c < 0.5:
    #        rate *= 0.5
    #        if debug:
    #            print type, "down to", rate
    #    else:
    #        rate += 1000 # hmm
    #        if debug:
    #            print type, "up to", rate
    #    return rate

    #def congestion_estimator_ratio(self, type, t, p, min_p, max_p, rate):
    #    ratio = p / max_p
    #    if debug:
    #        print "RATIO", ratio
    #    if ratio < 0.5:
    #        rate = ratio * self.max_rates[type]
    #        if debug:
    #            print type.upper(), "SET to", rate
    #    else:
    #        rate += rate * (ratio/10.0) # hmm
    #        if debug:
    #            print type.upper(), "UP to", rate
    #
    #    return max(rate, 1000)

    #def congestion_estimator_stddev(self, type, std, max_std, rate):
    #    if std > (max_std * 0.80): # FUDGE
    #        rate *= 0.80 # FUDGE
    #        if debug:
    #            print type.upper(), "DOWN to", rate
    #    else:
    #        rate += 1000 # FUDGE
    #        if debug:
    #            print type.upper(), "UP to", rate
    #
    #    return max(rate, 1000) # FUDGE

    #def _affect_rate(self, type, std, max_std, rate, set):
    #    rate = self._congestion_estimator_stddev(type, std, max_std, rate)
    #
    #    rock_bottom = False
    #    if rate <= 1000:
    #        if debug:
    #            print "Rock bottom"
    #        rock_bottom = True
    #        rate = 1000
    #
    #    set(int(rate))
    #    if stats:
    #        print "BandwidthManager._affect_rate(%f)" % rate
    #        self.rfp.write( "%d\t%d\n" % (bttime(),int(rate)) )
    #        self.sdevfp.write( "%d\t%f\n" % (bttime(), std ) )
    #
    #    return rock_bottom

    def _inspect_rates(self, t=None):
        """Called whenever an RTT sample arrives. If t == None then
           a timeout occurred."""
        if t == None:
            t = self.rttmonitor.get_current_rtt()

        if t == None:
            # this makes timeouts reduce the maximum std deviation
            self.congestion_estimator.timeout()
            return

        if debug:
            print "BandwidthManager._inspect_rates: %d" % t
        if stats:
            self.dfp.write("%f\t%f\n" % (bttime(), t))

        if not self.config['bandwidth_management']:
            return

        # TODO: slow start should be smarter than this
        #if self.start_time < bttime() + 20:
        #    self.config['max_upload_rate'] = 10000000
        #    self.config['max_dowload_rate'] = 10000000

        #if t < 3:
        #    # I simply don't believe you. Go away.
        #    return

        tup = self.get_rates()
        if tup == None:
            return
        uprate, downrate = tup

        # proceed through the building blocks.  (We can swap in various
        # implementations of each based on config).
        is_congested = self.congestion_estimator(t, uprate)
        rate_limit = self.control_law(is_congested, uprate)
        rate_limit = self.starvation_prevention(rate_limit)
        self._set_rate_limit(rate_limit)

    def _set_rate_limit(self, rate_limit):
        self.set_config('max_upload_rate', rate_limit)
class BandwidthManager(object):
    
    def __init__(self, external_add_task, config, set_option,
                       get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."
        self.external_add_task = external_add_task
        self.config = config
        self.set_option = set_option
        self.get_rates = get_rates
        # Next few lines were added by David Harrison to use RTTMonitor2
        #if os.name == 'nt':
        #    icmp_impl = Win32Icmp()
        #elif os.name == 'posix':
        #    icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])
        def got_new_rtt(rtt):
            self.external_add_task(0, self._inspect_rates, rtt)
        #self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.rttmonitor = RTTMonitor(got_new_rtt)
        self.nodefeeder = NodeFeeder(external_add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = None

        self.max_samples = 10 # hmm...
        self.u = SizedList(self.max_samples)
        self.d = SizedList(self.max_samples)
        self.t = SizedList(self.max_samples * 10)
        self.ur = SizedList(self.max_samples)
        self.dr = SizedList(self.max_samples)

        self.current_std = 0.001        
        self.max_std = 0.001

        self.max_rates = {}
        self.max_rates["upload"] = 1.0
        self.max_rates["download"] = 1.0
        self.max_p = 1.0
        self.min_p = 2**500
        self.mid_p = ((self.max_p - self.min_p) / 2.0) + self.min_p
        self.old_p = None

        # I pulled these numbers out of my ass.

        if stats:
            tmp_dir = platform.get_temp_dir()
            timestr = "%d_%d_%d_%d_%d" % time.localtime()[1:6]
            stats_dir = os.path.join( tmp_dir, "bittorrent%s_%d" %
                (timestr, os.getpid()) )
            os.mkdir(stats_dir)
            if debug: print "BandwidthManager: stats_dir = %s" % stats_dir
            rate_vs_time = os.path.join( stats_dir, "rate_vs_time.plotdata" )
            self.rfp = open( rate_vs_time, "w" )
            delay_vs_time = os.path.join( stats_dir, "delay_vs_time.plotdata" )
            self.dfp = open( delay_vs_time, "w" )
            sdev_vs_time = os.path.join( stats_dir, 
                "stddev_vs_time.plotdata" )
            self.sdevfp = open( sdev_vs_time, "w" )

    def _method_1(self, type, t, c, old_c, rate):
        # This concept is:
        # if the correlation is high and the latency is high
        # then lower the bandwidth limit.
        # otherwise, raise it.

        if ((c > 0.96) and (t > 100)): 
            rate /= 2.0
            if debug:
                print type, "down to", rate
        else:
            rate += 500 # hmm
            if debug:
                print type, "up to", rate
        return rate
    
    def _method_2(self, type, t, c, old_c, rate):
        # This concept is:
        # if the correlation is low and the latency is high, lower the limit
        # otherwise raise it

        if ((c < 0.60) and (t > 100)): 
            rate /= 2.0
            if debug: 
                print type, "down to", rate
        else:
            rate += 500 # hmm
            if debug:
                print type, "up to", rate
        return rate

    def _method_vegasish(self, type, t, c, old_c, rate):

        middle_rtt = ((self.rttmonitor.get_min_rtt() +
                       self.rttmonitor.get_max_rtt()) / 2.0)
        if t > middle_rtt:
            rate *= 1.0/8.0
            if debug:
                print type, "down to", rate
        else:
            rate += 1000 # hmm
            if debug:
                print type, "up to", rate
        return rate            

    def _method_vegas_greg(self, type, t, c, old_c, rate):

        middle_rtt = ((self.rttmonitor.get_min_rtt() +
                       self.rttmonitor.get_max_rtt()) / 2.0)
        if t > middle_rtt and c < 0.5:
            rate *= 1.0/8.0
            if debug:
                print type, "down to", rate
        else:
            rate += 1000 # hmm
            if debug:
                print type, "up to", rate
        return rate            

    def _method_ratio(self, type, t, p, min_p, max_p, rate):
        ratio = p / max_p
        if debug:
            print "RATIO", ratio
        if ratio < 0.5:
            rate = ratio * self.max_rates[type]
            if debug:
                print type.upper(), "SET to", rate
        else:
            rate += rate * (ratio/10.0) # hmm
            if debug:
                print type.upper(), "UP to", rate
                
        return max(rate, 1000)


    def _method_stddev(self, type, std, max_std, rate):
        if std > (max_std * 0.80): # FUDGE
            rate *= 0.80 # FUDGE
            if debug:
                print type.upper(), "DOWN to", rate
        else:
            rate += 1000 # FUDGE
            if debug:
                print type.upper(), "UP to", rate

        return max(rate, 1000) # FUDGE
    
    
    def _affect_rate(self, type, std, max_std, rate, set):
        rate = self._method_stddev(type, std, max_std, rate)

        rock_bottom = False
        if rate <= 4096:
            if debug:
                print "Rock bottom"
            rock_bottom = True
            rate = 4096
    
        set(int(rate))

        if stats:
            print "BandwidthManager._affect_rate(%f)" % rate
            self.rfp.write( "%d %d" % (bttime(),int(rate)) )
            self.sdevfp.write( "%d %f" % (bttime(), std ) )

        return rock_bottom
        

    def _inspect_rates(self, t = None):

        if t == None:
            t = self.rttmonitor.get_current_rtt()

        if t == None:
            # this makes timeouts reduce the maximum std deviation
            self.max_std *= 0.80 # FUDGE
            return

        if self.start_time == None:
            self.start_time = bttime()

        if debug:
            print "BandwidthManager._inspect_rates rtt: %d" % t
        if stats:
            self.dfp.write( "%d %d" % (bttime(),t) )

        def set_if_enabled(option, value):
            if not self.config['bandwidth_management']:
                return
            if debug:
                print "Setting %s to: %s" % (option, value)
            self.set_option(option, value)

        # TODO: slow start should be smarter than this
        if self.start_time + 20 > bttime():
            if debug:
                print 'SLOW START', fp(self.start_time + 20), fp(bttime())
            set_if_enabled('max_upload_rate', 10000000)
            set_if_enabled('max_download_rate', 10000000)

        if t < 3:
            # I simply don't believe you. Go away.
            return

        tup = self.get_rates()
        if tup == None:
            return
        u, d = tup
        #print "udt", u, d, t
        #print "uprate, downrate=", u, d

        self.u.append(u)
        self.d.append(d)
        self.t.append(t)
        self.ur.append(self.config['max_upload_rate'])
        self.dr.append(self.config['max_download_rate'])

        #s = time.time()
        #cu = correlation(self.u, self.t)
        #cd = correlation(self.d, self.t)
        #cur = correlation(self.u, self.ur)
        #cdr = correlation(self.d, self.dr)
        #e = time.time()

        self.current_std = standard_deviation(self.t)
        
        pu = ratio_sum_lists(self.u, self.t)
        pd = ratio_sum_lists(self.d, self.t)
        if len(self.u) > 2:
            lp = [ x/y for x, y in itertools.izip(self.u, self.t) ]
            min_pu = min(*lp)
            max_pu = max(*lp)
        else:
            min_pu = u / t
            max_pu = u / t
        pu = u / t

        self.max_rates["upload"] = max(max(self.u), self.max_rates["upload"])
        self.max_rates["download"] = max(max(self.d), self.max_rates["download"])

        if debug:
            print 'urate:', fp(u), 'umax:', self.config['max_upload_rate'], \
                  'maxstd:', fp(self.max_std), 'std:', fp(self.current_std), \
                  'pu:', fp(pu), 'pd:', fp(pd)
        
        rb = self._affect_rate("upload", self.current_std, self.max_std,
                               self.config['max_upload_rate'],
                               lambda r : set_if_enabled('max_upload_rate', r))
        # don't adjust download rate, it's not nearly correlated enough
##        if rb:
##            v = int(self.config['max_download_rate'] * 0.90) # FUDGE
##            v = max(v, 2000) # FUDGE
##            set_if_enabled('max_download_rate', v) 
##        else:
##            v = int(self.config['max_download_rate'] + 6000) # FUDGE
##            set_if_enabled('max_download_rate', v) 
##        if debug:
##            print "DOWNLOAD SET to", v
            
        #self._affect_rate("download", t, cd, self.last_cd, pd,
        #                  self.config['max_download_rate'],
        #                  lambda r : self.set_option('max_download_rate', r))

        self.max_std = max(self.max_std, self.current_std)
Example #6
0
    def __init__(self, external_add_task, config, set_option,
                 get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."
        self.external_add_task = external_add_task
        self.config = config
        self.set_option = set_option
        self.get_rates = get_rates

        # Next few lines were added by David Harrison to use RTTMonitor2
        #if os.name == 'nt':
        #    icmp_impl = Win32Icmp()
        #elif os.name == 'posix':
        #    icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])
        def got_new_rtt(rtt):
            self.external_add_task(0, self._inspect_rates, rtt)

        #self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.rttmonitor = RTTMonitor(got_new_rtt)
        self.nodefeeder = NodeFeeder(external_add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = None

        self.max_samples = 10  # hmm...
        self.u = SizedList(self.max_samples)
        self.d = SizedList(self.max_samples)
        self.t = SizedList(self.max_samples * 2)
        self.ur = SizedList(self.max_samples)
        self.dr = SizedList(self.max_samples)

        self.current_std = 0.001
        self.max_std = 0.001
        self.last_max = bttime()

        self.max_rates = {}
        self.max_rates["upload"] = 1.0
        self.max_rates["download"] = 1.0
        self.max_p = 1.0
        self.min_p = 2**500
        self.mid_p = ((self.max_p - self.min_p) / 2.0) + self.min_p
        self.old_p = None

        # I pulled these numbers out of my ass.

        if stats:
            tmp_dir = platform.get_temp_dir()
            timestr = "%d_%d_%d_%d_%d" % time.localtime()[1:6]
            stats_dir = os.path.join(
                tmp_dir, "bittorrent%s_%d" % (timestr, os.getpid()))
            os.mkdir(stats_dir)
            if debug: print "BandwidthManager: stats_dir = %s" % stats_dir
            rate_vs_time = os.path.join(stats_dir, "rate_vs_time.plotdata")
            self.rfp = open(rate_vs_time, "w")
            delay_vs_time = os.path.join(stats_dir, "delay_vs_time.plotdata")
            self.dfp = open(delay_vs_time, "w")
            sdev_vs_time = os.path.join(stats_dir, "stddev_vs_time.plotdata")
            self.sdevfp = open(sdev_vs_time, "w")
Example #7
0
class BandwidthManager(object):
    def __init__(self, external_add_task, config, set_option,
                 get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."
        self.external_add_task = external_add_task
        self.config = config
        self.set_option = set_option
        self.get_rates = get_rates

        # Next few lines were added by David Harrison to use RTTMonitor2
        #if os.name == 'nt':
        #    icmp_impl = Win32Icmp()
        #elif os.name == 'posix':
        #    icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])
        def got_new_rtt(rtt):
            self.external_add_task(0, self._inspect_rates, rtt)

        #self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.rttmonitor = RTTMonitor(got_new_rtt)
        self.nodefeeder = NodeFeeder(external_add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = None

        self.max_samples = 10  # hmm...
        self.u = SizedList(self.max_samples)
        self.d = SizedList(self.max_samples)
        self.t = SizedList(self.max_samples * 2)
        self.ur = SizedList(self.max_samples)
        self.dr = SizedList(self.max_samples)

        self.current_std = 0.001
        self.max_std = 0.001
        self.last_max = bttime()

        self.max_rates = {}
        self.max_rates["upload"] = 1.0
        self.max_rates["download"] = 1.0
        self.max_p = 1.0
        self.min_p = 2**500
        self.mid_p = ((self.max_p - self.min_p) / 2.0) + self.min_p
        self.old_p = None

        # I pulled these numbers out of my ass.

        if stats:
            tmp_dir = platform.get_temp_dir()
            timestr = "%d_%d_%d_%d_%d" % time.localtime()[1:6]
            stats_dir = os.path.join(
                tmp_dir, "bittorrent%s_%d" % (timestr, os.getpid()))
            os.mkdir(stats_dir)
            if debug: print "BandwidthManager: stats_dir = %s" % stats_dir
            rate_vs_time = os.path.join(stats_dir, "rate_vs_time.plotdata")
            self.rfp = open(rate_vs_time, "w")
            delay_vs_time = os.path.join(stats_dir, "delay_vs_time.plotdata")
            self.dfp = open(delay_vs_time, "w")
            sdev_vs_time = os.path.join(stats_dir, "stddev_vs_time.plotdata")
            self.sdevfp = open(sdev_vs_time, "w")

    def _method_1(self, type, t, c, old_c, rate):
        # This concept is:
        # if the correlation is high and the latency is high
        # then lower the bandwidth limit.
        # otherwise, raise it.

        if ((c > 0.96) and (t > 100)):
            rate /= 2.0
            if debug:
                print type, "down to", rate
        else:
            rate += 500  # hmm
            if debug:
                print type, "up to", rate
        return rate

    def _method_2(self, type, t, c, old_c, rate):
        # This concept is:
        # if the correlation is low and the latency is high, lower the limit
        # otherwise raise it

        if ((c < 0.60) and (t > 100)):
            rate /= 2.0
            if debug:
                print type, "down to", rate
        else:
            rate += 500  # hmm
            if debug:
                print type, "up to", rate
        return rate

    def _method_vegasish(self, type, t, c, old_c, rate):

        middle_rtt = (
            (self.rttmonitor.get_min_rtt() + self.rttmonitor.get_max_rtt()) /
            2.0)
        if t > middle_rtt:
            rate *= 1.0 / 8.0
            if debug:
                print type, "down to", rate
        else:
            rate += 1000  # hmm
            if debug:
                print type, "up to", rate
        return rate

    def _method_vegas_greg(self, type, t, c, old_c, rate):

        middle_rtt = (
            (self.rttmonitor.get_min_rtt() + self.rttmonitor.get_max_rtt()) /
            2.0)
        if t > middle_rtt and c < 0.5:
            rate *= 1.0 / 8.0
            if debug:
                print type, "down to", rate
        else:
            rate += 1000  # hmm
            if debug:
                print type, "up to", rate
        return rate

    def _method_ratio(self, type, t, p, min_p, max_p, rate):
        ratio = p / max_p
        if debug:
            print "RATIO", ratio
        if ratio < 0.5:
            rate = ratio * self.max_rates[type]
            if debug:
                print type.upper(), "SET to", rate
        else:
            rate += rate * (ratio / 10.0)  # hmm
            if debug:
                print type.upper(), "UP to", rate

        return max(rate, 1000)

    def _method_stddev(self, type, std, max_std, rate):
        top = 0.80  # FUDGE
        if std > (max_std * top):
            center = 1.0 + top - ((1.0 - top) * 0.5)
            s = min(std / max(0.0001, max_std), center)
            s = center - s
            rate *= s
            if debug:
                print type.upper(), "DOWN *", s, "to", rate
        else:
            s = 1000.0  # FUDGE
            s *= min(max_std / max(0.0001, std), 4) / 4.0
            s = int(s)
            rate += s
            if debug:
                print type.upper(), "UP +", s, "to", rate

        return max(rate, 1000)  # FUDGE

    def _affect_rate(self, type, std, max_std, rate, set):
        rate = self._method_stddev(type, std, max_std, rate)

        rock_bottom = False
        if rate <= 4096:
            if debug:
                print "Rock bottom"
            rock_bottom = True
            rate = 4096

        set(int(rate))

        if stats:
            print "BandwidthManager._affect_rate(%f)" % rate
            self.rfp.write("%d %d" % (bttime(), int(rate)))
            self.sdevfp.write("%d %f" % (bttime(), std))

        return rock_bottom

    def _inspect_rates(self, t=None):

        if t == None:
            t = self.rttmonitor.get_current_rtt()

        if t == None:
            # this makes timeouts reduce the maximum std deviation
            self.max_std *= 0.80  # FUDGE
            return

        if self.start_time == None:
            self.start_time = bttime()

        if debug:
            print "BandwidthManager._inspect_rates rtt: %d" % t
        if stats:
            self.dfp.write("%d %d" % (bttime(), t))

        def set_if_enabled(option, value):
            if not self.config['bandwidth_management']:
                return
            if debug:
                print "Setting %s to: %s" % (option, value)
            self.set_option(option, value)

        # TODO: slow start should be smarter than this
        if self.start_time + 20 > bttime():
            if debug:
                print 'SLOW START', fp(self.start_time + 20), fp(bttime())
            set_if_enabled('max_upload_rate', 10000000)
            set_if_enabled('max_download_rate', 10000000)

        if t < 3:
            # I simply don't believe you. Go away.
            return

        tup = self.get_rates()
        if tup == None:
            return
        u, d = tup
        #print "udt", u, d, t
        #print "uprate, downrate=", u, d

        self.u.append(u)
        self.d.append(d)
        self.t.append(t)
        self.ur.append(self.config['max_upload_rate'])
        self.dr.append(self.config['max_download_rate'])

        #s = time.time()
        #cu = correlation(self.u, self.t)
        #cd = correlation(self.d, self.t)
        #cur = correlation(self.u, self.ur)
        #cdr = correlation(self.d, self.dr)
        #e = time.time()

        self.current_std = standard_deviation(self.t)

        pu = ratio_sum_lists(self.u, self.t)
        pd = ratio_sum_lists(self.d, self.t)
        if len(self.u) > 2:
            lp = [x / y for x, y in itertools.izip(self.u, self.t)]
            min_pu = min(*lp)
            max_pu = max(*lp)
        else:
            min_pu = u / t
            max_pu = u / t
        pu = u / t

        self.max_rates["upload"] = max(max(self.u), self.max_rates["upload"])
        self.max_rates["download"] = max(max(self.d),
                                         self.max_rates["download"])

        if debug:
            print 'urate:', fp(u), 'umax:', self.config['max_upload_rate'], \
                  'maxstd:', fp(self.max_std), 'std:', fp(self.current_std), \
                  'pu:', fp(pu), 'pd:', fp(pd)

        rb = self._affect_rate("upload", self.current_std, self.max_std,
                               self.config['max_upload_rate'],
                               lambda r: set_if_enabled('max_upload_rate', r))
        # don't adjust download rate, it's not nearly correlated enough
        ##        if rb:
        ##            v = int(self.config['max_download_rate'] * 0.90) # FUDGE
        ##            v = max(v, 2000) # FUDGE
        ##            set_if_enabled('max_download_rate', v)
        ##        else:
        ##            v = int(self.config['max_download_rate'] + 6000) # FUDGE
        ##            set_if_enabled('max_download_rate', v)
        ##        if debug:
        ##            print "DOWNLOAD SET to", v

        #self._affect_rate("download", t, cd, self.last_cd, pd,
        #                  self.config['max_download_rate'],
        #                  lambda r : self.set_option('max_download_rate', r))

        if self.current_std > self.max_std:
            self.max_std = self.current_std
            self.last_max = bttime()
        elif bttime() - self.last_max > 10:
            # decay old maximums, to recover from flakey connections
            self.max_std *= 0.90  # FUDGE
            self.last_max = bttime()
class BandwidthManager(object):
    
    def __init__(self, external_add_task, config, set_option,
                       get_remote_endpoints, get_rates):
        self.external_add_task = external_add_task
        self.config = config
        self.set_option = set_option
        self.get_rates = get_rates
        def got_new_rtt(rtt):
            self.external_add_task(0, self._inspect_rates, rtt)
        self.rttmonitor = RTTMonitor(got_new_rtt)
        self.nodefeeder = NodeFeeder(external_add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = None

        self.max_samples = 10 # hmm...
        self.u = SizedList(self.max_samples)
        self.d = SizedList(self.max_samples)
        self.t = SizedList(self.max_samples * 10)
        self.ur = SizedList(self.max_samples)
        self.dr = SizedList(self.max_samples)

        self.current_std = 0.001        
        self.max_std = 0.001

        self.max_rates = {}
        self.max_rates["upload"] = 1.0
        self.max_rates["download"] = 1.0
        self.max_p = 1.0
        self.min_p = 2**500
        self.mid_p = ((self.max_p - self.min_p) / 2.0) + self.min_p
        self.old_p = None

    # I pulled these numbers out of my ass.

    def _method_1(self, type, t, c, old_c, rate):
        # This concept is:
        # if the correlation is high and the latency is high
        # then lower the bandwidth limit.
        # otherwise, raise it.

        if ((c > 0.96) and (t > 100)): 
            rate /= 2.0
            if debug:
                print type, "down to", rate
        else:
            rate += 500 # hmm
            if debug:
                print type, "up to", rate
        return rate
    
    def _method_2(self, type, t, c, old_c, rate):
        # This concept is:
        # if the correlation is low and the latency is high, lower the limit
        # otherwise raise it

        if ((c < 0.60) and (t > 100)): 
            rate /= 2.0
            if debug: 
                print type, "down to", rate
        else:
            rate += 500 # hmm
            if debug:
                print type, "up to", rate
        return rate

    def _method_vegasish(self, type, t, c, old_c, rate):

        middle_rtt = ((self.rttmonitor.get_min_rtt() +
                       self.rttmonitor.get_max_rtt()) / 2.0)
        if t > middle_rtt:
            rate *= 1.0/8.0
            if debug:
                print type, "down to", rate
        else:
            rate += 1000 # hmm
            if debug:
                print type, "up to", rate
        return rate            

    def _method_vegas_greg(self, type, t, c, old_c, rate):

        middle_rtt = ((self.rttmonitor.get_min_rtt() +
                       self.rttmonitor.get_max_rtt()) / 2.0)
        if t > middle_rtt and c < 0.5:
            rate *= 1.0/8.0
            if debug:
                print type, "down to", rate
        else:
            rate += 1000 # hmm
            if debug:
                print type, "up to", rate
        return rate            

    def _method_ratio(self, type, t, p, min_p, max_p, rate):
        ratio = p / max_p
        if debug:
            print "RATIO", ratio
        if ratio < 0.5:
            rate = ratio * self.max_rates[type]
            if debug:
                print type.upper(), "SET to", rate
        else:
            rate += rate * (ratio/10.0) # hmm
            if debug:
                print type.upper(), "UP to", rate
                
        return max(rate, 1000)


    def _method_stddev(self, type, std, max_std, rate):
        if std > (max_std * 0.80): # FUDGE
            rate *= 0.80 # FUDGE
            if debug:
                print type.upper(), "DOWN to", rate
        else:
            rate += 1000 # FUDGE
            if debug:
                print type.upper(), "UP to", rate

        return max(rate, 1000) # FUDGE
    
    
    def _affect_rate(self, type, std, max_std, rate, set):
        rate = self._method_stddev(type, std, max_std, rate)

        rock_bottom = False
        if rate <= 4096:
            if debug:
                print "Rock bottom"
            rock_bottom = True
            rate = 4096
    
        set(int(rate))

        return rock_bottom
        

    def _inspect_rates(self, t = None):

        if t == None:
            t = self.rttmonitor.get_current_rtt()

        if t == None:
            # this makes timeouts reduce the maximum std deviation
            self.max_std *= 0.80 # FUDGE
            return

        if self.start_time == None:
            self.start_time = bttime()
        def set_if_enabled(option, value):
            if not self.config['bandwidth_management']:
                return
            #print "Setting rate to ", value
            self.set_option(option, value)

        # TODO: slow start should be smarter than this
        if self.start_time + 20 > bttime():
            set_if_enabled('max_upload_rate', 10000000)
            set_if_enabled('max_download_rate', 10000000)

        if t < 3:
            # I simply don't believe you. Go away.
            return

        tup = self.get_rates()
        if tup == None:
            return
        u, d = tup
        #print "udt", u, d, t
        #print "uprate, downrate=", u, d

        self.u.append(u)
        self.d.append(d)
        self.t.append(t)
        self.ur.append(self.config['max_upload_rate'])
        self.dr.append(self.config['max_download_rate'])

        #s = time.time()
        #cu = correlation(self.u, self.t)
        #cd = correlation(self.d, self.t)
        #cur = correlation(self.u, self.ur)
        #cdr = correlation(self.d, self.dr)
        #e = time.time()

        self.current_std = standard_deviation(self.t)
        
        pu = ratio_sum_lists(self.u, self.t)
        pd = ratio_sum_lists(self.d, self.t)
        if len(self.u) > 2:
            lp = [ x/y for x, y in itertools.izip(self.u, self.t) ]
            min_pu = min(*lp)
            max_pu = max(*lp)
        else:
            min_pu = u / t
            max_pu = u / t
        pu = u / t

        self.max_rates["upload"] = max(max(self.u), self.max_rates["upload"])
        self.max_rates["download"] = max(max(self.d), self.max_rates["download"])

        if debug:
            print "STDDEV", u, self.config['max_upload_rate'], \
                  self.max_std, self.current_std, pu, pd
        
        rb = self._affect_rate("upload", self.current_std, self.max_std,
                               self.config['max_upload_rate'],
                               lambda r : set_if_enabled('max_upload_rate', r))
        # don't adjust download rate, it's not nearly correlated enough
##        if rb:
##            v = int(self.config['max_download_rate'] * 0.90) # FUDGE
##            v = max(v, 2000) # FUDGE
##            set_if_enabled('max_download_rate', v) 
##        else:
##            v = int(self.config['max_download_rate'] + 6000) # FUDGE
##            set_if_enabled('max_download_rate', v) 
##        if debug:
##            print "DOWNLOAD SET to", v
            
        #self._affect_rate("download", t, cd, self.last_cd, pd,
        #                  self.config['max_download_rate'],
        #                  lambda r : self.set_option('max_download_rate', r))

        self.max_std = max(self.max_std, self.current_std)

        #self.last_cu = cu
        #self.last_cd = cd

        # we're re-called by the pinging thing
        #self.external_add_task(0.1, self._inspect_rates)
        
        
    def __init__(self, external_add_task, config, set_config,
                       get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."
        
        self.external_add_task = external_add_task
        self.config = config
        self.set_config = set_config
        self.get_rates = get_rates
        if os.name == 'nt':
            icmp_impl = Win32Icmp()
        elif os.name == 'posix':
            icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])
        def got_new_rtt(rtt):
            print "got_new_rtt, rtt=", rtt
            self.external_add_task(0, self._inspect_rates, rtt)
        self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.nodefeeder = NodeFeeder(add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = bttime()

        if config['control_law'] == 'aimd':
            self.control_law = AIMDControlLaw(config['increase_delta'],
                                              config['decrease_factor'])
        elif config['control_law'] == 'aiad':
            self.control_law = AIADControlLaw(config['increase_delta'],
                                              config['decrease_delta'])

        # This configurability is temporary during testing/tuning.  --Dave
        if config['congestion_estimator'] == "chebyshev":
            self.congestion_estimator = ChebyshevCongestionEstimator(
                config['window_size'], config['drop_every_nth'],
                config['cheby_max_probability'],
                config['cheby_max_consecutive'],
                config['cheby_max_threshold'], config['ewma'])
            
        elif config['congestion_estimator'] == "variance":
            self.congestion_estimator = VarianceCongestionEstimator(
                config['window_size'])
        elif config['congestion_estimator'] == "vegasish":
            self.congestion_estimator = VegasishCongestionEstimator(
                config['window_size'], config['drop_every_nth'])
        else:
            raise BTFailure(_("Unrecognized congestion estimator '%s'.") %
                config['congestion_estimator'])

        self.starvation_prevention = FixedStarvationPrevention(
            config['min_upload_rate_limit'] )

        if stats:
            rlimit_vs_time = \
                           os.path.join( stats_dir, "rlimit_vs_time.plotdata" )
            fp = open( rlimit_vs_time, "w" )
            self.control_law = StreamTracer(self.control_law, fp)
            _copy_gnuplot( "rlimit_vs_time.gnuplot" )

            # samples are max(min_upload_rate_limit,rate).
            slimit_vs_time = \
                           os.path.join( stats_dir, "slimit_vs_time.plotdata" )
            fp = open( slimit_vs_time, "w" )
            self.starvation_prevention = StreamTracer(
                self.starvation_prevention, fp)
            
            delay_vs_time = os.path.join( stats_dir, "delay_vs_time.plotdata" )
            self.dfp = open( delay_vs_time, "w" )
            _copy_gnuplot( "delay_vs_time.gnuplot" )
class BandwidthManager(object):
    """Controls allocation of bandwidth between foreground and background
       traffic.  Currently all BitTorrent traffic is considered background.
       Background traffic is subjected to a global rate limit that is
       reduced during congestion to allow foreground traffic to takeover.

       A 'starvation prevention' building block applies a lower bound.
       """    
    def __init__(self, external_add_task, config, set_config,
                       get_remote_endpoints, get_rates):
        if debug:
            if config['bandwidth_management']:
                print "bandwidth management is up."
            else:
                print "!@#!@#!@#!@#!@# bandwidth management is down."
        
        self.external_add_task = external_add_task
        self.config = config
        self.set_config = set_config
        self.get_rates = get_rates
        if os.name == 'nt':
            icmp_impl = Win32Icmp()
        elif os.name == 'posix':
            icmp_impl = UnixIcmp(external_add_task, config['xicmp_port'])
        def got_new_rtt(rtt):
            print "got_new_rtt, rtt=", rtt
            self.external_add_task(0, self._inspect_rates, rtt)
        self.rttmonitor = RTTMonitor(got_new_rtt, icmp_impl)
        self.nodefeeder = NodeFeeder(add_task=external_add_task,
                                     get_remote_endpoints=get_remote_endpoints,
                                     rttmonitor=self.rttmonitor)

        self.start_time = bttime()

        if config['control_law'] == 'aimd':
            self.control_law = AIMDControlLaw(config['increase_delta'],
                                              config['decrease_factor'])
        elif config['control_law'] == 'aiad':
            self.control_law = AIADControlLaw(config['increase_delta'],
                                              config['decrease_delta'])

        # This configurability is temporary during testing/tuning.  --Dave
        if config['congestion_estimator'] == "chebyshev":
            self.congestion_estimator = ChebyshevCongestionEstimator(
                config['window_size'], config['drop_every_nth'],
                config['cheby_max_probability'],
                config['cheby_max_consecutive'],
                config['cheby_max_threshold'], config['ewma'])
            
        elif config['congestion_estimator'] == "variance":
            self.congestion_estimator = VarianceCongestionEstimator(
                config['window_size'])
        elif config['congestion_estimator'] == "vegasish":
            self.congestion_estimator = VegasishCongestionEstimator(
                config['window_size'], config['drop_every_nth'])
        else:
            raise BTFailure(_("Unrecognized congestion estimator '%s'.") %
                config['congestion_estimator'])

        self.starvation_prevention = FixedStarvationPrevention(
            config['min_upload_rate_limit'] )

        if stats:
            rlimit_vs_time = \
                           os.path.join( stats_dir, "rlimit_vs_time.plotdata" )
            fp = open( rlimit_vs_time, "w" )
            self.control_law = StreamTracer(self.control_law, fp)
            _copy_gnuplot( "rlimit_vs_time.gnuplot" )

            # samples are max(min_upload_rate_limit,rate).
            slimit_vs_time = \
                           os.path.join( stats_dir, "slimit_vs_time.plotdata" )
            fp = open( slimit_vs_time, "w" )
            self.starvation_prevention = StreamTracer(
                self.starvation_prevention, fp)
            
            delay_vs_time = os.path.join( stats_dir, "delay_vs_time.plotdata" )
            self.dfp = open( delay_vs_time, "w" )
            _copy_gnuplot( "delay_vs_time.gnuplot" )

    #def congestion_estimator_vegas_greg(self, rtt, rate):
    #
    #    middle_rtt = ((self.propagation_estimator(rtt) +
    #                   self.delay_on_full_estimator(rtt)) / 2.0 )
    #    if t > middle_rtt and c < 0.5:
    #        rate *= 0.5
    #        if debug:
    #            print type, "down to", rate
    #    else:
    #        rate += 1000 # hmm
    #        if debug:
    #            print type, "up to", rate
    #    return rate            

    #def congestion_estimator_ratio(self, type, t, p, min_p, max_p, rate):
    #    ratio = p / max_p
    #    if debug:
    #        print "RATIO", ratio
    #    if ratio < 0.5:
    #        rate = ratio * self.max_rates[type]
    #        if debug:
    #            print type.upper(), "SET to", rate
    #    else:
    #        rate += rate * (ratio/10.0) # hmm
    #        if debug:
    #            print type.upper(), "UP to", rate
    #            
    #    return max(rate, 1000)

    #def congestion_estimator_stddev(self, type, std, max_std, rate):
    #    if std > (max_std * 0.80): # FUDGE
    #        rate *= 0.80 # FUDGE
    #        if debug:
    #            print type.upper(), "DOWN to", rate
    #    else:
    #        rate += 1000 # FUDGE
    #        if debug:
    #            print type.upper(), "UP to", rate
    #
    #    return max(rate, 1000) # FUDGE
    
    #def _affect_rate(self, type, std, max_std, rate, set):
    #    rate = self._congestion_estimator_stddev(type, std, max_std, rate)
    #
    #    rock_bottom = False
    #    if rate <= 1000:
    #        if debug:
    #            print "Rock bottom"
    #        rock_bottom = True
    #        rate = 1000
    #
    #    set(int(rate))
    #    if stats:
    #        print "BandwidthManager._affect_rate(%f)" % rate
    #        self.rfp.write( "%d\t%d\n" % (bttime(),int(rate)) )
    #        self.sdevfp.write( "%d\t%f\n" % (bttime(), std ) )
    #
    #    return rock_bottom

    def _inspect_rates(self, t = None):
        """Called whenever an RTT sample arrives. If t == None then
           a timeout occurred."""
        if t == None:
            t = self.rttmonitor.get_current_rtt()

        if t == None:
            # this makes timeouts reduce the maximum std deviation
            self.congestion_estimator.timeout()
            return

        if debug:
            print "BandwidthManager._inspect_rates: %d" % t
        if stats:
            self.dfp.write( "%f\t%f\n" % (bttime(),t) )

        if not self.config['bandwidth_management']:
            return

        # TODO: slow start should be smarter than this
        #if self.start_time < bttime() + 20:
        #    self.config['max_upload_rate'] = 10000000
        #    self.config['max_dowload_rate'] = 10000000

        #if t < 3:
        #    # I simply don't believe you. Go away.
        #    return

        tup = self.get_rates() 
        if tup == None:
            return
        uprate, downrate = tup

        # proceed through the building blocks.  (We can swap in various
        # implementations of each based on config).
        is_congested = self.congestion_estimator(t,uprate)
        rate_limit = self.control_law(is_congested,uprate)
        rate_limit = self.starvation_prevention(rate_limit)
        self._set_rate_limit(rate_limit)

    def _set_rate_limit(self,rate_limit):
        self.set_config('max_upload_rate', rate_limit)