quic/congestion_control/BbrBandwidthSampler.cpp (92 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include <quic/congestion_control/BbrBandwidthSampler.h> #include <quic/logging/QLoggerConstants.h> namespace quic { BbrBandwidthSampler::BbrBandwidthSampler(QuicConnectionStateBase& conn) : conn_(conn), windowedFilter_(bandwidthWindowLength(kNumOfCycles), Bandwidth(), 0) {} Bandwidth BbrBandwidthSampler::getBandwidth() const noexcept { return windowedFilter_.GetBest(); } Bandwidth BbrBandwidthSampler::getLatestSample() const noexcept { return latestSample_; } void BbrBandwidthSampler::setWindowLength( const uint64_t windowLength) noexcept { windowedFilter_.SetWindowLength(windowLength); } void BbrBandwidthSampler::onPacketAcked( const CongestionController::AckEvent& ackEvent, uint64_t rttCounter) { if (appLimited_) { if (appLimitedExitTarget_ < ackEvent.largestNewlyAckedPacketSentTime) { appLimited_ = false; if (conn_.qLogger) { conn_.qLogger->addAppUnlimitedUpdate(); } } } // TODO: If i'm smart enough, maybe we don't have to loop through the acked // packets. Can we calculate the bandwidth based on aggregated stats? bool bandwidthUpdated = false; for (auto const& ackedPacket : ackEvent.ackedPackets) { if (ackedPacket.outstandingPacketMetadata.encodedSize == 0) { continue; } Bandwidth sendRate, ackRate; if (ackedPacket.lastAckedPacketInfo) { DCHECK( ackedPacket.outstandingPacketMetadata.time > ackedPacket.lastAckedPacketInfo->sentTime); DCHECK_GE( ackedPacket.outstandingPacketMetadata.totalBytesSent, ackedPacket.lastAckedPacketInfo->totalBytesSent); sendRate = Bandwidth( ackedPacket.outstandingPacketMetadata.totalBytesSent - ackedPacket.lastAckedPacketInfo->totalBytesSent, std::chrono::duration_cast<std::chrono::microseconds>( ackedPacket.outstandingPacketMetadata.time - ackedPacket.lastAckedPacketInfo->sentTime)); DCHECK(ackEvent.ackTime > ackedPacket.lastAckedPacketInfo->ackTime); DCHECK_GE( conn_.lossState.totalBytesAcked, ackedPacket.lastAckedPacketInfo->totalBytesAcked); auto ackDuration = (ackEvent.adjustedAckTime > ackedPacket.lastAckedPacketInfo->adjustedAckTime) ? (ackEvent.adjustedAckTime - ackedPacket.lastAckedPacketInfo->adjustedAckTime) : (ackEvent.ackTime - ackedPacket.lastAckedPacketInfo->ackTime); ackRate = Bandwidth( conn_.lossState.totalBytesAcked - ackedPacket.lastAckedPacketInfo->totalBytesAcked, std::chrono::duration_cast<std::chrono::microseconds>(ackDuration)); } else if (ackEvent.ackTime > ackedPacket.outstandingPacketMetadata.time) { // No previous ack info from outstanding packet, default to taking the // total acked bytes / ~RTT. // // Note that this if condition: // ack.Event.ackTime > ackedPacket.sentTime // will almost always be true unless your network is very very fast, or // your clock is broken, or isn't steady. Anyway, in the rare cases that // it isn't true, divide by zero will crash. sendRate = Bandwidth( ackEvent.ackedBytes, std::chrono::duration_cast<std::chrono::microseconds>( ackEvent.ackTime - ackedPacket.outstandingPacketMetadata.time)); } Bandwidth measuredBandwidth = sendRate > ackRate ? sendRate : ackRate; // This is a valid sample if the packet was sent while app-limited or // it's higher than the current sample. if (!ackedPacket.isAppLimited || measuredBandwidth > latestSample_) { latestSample_ = measuredBandwidth; } // If a sample is from a packet sent during app-limited period, we should // still use this sample if it's >= current best value. if (measuredBandwidth >= windowedFilter_.GetBest() || !ackedPacket.isAppLimited) { windowedFilter_.Update(measuredBandwidth, rttCounter); bandwidthUpdated = true; } } if (bandwidthUpdated && conn_.qLogger) { auto newBandwidth = getBandwidth(); conn_.qLogger->addBandwidthEstUpdate( newBandwidth.units, newBandwidth.interval); } } void BbrBandwidthSampler::onAppLimited() { appLimited_ = true; appLimitedExitTarget_ = Clock::now(); if (conn_.qLogger) { conn_.qLogger->addAppLimitedUpdate(); } } bool BbrBandwidthSampler::isAppLimited() const noexcept { return appLimited_; } } // namespace quic