forked from premiere/premiere-libtorrent
fix overflow in sliding_average in the case of very high download rates
This commit is contained in:
parent
949867eca9
commit
a4267d61e7
|
@ -119,7 +119,7 @@ private:
|
|||
// have higher priority
|
||||
vector<piece_index_t, int> m_priority_pieces;
|
||||
|
||||
sliding_average<30> m_availability;
|
||||
sliding_average<int, 30> m_availability;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -47,7 +47,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/error_code.hpp"
|
||||
#include "libtorrent/io_service_fwd.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/sliding_average.hpp"
|
||||
#include "libtorrent/tailqueue.hpp"
|
||||
#include "libtorrent/linked_list.hpp"
|
||||
#include "libtorrent/disk_buffer_pool.hpp"
|
||||
|
|
|
@ -39,7 +39,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/allocator.hpp"
|
||||
#include "libtorrent/io_service.hpp"
|
||||
#include "libtorrent/sliding_average.hpp"
|
||||
#include "libtorrent/disk_io_thread_pool.hpp"
|
||||
#include "libtorrent/disk_io_job.hpp"
|
||||
#include "libtorrent/disk_job_pool.hpp"
|
||||
|
|
|
@ -842,7 +842,7 @@ namespace aux {
|
|||
// outstanding request, the time since the piece was requested. It
|
||||
// is essentially an estimate of the time it will take to completely
|
||||
// receive a payload message after it has been requested.
|
||||
sliding_average<20> m_request_time;
|
||||
sliding_average<int, 20> m_request_time;
|
||||
|
||||
// keep the io_service running as long as we
|
||||
// have peer connections
|
||||
|
|
|
@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/buffer.hpp"
|
||||
#include "libtorrent/disk_buffer_holder.hpp"
|
||||
#include "libtorrent/sliding_average.hpp"
|
||||
#include "libtorrent/aux_/numeric_cast.hpp"
|
||||
|
||||
#include <climits>
|
||||
|
||||
|
@ -57,8 +58,8 @@ struct TORRENT_EXTRA_EXPORT receive_buffer
|
|||
|
||||
bool packet_finished() const { return m_packet_size <= m_recv_pos; }
|
||||
int pos() const { return m_recv_pos; }
|
||||
int capacity() const { return int(m_recv_buffer.size()); }
|
||||
int watermark() const { return m_watermark.mean(); }
|
||||
int capacity() const { return aux::numeric_cast<int>(m_recv_buffer.size()); }
|
||||
int watermark() const { return aux::numeric_cast<int>(m_watermark.mean()); }
|
||||
|
||||
span<char> reserve(int size);
|
||||
void grow(int limit);
|
||||
|
@ -154,7 +155,7 @@ private:
|
|||
|
||||
// keep track of how much of the receive buffer we use, if we're not using
|
||||
// enough of it we shrink it
|
||||
sliding_average<20> m_watermark;
|
||||
sliding_average<std::int64_t, 20> m_watermark;
|
||||
|
||||
buffer m_recv_buffer;
|
||||
};
|
||||
|
|
|
@ -35,26 +35,29 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <cstdint>
|
||||
#include <cstdlib> // for std::abs
|
||||
#include <limits>
|
||||
|
||||
#include "libtorrent/assert.hpp"
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
// an exponential moving average accumulator. Add samples to it and it keeps
|
||||
// track of a moving mean value and an average deviation
|
||||
template <int inverted_gain>
|
||||
template <typename Int, Int inverted_gain>
|
||||
struct sliding_average
|
||||
{
|
||||
static_assert(std::is_integral<Int>::value, "template argument must be integral");
|
||||
|
||||
sliding_average(): m_mean(0), m_average_deviation(0), m_num_samples(0) {}
|
||||
sliding_average(sliding_average const&) = default;
|
||||
sliding_average& operator=(sliding_average const&) = default;
|
||||
|
||||
void add_sample(int s)
|
||||
void add_sample(Int s)
|
||||
{
|
||||
TORRENT_ASSERT(s < std::numeric_limits<Int>::max() / 64);
|
||||
// fixed point
|
||||
s *= 64;
|
||||
int deviation = 0;
|
||||
|
||||
if (m_num_samples > 0)
|
||||
deviation = std::abs(m_mean - s);
|
||||
Int const deviation = (m_num_samples > 0) ? std::abs(m_mean - s) : 0;
|
||||
|
||||
if (m_num_samples < inverted_gain)
|
||||
++m_num_samples;
|
||||
|
@ -70,14 +73,14 @@ struct sliding_average
|
|||
}
|
||||
}
|
||||
|
||||
int mean() const { return m_num_samples > 0 ? (m_mean + 32) / 64 : 0; }
|
||||
int avg_deviation() const { return m_num_samples > 1 ? (m_average_deviation + 32) / 64 : 0; }
|
||||
Int mean() const { return m_num_samples > 0 ? (m_mean + 32) / 64 : 0; }
|
||||
Int avg_deviation() const { return m_num_samples > 1 ? (m_average_deviation + 32) / 64 : 0; }
|
||||
int num_samples() const { return m_num_samples; }
|
||||
|
||||
private:
|
||||
// both of these are fixed point values (* 64)
|
||||
int m_mean = 0;
|
||||
int m_average_deviation = 0;
|
||||
Int m_mean = 0;
|
||||
Int m_average_deviation = 0;
|
||||
// the number of samples we have received, but no more than inverted_gain
|
||||
// this is the effective inverted_gain
|
||||
int m_num_samples = 0;
|
||||
|
|
|
@ -60,7 +60,7 @@ span<char> receive_buffer::reserve(int const size)
|
|||
|
||||
// since we just increased the size of the buffer, reset the watermark to
|
||||
// start at our new size (avoid flapping the buffer size)
|
||||
m_watermark = sliding_average<20>();
|
||||
m_watermark = {};
|
||||
}
|
||||
|
||||
return aux::typed_span<char>(m_recv_buffer).subspan(m_recv_end, size);
|
||||
|
@ -83,7 +83,7 @@ void receive_buffer::grow(int const limit)
|
|||
|
||||
// since we just increased the size of the buffer, reset the watermark to
|
||||
// start at our new size (avoid flapping the buffer size)
|
||||
m_watermark = sliding_average<20>();
|
||||
m_watermark = {};
|
||||
}
|
||||
|
||||
int receive_buffer::advance_pos(int const bytes)
|
||||
|
@ -180,7 +180,7 @@ void receive_buffer::normalize(int const force_shrink)
|
|||
|
||||
// if the running average drops below half of the current buffer size,
|
||||
// reallocate a smaller one.
|
||||
bool const shrink_buffer = int(m_recv_buffer.size()) / 2 > m_watermark.mean()
|
||||
bool const shrink_buffer = std::int64_t(m_recv_buffer.size()) / 2 > m_watermark.mean()
|
||||
&& m_watermark.mean() > (m_recv_end - m_recv_start);
|
||||
|
||||
span<char const> bytes_to_shift(m_recv_buffer.data() + m_recv_start
|
||||
|
|
|
@ -472,7 +472,7 @@ struct utp_socket_impl
|
|||
std::int32_t m_recv_delay = 0;
|
||||
|
||||
// average RTT
|
||||
sliding_average<16> m_rtt;
|
||||
sliding_average<int, 16> m_rtt;
|
||||
|
||||
// if this is != 0, it means the upper layer provided a reason for why
|
||||
// the connection is being closed. The reason is indicated by this
|
||||
|
|
|
@ -211,6 +211,17 @@ TORRENT_TEST(receive_buffer_max_receive)
|
|||
TEST_EQUAL(b.max_receive(), max_receive - 20);
|
||||
}
|
||||
|
||||
TORRENT_TEST(receive_buffer_watermark)
|
||||
{
|
||||
receive_buffer b;
|
||||
b.reset(0x4000);
|
||||
b.reserve(35000000);
|
||||
b.received(35000000);
|
||||
b.normalize();
|
||||
|
||||
TEST_EQUAL(b.watermark(), 35000000);
|
||||
}
|
||||
|
||||
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
||||
|
||||
TORRENT_TEST(recv_buffer_mutable_buffers)
|
||||
|
|
|
@ -53,7 +53,7 @@ using namespace lt;
|
|||
// make sure we react quickly for the first few samples
|
||||
TORRENT_TEST(reaction_time)
|
||||
{
|
||||
sliding_average<10> avg;
|
||||
sliding_average<int, 10> avg;
|
||||
|
||||
avg.add_sample(-10);
|
||||
avg.add_sample(10);
|
||||
|
@ -63,7 +63,7 @@ TORRENT_TEST(reaction_time)
|
|||
|
||||
TORRENT_TEST(reaction_time2)
|
||||
{
|
||||
sliding_average<10> avg;
|
||||
sliding_average<int, 10> avg;
|
||||
|
||||
avg.add_sample(10);
|
||||
avg.add_sample(20);
|
||||
|
@ -74,7 +74,7 @@ TORRENT_TEST(reaction_time2)
|
|||
// make sure we converge
|
||||
TORRENT_TEST(converge)
|
||||
{
|
||||
sliding_average<10> avg;
|
||||
sliding_average<int, 10> avg;
|
||||
avg.add_sample(100);
|
||||
for (int i = 0; i < 20; ++i)
|
||||
avg.add_sample(10);
|
||||
|
@ -83,7 +83,7 @@ TORRENT_TEST(converge)
|
|||
|
||||
TORRENT_TEST(converge2)
|
||||
{
|
||||
sliding_average<10> avg;
|
||||
sliding_average<int, 10> avg;
|
||||
avg.add_sample(-100);
|
||||
for (int i = 0; i < 20; ++i)
|
||||
avg.add_sample(-10);
|
||||
|
@ -93,7 +93,7 @@ TORRENT_TEST(converge2)
|
|||
// test with a more realistic input
|
||||
TORRENT_TEST(random_converge)
|
||||
{
|
||||
sliding_average<10> avg;
|
||||
sliding_average<int, 10> avg;
|
||||
for (int i = 0; i < int(sizeof(samples)/sizeof(samples[0])); ++i)
|
||||
avg.add_sample(samples[i]);
|
||||
TEST_CHECK(abs(avg.mean() - 60) <= 3);
|
||||
|
@ -101,7 +101,7 @@ TORRENT_TEST(random_converge)
|
|||
|
||||
TORRENT_TEST(sliding_average)
|
||||
{
|
||||
sliding_average<4> avg;
|
||||
sliding_average<int, 4> avg;
|
||||
TEST_EQUAL(avg.mean(), 0);
|
||||
TEST_EQUAL(avg.avg_deviation(), 0);
|
||||
avg.add_sample(500);
|
||||
|
|
Loading…
Reference in New Issue