diff --git a/ChangeLog b/ChangeLog index 7d6c1923f..1b8b951d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -27,6 +27,7 @@ * almost completely changed the storage interface (for custom storage) * added support for hashing pieces in multiple threads + * made uTP re-enter slow-start after time-out * fixed uTP upload performance issue * fix missing support for DHT put salt @@ -96,6 +97,7 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * fixed bug in add_torrent_alert::message for magnet links * disable optimistic disconnects when connection limit is low * improved error handling of session::listen_on * suppress initial 'completed' announce to trackers added with replace_trackers diff --git a/src/alert.cpp b/src/alert.cpp index 049cf5463..b06ba0f7c 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -522,19 +522,22 @@ namespace libtorrent { std::string add_torrent_alert::message() const { char msg[600]; + char info_hash[41]; + char const* torrent_name = info_hash; + if (params.ti) torrent_name = params.ti->name().c_str(); + else if (!params.name.empty()) torrent_name = params.name.c_str(); + else if (!params.url.empty()) torrent_name = params.url.c_str(); + else to_hex((const char*)¶ms.info_hash[0], 20, info_hash); + if (error) { - snprintf(msg, sizeof(msg), "failed to add torrent: %s" + snprintf(msg, sizeof(msg), "failed to add torrent \"%s\": [%s] %s" + , torrent_name, error.category().name() , convert_from_native(error.message()).c_str()); } else { - snprintf(msg, sizeof(msg), "added torrent: %s" - , !params.url.empty() ? params.url.c_str() - : params.ti ? params.ti->name().c_str() - : !params.name.empty() ? params.name.c_str() - : !params.uuid.empty() ? params.uuid.c_str() - : ""); + snprintf(msg, sizeof(msg), "added torrent: %s", torrent_name); } return msg; } diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index 16ab4853e..3afb86360 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -236,6 +236,7 @@ struct utp_socket_impl , m_timeout(time_now_hires() + milliseconds(m_sm->connect_timeout())) , m_last_history_step(time_now_hires()) , m_cwnd(TORRENT_ETHERNET_MTU << 16) + , m_ssthres(0) , m_buffered_incoming_bytes(0) , m_reply_micro(0) , m_adv_wnd(TORRENT_ETHERNET_MTU) @@ -438,6 +439,11 @@ struct utp_socket_impl timestamp_history m_delay_hist; timestamp_history m_their_delay_hist; + // the slow-start threshold. This is the congestion window size (m_cwnd) + // in bytes the last time we left slow-start mode. This is used as a + // threshold to leave slow-start earlier next time, to avoid packet-loss + boost::int32_t m_ssthres; + // the number of bytes we have buffered in m_inbuf boost::int32_t m_buffered_incoming_bytes; @@ -2153,6 +2159,14 @@ void utp_socket_impl::experienced_loss(int seq_nr) // same packet again, ignore it. if (compare_less_wrap(seq_nr, m_loss_seq_nr + 1, ACK_MASK)) return; + // if we happen to be in slow-start mode, we need to leave it + if (m_slow_start) + { + m_ssthres = m_cwnd >> 16; + m_slow_start = false; + UTP_LOGV("%8p: experienced loss, slow_start -> 0\n", this); + } + // cut window size in 2 m_cwnd = (std::max)(m_cwnd * m_sm->loss_multiplier() / 100, boost::int64_t(m_mtu << 16)); m_loss_seq_nr = m_seq_nr; @@ -2161,8 +2175,6 @@ void utp_socket_impl::experienced_loss(int seq_nr) // the window size could go below one MMS here, if it does, // we'll get a timeout in about one second - // if we happen to be in slow-start mode, we need to leave it - m_slow_start = false; m_sm->inc_stats_counter(counters::utp_packet_loss); } @@ -3062,6 +3074,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size "send_buffer:%d " "recv_buffer:%d " "fast_resend_seq_nr:%d " + "ssthres:%d " "\n" , this , sample @@ -3093,7 +3106,8 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size , min_rtt / 1000 , m_write_buffer_size , m_read_buffer_size - , m_fast_resend_seq_nr); + , m_fast_resend_seq_nr + , m_ssthres); } #endif @@ -3222,10 +3236,13 @@ void utp_socket_impl::do_ledbat(int acked_bytes, int delay, int in_flight) if (delay >= target_delay) { if (m_slow_start) + { UTP_LOGV("%8p: off_target: %d slow_start -> 0\n", this, target_delay - delay); + m_ssthres = m_cwnd >> 16; + m_slow_start = false; + } m_sm->inc_stats_counter(counters::utp_samples_above_target); - m_slow_start = false; } else { @@ -3239,11 +3256,25 @@ void utp_socket_impl::do_ledbat(int acked_bytes, int delay, int in_flight) // congestion window), don't adjust it at all. if (cwnd_saturated) { + boost::int64_t exponential_gain = boost::int64_t(acked_bytes) << 16; if (m_slow_start) { // mimic TCP slow-start by adding the number of acked // bytes to cwnd - scaled_gain = (std::max)(boost::int64_t(acked_bytes) << 16, linear_gain); + if (m_ssthres != 0 && ((m_cwnd + exponential_gain) >> 16) > m_ssthres) + { + // if we would exeed the slow start threshold by growing the cwnd + // exponentially, don't do it, and leave slow-start mode. This + // make us avoid causing more delay and/or packet loss by being too + // aggressive + m_slow_start = false; + scaled_gain = linear_gain; + UTP_LOGV("%8p: cwnd > ssthres (%d) slow_start -> 0\n", this, m_ssthres); + } + else + { + scaled_gain = (std::max)(exponential_gain, linear_gain); + } } else { @@ -3288,7 +3319,11 @@ void utp_socket_impl::do_ledbat(int acked_bytes, int delay, int in_flight) } if ((m_cwnd >> 16) >= m_adv_wnd) + { m_slow_start = false; + UTP_LOGV("%8p: cwnd > advertized wnd (%d) slow_start -> 0\n" + , this, m_adv_wnd); + } } void utp_stream::bind(endpoint_type const& ep, error_code& ec) { } @@ -3390,6 +3425,13 @@ void utp_socket_impl::tick(ptime now) // timed out m_loss_seq_nr = m_seq_nr; + // when we time out, the cwnd is reset to 1 MSS, which means we + // need to ramp it up quickly again. enter slow start mode. This time + // we're very likely to have an ssthres set, which will make us leave + // slow start before inducing more delay or loss. + m_slow_start = true; + UTP_LOGV("%8p: timeout slow_start -> 1\n", this); + // we need to go one past m_seq_nr to cover the case // where we just sent a SYN packet and then adjusted for // the uTorrent sequence number reuse diff --git a/tools/parse_utp_log.py b/tools/parse_utp_log.py index 690e66077..aaeaa222e 100644 --- a/tools/parse_utp_log.py +++ b/tools/parse_utp_log.py @@ -71,6 +71,7 @@ metrics = { 'their_delay':['their delay (ms)', 'x1y2', delay_samples], 'get_microseconds':['clock (us)', 'x1y1', 'steps'], 'wnduser':['advertised window size (B)', 'x1y1', 'steps'], + 'ssthres':['slow-start threshold (B)', 'x1y1', 'steps'], 'delay_base':['delay base (us)', 'x1y1', delay_base], 'their_delay_base':['their delay base (us)', 'x1y1', delay_base], @@ -204,7 +205,7 @@ plot = [ 'y2': 'Time (ms)' }, { - 'data': ['max_window', 'cur_window', 'our_delay', 'target_delay'], + 'data': ['max_window', 'cur_window', 'our_delay', 'target_delay', 'ssthres'], 'title': 'cwnd', 'y1': 'Bytes', 'y2': 'Time (ms)'