From e09457e4ab17549cb0d67a93a9fb8cfafdd5a064 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 5 May 2008 17:08:14 +0000 Subject: [PATCH] take an estimate of the IP ACK traffic into account when rate limiting (allows setting rate limits closer to the capacity) --- include/libtorrent/bandwidth_manager.hpp | 25 +++++++++++++++++++++++ include/libtorrent/peer_connection.hpp | 2 ++ include/libtorrent/stat.hpp | 26 ++++++++++++++++++++++-- src/peer_connection.cpp | 5 +++++ src/session_impl.cpp | 4 ++++ src/torrent.cpp | 1 + 6 files changed, 61 insertions(+), 2 deletions(-) diff --git a/include/libtorrent/bandwidth_manager.hpp b/include/libtorrent/bandwidth_manager.hpp index 42dc4ba7e..ef58337c5 100644 --- a/include/libtorrent/bandwidth_manager.hpp +++ b/include/libtorrent/bandwidth_manager.hpp @@ -76,6 +76,8 @@ struct history_entry history_entry(intrusive_ptr p, weak_ptr t , int a, ptime exp) : expires_at(exp), amount(a), peer(p), tor(t) {} + history_entry(int a, ptime exp) + : expires_at(exp), amount(a), peer(), tor() {} ptime expires_at; int amount; intrusive_ptr peer; @@ -111,6 +113,7 @@ struct bandwidth_manager : m_ios(ios) , m_history_timer(m_ios) , m_limit(bandwidth_limit::inf) + , m_drain_quota(0) , m_current_quota(0) , m_channel(channel) , m_in_hand_out_bandwidth(false) @@ -123,6 +126,14 @@ struct bandwidth_manager #endif } + void drain(int bytes) + { + mutex_t::scoped_lock l(m_mutex); + TORRENT_ASSERT(bytes >= 0); + m_drain_quota += bytes; + if (m_drain_quota > m_limit * 5) m_drain_quota = m_limit * 5; + } + void throttle(int limit) { mutex_t::scoped_lock l(m_mutex); @@ -288,6 +299,7 @@ private: << std::endl; #endif intrusive_ptr c = e.peer; + if (!c) continue; shared_ptr t = e.tor.lock(); l.unlock(); if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount); @@ -329,6 +341,15 @@ private: if (amount <= 0) return; + if (m_drain_quota > 0) + { + int drain_amount = (std::min)(m_drain_quota, amount); + m_drain_quota -= drain_amount; + amount -= drain_amount; + add_history_entry(history_entry( + drain_amount, now + bw_window_size)); + } + queue_t tmp; while (!m_queue.empty() && amount > 0) { @@ -433,6 +454,10 @@ private: // the rate limit (bytes per second) int m_limit; + // bytes to drain without handing out to a peer + // used to deduct the IP overhead + int m_drain_quota; + // the sum of all recently handed out bandwidth blocks int m_current_quota; diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 28b452063..709560962 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -230,6 +230,8 @@ namespace libtorrent const stat& statistics() const { return m_statistics; } void add_stat(size_type downloaded, size_type uploaded); + void calc_ip_overhead(); + // is called once every second by the main loop void second_tick(float tick_interval); diff --git a/include/libtorrent/stat.hpp b/include/libtorrent/stat.hpp index 0087fcad0..84daec3af 100755 --- a/include/libtorrent/stat.hpp +++ b/include/libtorrent/stat.hpp @@ -140,6 +140,24 @@ namespace libtorrent m_stat[upload_protocol].add(bytes_protocol); } + // calculate ip protocol overhead + void calc_ip_overhead() + { + // traffic balance is the number of bytes we downloaded + // more than we uploaded + int traffic_balance = m_stat[download_protocol].counter() + + m_stat[download_payload].counter() + - m_stat[upload_protocol].counter() + - m_stat[upload_payload].counter(); + if (traffic_balance > 0) + m_stat[upload_ip_protocol].add(traffic_balance / 20); + else + m_stat[download_ip_protocol].add(-traffic_balance / 20); + } + + int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); } + int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); } + // should be called once every second void second_tick(float tick_interval) { @@ -150,13 +168,15 @@ namespace libtorrent float upload_rate() const { return m_stat[upload_payload].rate() - + m_stat[upload_protocol].rate(); + + m_stat[upload_protocol].rate() + + m_stat[upload_ip_protocol].rate(); } float download_rate() const { return m_stat[download_payload].rate() - + m_stat[download_protocol].rate(); + + m_stat[download_protocol].rate() + + m_stat[download_ip_protocol].rate(); } float upload_payload_rate() const @@ -198,8 +218,10 @@ namespace libtorrent { upload_payload, upload_protocol, + upload_ip_protocol, download_payload, download_protocol, + download_ip_protocol, num_channels }; diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 3651c0e7a..350b6c7aa 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -2413,6 +2413,11 @@ namespace libtorrent m_packet_size = packet_size; } + void peer_connection::calc_ip_overhead() + { + m_statistics.calc_ip_overhead(); + } + void peer_connection::second_tick(float tick_interval) { INVARIANT_CHECK; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index a0f64230c..3e8632825 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1046,6 +1046,10 @@ namespace aux { ++i; } + // drain the IP overhead from the bandwidth limiters + m_download_channel.drain(m_stat.download_ip_overhead()); + m_upload_channel.drain(m_stat.upload_ip_overhead()); + m_stat.second_tick(tick_interval); diff --git a/src/torrent.cpp b/src/torrent.cpp index a1dfe0e79..444b1d38c 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -3489,6 +3489,7 @@ namespace libtorrent { peer_connection* p = *i; ++i; + p->calc_ip_overhead(); m_stat += p->statistics(); // updates the peer connection's ul/dl bandwidth // resource requests