| Index: content/renderer/p2p/ipc_socket_factory.cc
|
| diff --git a/content/renderer/p2p/ipc_socket_factory.cc b/content/renderer/p2p/ipc_socket_factory.cc
|
| index d1f56863645ac771186fdde0160eb82eb218d5a7..01c6874657795bf0482cba9b3963ff9489b587dd 100644
|
| --- a/content/renderer/p2p/ipc_socket_factory.cc
|
| +++ b/content/renderer/p2p/ipc_socket_factory.cc
|
| @@ -4,6 +4,8 @@
|
|
|
| #include "content/renderer/p2p/ipc_socket_factory.h"
|
|
|
| +#include <deque>
|
| +
|
| #include "base/compiler_specific.h"
|
| #include "base/debug/trace_event.h"
|
| #include "base/message_loop.h"
|
| @@ -17,9 +19,8 @@ namespace content {
|
|
|
| namespace {
|
|
|
| -// TODO(hclam): This shouldn't be a pre-defined value. Bug: crbug.com/181321.
|
| -const int kMaxPendingPackets = 32;
|
| -const int kWritableSignalThreshold = 0;
|
| +// TODO(miu): This needs tuning. http://crbug.com/237960
|
| +const size_t kMaximumInFlightBytes = 64 * 1024; // 64 KB
|
|
|
| // IpcPacketSocket implements talk_base::AsyncPacketSocket interface
|
| // using P2PSocketClient that works over IPC-channel. It must be used
|
| @@ -66,6 +67,11 @@ class IpcPacketSocket : public talk_base::AsyncPacketSocket,
|
| IS_ERROR,
|
| };
|
|
|
| + // Update trace of send throttling internal state. This should be called
|
| + // immediately after any changes to |send_bytes_available_| and/or
|
| + // |in_flight_packet_sizes_|.
|
| + void TraceSendThrottlingState() const;
|
| +
|
| void InitAcceptedTcp(P2PSocketClient* client,
|
| const talk_base::SocketAddress& local_address,
|
| const talk_base::SocketAddress& remote_address);
|
| @@ -89,9 +95,14 @@ class IpcPacketSocket : public talk_base::AsyncPacketSocket,
|
| // Current state of the object.
|
| InternalState state_;
|
|
|
| - // Number which have been sent to the browser, but for which we haven't
|
| - // received response.
|
| - int send_packets_pending_;
|
| + // Track the number of bytes allowed to be sent non-blocking. This is used to
|
| + // throttle the sending of packets to the browser process. For each packet
|
| + // sent, the value is decreased. As callbacks to OnSendComplete() (as IPCs
|
| + // from the browser process) are made, the value is increased back. This
|
| + // allows short bursts of high-rate sending without dropping packets, but
|
| + // quickly restricts the client to a sustainable steady-state rate.
|
| + size_t send_bytes_available_;
|
| + std::deque<size_t> in_flight_packet_sizes_;
|
|
|
| // Set to true once EWOULDBLOCK was returned from Send(). Indicates that the
|
| // caller expects SignalWritable notification.
|
| @@ -107,9 +118,11 @@ IpcPacketSocket::IpcPacketSocket()
|
| : type_(P2P_SOCKET_UDP),
|
| message_loop_(base::MessageLoop::current()),
|
| state_(IS_UNINITIALIZED),
|
| - send_packets_pending_(0),
|
| + send_bytes_available_(kMaximumInFlightBytes),
|
| writable_signal_expected_(false),
|
| - error_(0) {}
|
| + error_(0) {
|
| + COMPILE_ASSERT(kMaximumInFlightBytes > 0, would_send_at_zero_rate);
|
| +}
|
|
|
| IpcPacketSocket::~IpcPacketSocket() {
|
| if (state_ == IS_OPENING || state_ == IS_OPEN ||
|
| @@ -118,6 +131,12 @@ IpcPacketSocket::~IpcPacketSocket() {
|
| }
|
| }
|
|
|
| +void IpcPacketSocket::TraceSendThrottlingState() const {
|
| + TRACE_COUNTER1("p2p", "P2PSendBytesAvailable", send_bytes_available_);
|
| + TRACE_COUNTER1("p2p", "P2PSendPacketsInFlight",
|
| + in_flight_packet_sizes_.size());
|
| +}
|
| +
|
| bool IpcPacketSocket::Init(P2PSocketType type, P2PSocketClient* client,
|
| const talk_base::SocketAddress& local_address,
|
| const talk_base::SocketAddress& remote_address) {
|
| @@ -157,6 +176,7 @@ void IpcPacketSocket::InitAcceptedTcp(
|
| local_address_ = local_address;
|
| remote_address_ = remote_address;
|
| state_ = IS_OPEN;
|
| + TraceSendThrottlingState();
|
| client_->set_delegate(this);
|
| }
|
|
|
| @@ -195,24 +215,31 @@ int IpcPacketSocket::SendTo(const void *data, size_t data_size,
|
| break;
|
| }
|
|
|
| - if (send_packets_pending_ > kMaxPendingPackets) {
|
| - TRACE_EVENT_INSTANT1("p2p", "MaxPendingPacketsWouldBlock",
|
| + if (data_size == 0) {
|
| + NOTREACHED();
|
| + return 0;
|
| + }
|
| +
|
| + if (data_size > send_bytes_available_) {
|
| + TRACE_EVENT_INSTANT1("p2p", "MaxPendingBytesWouldBlock",
|
| TRACE_EVENT_SCOPE_THREAD, "id", client_->socket_id());
|
| writable_signal_expected_ = true;
|
| error_ = EWOULDBLOCK;
|
| return -1;
|
| }
|
|
|
| - const char* data_char = reinterpret_cast<const char*>(data);
|
| - std::vector<char> data_vector(data_char, data_char + data_size);
|
| -
|
| net::IPEndPoint address_chrome;
|
| if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) {
|
| NOTREACHED();
|
| return -1;
|
| }
|
|
|
| - ++send_packets_pending_;
|
| + send_bytes_available_ -= data_size;
|
| + in_flight_packet_sizes_.push_back(data_size);
|
| + TraceSendThrottlingState();
|
| +
|
| + const char* data_char = reinterpret_cast<const char*>(data);
|
| + std::vector<char> data_vector(data_char, data_char + data_size);
|
| client_->Send(address_chrome, data_vector);
|
|
|
| // Fake successful send. The caller ignores result anyway.
|
| @@ -286,6 +313,7 @@ void IpcPacketSocket::OnOpen(const net::IPEndPoint& address) {
|
| }
|
|
|
| state_ = IS_OPEN;
|
| + TraceSendThrottlingState();
|
|
|
| SignalAddressReady(this, local_address_);
|
| if (type_ == P2P_SOCKET_TCP_CLIENT)
|
| @@ -311,11 +339,13 @@ void IpcPacketSocket::OnIncomingTcpConnection(
|
| void IpcPacketSocket::OnSendComplete() {
|
| DCHECK_EQ(base::MessageLoop::current(), message_loop_);
|
|
|
| - --send_packets_pending_;
|
| - DCHECK_GE(send_packets_pending_, 0);
|
| + CHECK(!in_flight_packet_sizes_.empty());
|
| + send_bytes_available_ += in_flight_packet_sizes_.front();
|
| + DCHECK_LE(send_bytes_available_, kMaximumInFlightBytes);
|
| + in_flight_packet_sizes_.pop_front();
|
| + TraceSendThrottlingState();
|
|
|
| - if (writable_signal_expected_ &&
|
| - send_packets_pending_ <= kWritableSignalThreshold) {
|
| + if (writable_signal_expected_ && send_bytes_available_ > 0) {
|
| SignalReadyToSend(this);
|
| writable_signal_expected_ = false;
|
| }
|
|
|