Index: net/quic/congestion_control/send_algorithm_simulator.cc |
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc |
index 3b8ca70a8ad7d8bb93b42f7756e8daa7d766a8e2..0798d5774ca7ed0ff32c2e0201dbdfb333c85d14 100644 |
--- a/net/quic/congestion_control/send_algorithm_simulator.cc |
+++ b/net/quic/congestion_control/send_algorithm_simulator.cc |
@@ -13,6 +13,7 @@ |
using std::list; |
using std::max; |
using std::min; |
+using std::vector; |
namespace net { |
@@ -22,30 +23,31 @@ const QuicByteCount kPacketSize = 1200; |
} // namespace |
+SendAlgorithmSimulator::Sender::Sender(SendAlgorithmInterface* send_algorithm, |
+ RttStats* rtt_stats) |
+ : send_algorithm(send_algorithm), |
+ rtt_stats(rtt_stats), |
+ last_sent(0), |
+ last_acked(0), |
+ next_acked(1), |
+ max_cwnd(0), |
+ min_cwnd(100000), |
+ max_cwnd_drop(0), |
+ last_cwnd(0), |
+ last_transfer_bandwidth(QuicBandwidth::Zero()) {} |
+ |
SendAlgorithmSimulator::SendAlgorithmSimulator( |
- SendAlgorithmInterface* send_algorithm, |
MockClock* clock, |
- RttStats* rtt_stats, |
QuicBandwidth bandwidth, |
QuicTime::Delta rtt) |
- : send_algorithm_(send_algorithm), |
- clock_(clock), |
- rtt_stats_(rtt_stats), |
- next_sent_(1), |
- last_acked_(0), |
- next_acked_(1), |
+ : clock_(clock), |
lose_next_ack_(false), |
- bytes_in_flight_(0), |
forward_loss_rate_(0), |
reverse_loss_rate_(0), |
loss_correlation_(0), |
bandwidth_(bandwidth), |
rtt_(rtt), |
- buffer_size_(1000000), |
- max_cwnd_(0), |
- min_cwnd_(100000), |
- max_cwnd_drop_(0), |
- last_cwnd_(0) { |
+ buffer_size_(1000000) { |
uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max()); |
DVLOG(1) << "Seeding SendAlgorithmSimulator with " << seed; |
simple_random_.set_seed(seed); |
@@ -53,102 +55,126 @@ SendAlgorithmSimulator::SendAlgorithmSimulator( |
SendAlgorithmSimulator::~SendAlgorithmSimulator() {} |
-// Sends the specified number of bytes as quickly as possible and returns the |
-// average bandwidth in bytes per second. The time elapsed is based on |
-// waiting for all acks to arrive. |
-QuicBandwidth SendAlgorithmSimulator::SendBytes(size_t num_bytes) { |
- const QuicTime start_time = clock_->Now(); |
- size_t bytes_acked = 0; |
- while (bytes_acked < num_bytes) { |
- DVLOG(1) << "bytes_acked:" << bytes_acked << " bytes_in_flight_:" |
- << bytes_in_flight_ << " CWND(bytes):" |
- << send_algorithm_->GetCongestionWindow(); |
+void SendAlgorithmSimulator::AddTransfer(Sender* sender, size_t num_bytes) { |
+ AddTransfer(sender, num_bytes, clock_->Now()); |
+} |
+ |
+void SendAlgorithmSimulator::AddTransfer( |
+ Sender* sender, size_t num_bytes, QuicTime start_time) { |
+ pending_transfers_.push_back(Transfer(sender, num_bytes, start_time)); |
+ // Record initial stats from when the transfer begins. |
+ pending_transfers_.back().sender->RecordStats(); |
+} |
+ |
+void SendAlgorithmSimulator::TransferBytes() { |
+ TransferBytes(kuint64max, QuicTime::Delta::Infinite()); |
+} |
+ |
+void SendAlgorithmSimulator::TransferBytes(QuicByteCount max_bytes, |
+ QuicTime::Delta max_time) { |
+ const QuicTime end_time = clock_->Now().Add(max_time); |
+ QuicByteCount bytes_sent = 0; |
+ while (!pending_transfers_.empty() && |
+ clock_->Now() < end_time && |
+ bytes_sent < max_bytes) { |
// Determine the times of next send and of the next ack arrival. |
- QuicTime::Delta send_delta = send_algorithm_->TimeUntilSend( |
- clock_->Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA); |
- // If we've already sent enough bytes, wait for them to be acked. |
- if (bytes_acked + bytes_in_flight_ >= num_bytes) { |
- send_delta = QuicTime::Delta::Infinite(); |
- } |
- QuicTime::Delta ack_delta = NextAckDelta(); |
+ PacketEvent send_event = NextSendEvent(); |
+ PacketEvent ack_event = NextAckEvent(); |
// If both times are infinite, fire a TLP. |
- if (ack_delta.IsInfinite() && send_delta.IsInfinite()) { |
+ if (ack_event.time_delta.IsInfinite() && |
+ send_event.time_delta.IsInfinite()) { |
DVLOG(1) << "Both times are infinite, simulating a TLP."; |
- // TODO(ianswett): Use a more sophisticated TLP timer. |
+ // TODO(ianswett): Use a more sophisticated TLP timer or never lose |
+ // the last ack? |
clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); |
- SendDataNow(); |
- } else if (ack_delta < send_delta) { |
+ SendDataNow(&pending_transfers_.front()); |
+ } else if (ack_event.time_delta < send_event.time_delta) { |
DVLOG(1) << "Handling ack, advancing time:" |
- << ack_delta.ToMicroseconds() << "us"; |
+ << ack_event.time_delta.ToMicroseconds() << "us"; |
// Ack data all the data up to ack time and lose any missing sequence |
// numbers. |
- clock_->AdvanceTime(ack_delta); |
- bytes_acked += HandlePendingAck(); |
+ clock_->AdvanceTime(ack_event.time_delta); |
+ HandlePendingAck(ack_event.transfer); |
} else { |
DVLOG(1) << "Sending, advancing time:" |
- << send_delta.ToMicroseconds() << "us"; |
- clock_->AdvanceTime(send_delta); |
- SendDataNow(); |
+ << send_event.time_delta.ToMicroseconds() << "us"; |
+ clock_->AdvanceTime(send_event.time_delta); |
+ SendDataNow(send_event.transfer); |
+ bytes_sent += kPacketSize; |
+ } |
+ } |
+} |
+ |
+SendAlgorithmSimulator::PacketEvent SendAlgorithmSimulator::NextSendEvent() { |
+ QuicTime::Delta send_time = QuicTime::Delta::Infinite(); |
+ Transfer* transfer = NULL; |
+ for (vector<Transfer>::iterator it = pending_transfers_.begin(); |
+ it != pending_transfers_.end(); ++it) { |
+ // If the flow hasn't started, return the start time. |
+ if (clock_->Now() < it->start_time) { |
+ send_time = it->start_time.Subtract(clock_->Now()); |
+ transfer = &(*it); |
+ continue; |
+ } |
+ // If we've already sent enough bytes, wait for them to be acked. |
+ if (it->bytes_acked + it->bytes_in_flight >= it->num_bytes) { |
+ continue; |
+ } |
+ QuicTime::Delta transfer_send_time = |
+ it->sender->send_algorithm->TimeUntilSend( |
+ clock_->Now(), it->bytes_in_flight, HAS_RETRANSMITTABLE_DATA); |
+ if (transfer_send_time < send_time) { |
+ send_time = transfer_send_time; |
+ transfer = &(*it); |
} |
- RecordStats(); |
} |
- return QuicBandwidth::FromBytesAndTimeDelta( |
- num_bytes, clock_->Now().Subtract(start_time)); |
+ DVLOG(1) << "NextSendTime returning delta(ms):" << send_time.ToMilliseconds(); |
+ return PacketEvent(send_time, transfer); |
} |
// NextAck takes into account packet loss in both forward and reverse |
// direction, as well as correlated losses. And it assumes the receiver acks |
// every other packet when there is no loss. |
-QuicTime::Delta SendAlgorithmSimulator::NextAckDelta() { |
- if (sent_packets_.empty() || AllPacketsLost()) { |
- DVLOG(1) << "No outstanding packets to cause acks. sent_packets_.size():" |
- << sent_packets_.size(); |
- return QuicTime::Delta::Infinite(); |
+SendAlgorithmSimulator::PacketEvent SendAlgorithmSimulator::NextAckEvent() { |
+ if (sent_packets_.empty()) { |
+ DVLOG(1) << "No outstanding packets to ack for any transfer."; |
+ return PacketEvent(QuicTime::Delta::Infinite(), NULL); |
} |
- // If necessary, determine next_acked_. |
- // This is only done once to ensure multiple calls return the same time. |
- FindNextAcked(); |
- |
- // If only one packet is acked, simulate a delayed ack. |
- if (next_acked_ - last_acked_ == 1) { |
- return sent_packets_.front().ack_time.Add( |
- QuicTime::Delta::FromMilliseconds(100)).Subtract(clock_->Now()); |
- } |
- for (list<SentPacket>::const_iterator it = sent_packets_.begin(); |
- it != sent_packets_.end(); ++it) { |
- if (next_acked_ == it->sequence_number) { |
- return it->ack_time.Subtract(clock_->Now()); |
+ // For each connection, find the next acked packet. |
+ QuicTime::Delta ack_time = QuicTime::Delta::Infinite(); |
+ Transfer* transfer = NULL; |
+ for (vector<Transfer>::iterator it = pending_transfers_.begin(); |
+ it != pending_transfers_.end(); ++it) { |
+ // If necessary, determine next_acked_. |
+ // This is only done once to ensure multiple calls return the same time. |
+ QuicTime::Delta transfer_ack_time = FindNextAcked(&(*it)); |
+ if (transfer_ack_time < ack_time) { |
+ ack_time = transfer_ack_time; |
+ transfer = &(*it); |
} |
} |
- LOG(DFATAL) << "Error, next_acked_: " << next_acked_ |
- << " should have been found in sent_packets_"; |
- return QuicTime::Delta::Infinite(); |
-} |
-bool SendAlgorithmSimulator::AllPacketsLost() { |
- for (list<SentPacket>::const_iterator it = sent_packets_.begin(); |
- it != sent_packets_.end(); ++it) { |
- if (it->ack_time.IsInitialized()) { |
- return false; |
- } |
- } |
- return true; |
+ return PacketEvent(ack_time, transfer); |
} |
-void SendAlgorithmSimulator::FindNextAcked() { |
- // TODO(ianswett): Add a simpler mode which acks every packet. |
- bool packets_lost = false; |
- if (next_acked_ == last_acked_) { |
+QuicTime::Delta SendAlgorithmSimulator::FindNextAcked(Transfer* transfer) { |
+ Sender* sender = transfer->sender; |
+ if (sender->next_acked == sender->last_acked) { |
// Determine if the next ack is lost only once, to ensure determinism. |
lose_next_ack_ = |
reverse_loss_rate_ * kuint64max > simple_random_.RandUint64(); |
} |
bool two_acks_remaining = lose_next_ack_; |
- next_acked_ = last_acked_; |
+ sender->next_acked = sender->last_acked; |
+ bool packets_lost = false; |
// Remove any packets that are simulated as lost. |
for (list<SentPacket>::const_iterator it = sent_packets_.begin(); |
- it != sent_packets_.end(); ++it) { |
+ it != sent_packets_.end(); ++it) { |
+ if (transfer != it->transfer) { |
+ continue; |
+ } |
+ |
// Lost packets don't trigger an ack. |
if (it->ack_time == QuicTime::Zero()) { |
packets_lost = true; |
@@ -156,11 +182,11 @@ void SendAlgorithmSimulator::FindNextAcked() { |
} |
// Buffer dropped packets are skipped automatically, but still end up |
// being lost and cause acks to be sent immediately. |
- if (next_acked_ < it->sequence_number - 1) { |
+ if (sender->next_acked < it->sequence_number - 1) { |
packets_lost = true; |
} |
- next_acked_ = it->sequence_number; |
- if (packets_lost || (next_acked_ - last_acked_) % 2 == 0) { |
+ sender->next_acked = it->sequence_number; |
+ if (packets_lost || (sender->next_acked - sender->last_acked) % 2 == 0) { |
if (two_acks_remaining) { |
two_acks_remaining = false; |
} else { |
@@ -168,33 +194,49 @@ void SendAlgorithmSimulator::FindNextAcked() { |
} |
} |
} |
- DVLOG(1) << "FindNextAcked found next_acked_:" << next_acked_ |
- << " last_acked:" << last_acked_; |
+ |
+ QuicTime::Delta ack_time = QuicTime::Delta::Infinite(); |
+ for (list<SentPacket>::const_iterator it = sent_packets_.begin(); |
+ it != sent_packets_.end(); ++it) { |
+ if (transfer == it->transfer && sender->next_acked == it->sequence_number) { |
+ ack_time = it->ack_time.Subtract(clock_->Now()); |
+ } |
+ } |
+ // If only one packet is acked, simulate a delayed ack. |
+ if (!ack_time.IsInfinite() && transfer->bytes_in_flight == kPacketSize) { |
+ ack_time = ack_time.Add(QuicTime::Delta::FromMilliseconds(100)); |
+ } |
+ DVLOG(1) << "FindNextAcked found next_acked_:" |
+ << transfer->sender->next_acked |
+ << " last_acked:" << transfer->sender->last_acked |
+ << " ack_time(ms):" << ack_time.ToMilliseconds(); |
+ return ack_time; |
} |
-int SendAlgorithmSimulator::HandlePendingAck() { |
- DCHECK_LT(last_acked_, next_acked_); |
+void SendAlgorithmSimulator::HandlePendingAck(Transfer* transfer) { |
+ Sender* sender = transfer->sender; |
+ DCHECK_LT(sender->last_acked, sender->next_acked); |
SendAlgorithmInterface::CongestionMap acked_packets; |
SendAlgorithmInterface::CongestionMap lost_packets; |
// Some entries may be missing from the sent_packets_ array, if they were |
// dropped due to buffer overruns. |
SentPacket largest_observed = sent_packets_.front(); |
- while (last_acked_ < next_acked_) { |
- ++last_acked_; |
+ while (sender->last_acked < sender->next_acked) { |
+ ++sender->last_acked; |
TransmissionInfo info = TransmissionInfo(); |
info.bytes_sent = kPacketSize; |
info.in_flight = true; |
// If it's missing from the array, it's a loss. |
- if (sent_packets_.front().sequence_number > last_acked_) { |
- DVLOG(1) << "Lost packet:" << last_acked_ |
+ if (sent_packets_.front().sequence_number > sender->last_acked) { |
+ DVLOG(1) << "Lost packet:" << sender->last_acked |
<< " dropped by buffer overflow."; |
- lost_packets[last_acked_] = info; |
+ lost_packets[sender->last_acked] = info; |
continue; |
} |
if (sent_packets_.front().ack_time.IsInitialized()) { |
- acked_packets[last_acked_] = info; |
+ acked_packets[sender->last_acked] = info; |
} else { |
- lost_packets[last_acked_] = info; |
+ lost_packets[sender->last_acked] = info; |
} |
// Remove all packets from the front to next_acked_. |
largest_observed = sent_packets_.front(); |
@@ -202,25 +244,44 @@ int SendAlgorithmSimulator::HandlePendingAck() { |
} |
DCHECK(largest_observed.ack_time.IsInitialized()); |
- rtt_stats_->UpdateRtt( |
+ sender->rtt_stats->UpdateRtt( |
largest_observed.ack_time.Subtract(largest_observed.send_time), |
QuicTime::Delta::Zero(), |
clock_->Now()); |
- send_algorithm_->OnCongestionEvent( |
- true, bytes_in_flight_, acked_packets, lost_packets); |
+ sender->send_algorithm->OnCongestionEvent( |
+ true, transfer->bytes_in_flight, acked_packets, lost_packets); |
DCHECK_LE(kPacketSize * (acked_packets.size() + lost_packets.size()), |
- bytes_in_flight_); |
- bytes_in_flight_ -= |
+ transfer->bytes_in_flight); |
+ transfer->bytes_in_flight -= |
kPacketSize * (acked_packets.size() + lost_packets.size()); |
- return acked_packets.size() * kPacketSize; |
+ |
+ sender->RecordStats(); |
+ transfer->bytes_acked += acked_packets.size() * kPacketSize; |
+ if (transfer->bytes_acked >= transfer->num_bytes) { |
+ // Remove completed transfers and record transfer bandwidth. |
+ QuicTime::Delta transfer_time = |
+ clock_->Now().Subtract(transfer->start_time); |
+ sender->last_transfer_bandwidth = |
+ QuicBandwidth::FromBytesAndTimeDelta(transfer->num_bytes, |
+ transfer_time); |
+ for (vector<Transfer>::iterator it = pending_transfers_.begin(); |
+ it != pending_transfers_.end(); ++it) { |
+ if (transfer == &(*it)) { |
+ pending_transfers_.erase(it); |
+ break; |
+ } |
+ } |
+ } |
} |
-void SendAlgorithmSimulator::SendDataNow() { |
- DVLOG(1) << "Sending packet:" << next_sent_ << " bytes_in_flight:" |
- << bytes_in_flight_; |
- send_algorithm_->OnPacketSent( |
- clock_->Now(), bytes_in_flight_, |
- next_sent_, kPacketSize, HAS_RETRANSMITTABLE_DATA); |
+void SendAlgorithmSimulator::SendDataNow(Transfer* transfer) { |
+ Sender* sender = transfer->sender; |
+ ++sender->last_sent; |
+ DVLOG(1) << "Sending packet:" << sender->last_sent |
+ << " bytes_in_flight:" << transfer->bytes_in_flight; |
+ sender->send_algorithm->OnPacketSent( |
+ clock_->Now(), transfer->bytes_in_flight, |
+ sender->last_sent, kPacketSize, HAS_RETRANSMITTABLE_DATA); |
// Lose the packet immediately if the buffer is full. |
if (sent_packets_.size() * kPacketSize < buffer_size_) { |
// TODO(ianswett): This buffer simulation is an approximation. |
@@ -233,6 +294,8 @@ void SendAlgorithmSimulator::SendDataNow() { |
loss_correlation_ * kuint64max > simple_random_.RandUint64()) { |
packet_lost = true; |
} |
+ DVLOG(1) << "losing packet:" << sender->last_sent |
+ << " due to random loss."; |
QuicTime ack_time = clock_->Now().Add(rtt_); |
// If the number of bytes in flight are less than the bdp, there's |
@@ -244,20 +307,13 @@ void SendAlgorithmSimulator::SendDataNow() { |
} |
// If the packet is lost, give it an ack time of Zero. |
sent_packets_.push_back(SentPacket( |
- next_sent_, clock_->Now(), packet_lost ? QuicTime::Zero() : ack_time)); |
- } |
- ++next_sent_; |
- bytes_in_flight_ += kPacketSize; |
-} |
- |
-void SendAlgorithmSimulator::RecordStats() { |
- QuicByteCount cwnd = send_algorithm_->GetCongestionWindow(); |
- max_cwnd_ = max(max_cwnd_, cwnd); |
- min_cwnd_ = min(min_cwnd_, cwnd); |
- if (last_cwnd_ > cwnd) { |
- max_cwnd_drop_ = max(max_cwnd_drop_, last_cwnd_ - cwnd); |
+ sender->last_sent, clock_->Now(), |
+ packet_lost ? QuicTime::Zero() : ack_time, transfer)); |
+ } else { |
+ DVLOG(1) << "losing packet:" << sender->last_sent |
+ << " because the buffer was full."; |
} |
- last_cwnd_ = cwnd; |
+ transfer->bytes_in_flight += kPacketSize; |
} |
// Advance the time by |delta| without sending anything. |
@@ -265,9 +321,4 @@ void SendAlgorithmSimulator::AdvanceTime(QuicTime::Delta delta) { |
clock_->AdvanceTime(delta); |
} |
-// Elapsed time from the start of the connection. |
-QuicTime SendAlgorithmSimulator::ElapsedTime() { |
- return clock_->Now(); |
-} |
- |
} // namespace net |