Documentation ¶
Index ¶
- Constants
- func BandwidthFromBytesAndTimeDelta(bytes int64, duration time.Duration) int64
- func MaxFilter[T mathext.Number](lhs, rhs T) int
- func MinFilter[T mathext.Number](lhs, rhs T) int
- type AckedPacketInfo
- type BBRSender
- func (b *BBRSender) BandwidthEstimate() int64
- func (b *BBRSender) CanSend(bytesInFlight, bytes int64) bool
- func (b *BBRSender) OnApplicationLimited(bytesInFlight int64)
- func (b *BBRSender) OnCongestionEvent(priorInFlight int64, eventTime time.Time, ackedPackets []AckedPacketInfo, ...)
- func (b *BBRSender) OnPacketSent(sentTime time.Time, bytesInFlight int64, packetNumber int64, bytes int64, ...)
- type BandwidthSample
- type BandwidthSampler
- func (bs *BandwidthSampler) EndOfAppLimitedPhase() int64
- func (bs *BandwidthSampler) IsAppLimited() bool
- func (bs *BandwidthSampler) OnAppLimited()
- func (bs *BandwidthSampler) OnPacketAcknowledged(ackTime time.Time, packetNumber int64) BandwidthSample
- func (bs *BandwidthSampler) OnPacketLost(packetNumber int64)
- func (bs *BandwidthSampler) OnPacketSent(sentTime time.Time, packetNumber int64, bytes int64, bytesInFlight int64, ...)
- func (bs *BandwidthSampler) RemoveObsoletePackets(leastUnacked int64)
- func (bs *BandwidthSampler) TotalBytesAcked() int64
- type BandwidthSamplerInterface
- type ConnectionStateOnSentPacket
- type CubicSendAlgorithm
- type EntryWrapper
- type LostPacketInfo
- type Pacer
- type PacketNumberIndexedQueue
- func (p *PacketNumberIndexedQueue[T]) Emplace(packetNumber int64, args T) bool
- func (p *PacketNumberIndexedQueue[T]) FirstPacket() int64
- func (p *PacketNumberIndexedQueue[T]) GetEntry(packetNumber int64) *T
- func (p *PacketNumberIndexedQueue[T]) IsEmpty() bool
- func (p *PacketNumberIndexedQueue[T]) LastPacket() int64
- func (p *PacketNumberIndexedQueue[T]) Remove(packetNumber int64) bool
- type RTTStats
- func (r *RTTStats) ExpireSmoothedMetrics()
- func (r *RTTStats) LatestRTT() time.Duration
- func (r *RTTStats) MaxAckDelay() time.Duration
- func (r *RTTStats) MeanDeviation() time.Duration
- func (r *RTTStats) MinRTT() time.Duration
- func (r *RTTStats) RTO() time.Duration
- func (r *RTTStats) Reset()
- func (r *RTTStats) SetInitialRTT(t time.Duration)
- func (r *RTTStats) SetMaxAckDelay(mad time.Duration)
- func (r *RTTStats) SetRTOMultiplier(n float64)
- func (r *RTTStats) SmoothedRTT() time.Duration
- func (r *RTTStats) UpdateRTT(sample time.Duration)
- type Sample
- type WindowedFilter
- func (wf *WindowedFilter[T]) GetBest() T
- func (wf *WindowedFilter[T]) GetSecondBest() T
- func (wf *WindowedFilter[T]) GetThirdBest() T
- func (wf *WindowedFilter[T]) Reset(newSample T, newTime int64)
- func (wf *WindowedFilter[V]) SetWindowLength(windowLength int64)
- func (wf *WindowedFilter[V]) Update(newSample V, newTime int64)
Constants ¶
const ( // The gain used in STARTUP after loss has been detected. // 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth // in measured bandwidth. StartupAfterLossGain = 1.5 )
Variables ¶
This section is empty.
Functions ¶
Types ¶
type AckedPacketInfo ¶
func (AckedPacketInfo) String ¶
func (i AckedPacketInfo) String() string
type BBRSender ¶
type BBRSender struct {
// contains filtered or unexported fields
}
func NewBBRSender ¶
NewBBRSender constructs a new BBR sender object.
func (*BBRSender) BandwidthEstimate ¶
BandwidthEstimate returns the estimate of maximum bandwidth.
func (*BBRSender) CanSend ¶
CanSend returns true if a packet can be sent based on the congestion window.
func (*BBRSender) OnApplicationLimited ¶
OnApplicationLimited updates BBR sender state when there is no application data to send.
func (*BBRSender) OnCongestionEvent ¶
func (b *BBRSender) OnCongestionEvent(priorInFlight int64, eventTime time.Time, ackedPackets []AckedPacketInfo, lostPackets []LostPacketInfo)
OnCongestionEvent updates BBR sender state from acknowledged and lost packets.
type BandwidthSample ¶
type BandwidthSample struct {
// contains filtered or unexported fields
}
BandwidthSample contains a single data point of network bandwidth.
func (BandwidthSample) String ¶
func (bs BandwidthSample) String() string
type BandwidthSampler ¶
type BandwidthSampler struct {
// contains filtered or unexported fields
}
BandwidthSampler keeps track of sent and acknowledged packets and outputs a bandwidth sample for every packet acknowledged. The samples are taken for individual packets, and are not filtered; the consumer has to filter the bandwidth samples itself. In certain cases, the sampler will locally severely underestimate the bandwidth, hence a maximum filter with a size of at least one RTT is recommended.
This class bases its samples on the slope of two curves: the number of bytes sent over time, and the number of bytes acknowledged as received over time. It produces a sample of both slopes for every packet that gets acknowledged, based on a slope between two points on each of the corresponding curves. Note that due to the packet loss, the number of bytes on each curve might get further and further away from each other, meaning that it is not feasible to compare byte values coming from different curves with each other.
The obvious points for measuring slope sample are the ones corresponding to the packet that was just acknowledged. Let us denote them as S_1 (point at which the current packet was sent) and A_1 (point at which the current packet was acknowledged). However, taking a slope requires two points on each line, so estimating bandwidth requires picking a packet in the past with respect to which the slope is measured.
For that purpose, BandwidthSampler always keeps track of the most recently acknowledged packet, and records it together with every outgoing packet. When a packet gets acknowledged (A_1), it has not only information about when it itself was sent (S_1), but also the information about the latest acknowledged packet right before it was sent (S_0 and A_0).
Based on that data, send and ack rate are estimated as:
send_rate = (bytes(S_1) - bytes(S_0)) / (time(S_1) - time(S_0)) ack_rate = (bytes(A_1) - bytes(A_0)) / (time(A_1) - time(A_0))
Here, the ack rate is intuitively the rate we want to treat as bandwidth. However, in certain cases (e.g. ack compression) the ack rate at a point may end up higher than the rate at which the data was originally sent, which is not indicative of the real bandwidth. Hence, we use the send rate as an upper bound, and the sample value is
rate_sample = min(send_rate, ack_rate)
An important edge case handled by the sampler is tracking the app-limited samples. There are multiple meaning of "app-limited" used interchangeably, hence it is important to understand and to be able to distinguish between them.
Meaning 1: connection state. The connection is said to be app-limited when there is no outstanding data to send. This means that certain bandwidth samples in the future would not be an accurate indication of the link capacity, and it is important to inform consumer about that. Whenever connection becomes app-limited, the sampler is notified via OnAppLimited() method.
Meaning 2: a phase in the bandwidth sampler. As soon as the bandwidth sampler becomes notified about the connection being app-limited, it enters app-limited phase. In that phase, all *sent* packets are marked as app-limited. Note that the connection itself does not have to be app-limited during the app-limited phase, and in fact it will not be (otherwise how would it send packets?). The boolean flag below indicates whether the sampler is in that phase.
Meaning 3: a flag on the sent packet and on the sample. If a sent packet is sent during the app-limited phase, the resulting sample related to the packet will be marked as app-limited.
With the terminology issue out of the way, let us consider the question of what kind of situation it addresses.
Consider a scenario where we first send packets 1 to 20 at a regular bandwidth, and then immediately run out of data. After a few seconds, we send packets 21 to 60, and only receive ack for 21 between sending packets 40 and 41. In this case, when we sample bandwidth for packets 21 to 40, the S_0/A_0 we use to compute the slope is going to be packet 20, a few seconds apart from the current packet, hence the resulting estimate would be extremely low and not indicative of anything. Only at packet 41 the S_0/A_0 will become 21, meaning that the bandwidth sample would exclude the quiescence.
Based on the analysis of that scenario, we implement the following rule: once OnAppLimited() is called, all sent packets will produce app-limited samples up until an ack for a packet that was sent after OnAppLimited() was called. Note that while the scenario above is not the only scenario when the connection is app-limited, the approach works in other cases too.
func (*BandwidthSampler) EndOfAppLimitedPhase ¶
func (bs *BandwidthSampler) EndOfAppLimitedPhase() int64
func (*BandwidthSampler) IsAppLimited ¶
func (bs *BandwidthSampler) IsAppLimited() bool
func (*BandwidthSampler) OnAppLimited ¶
func (bs *BandwidthSampler) OnAppLimited()
func (*BandwidthSampler) OnPacketAcknowledged ¶
func (bs *BandwidthSampler) OnPacketAcknowledged(ackTime time.Time, packetNumber int64) BandwidthSample
func (*BandwidthSampler) OnPacketLost ¶
func (bs *BandwidthSampler) OnPacketLost(packetNumber int64)
func (*BandwidthSampler) OnPacketSent ¶
func (*BandwidthSampler) RemoveObsoletePackets ¶
func (bs *BandwidthSampler) RemoveObsoletePackets(leastUnacked int64)
func (*BandwidthSampler) TotalBytesAcked ¶
func (bs *BandwidthSampler) TotalBytesAcked() int64
type BandwidthSamplerInterface ¶
type BandwidthSamplerInterface interface { // OnPacketSent inputs the sent packet information into the sampler. Assumes that // all packets are sent in order. The information about the packet will not be // released from the sampler until it the packet is either acknowledged or // declared lost. OnPacketSent(sentTime time.Time, packetNumber, bytes, bytesInFlight int64, hasRetransmittableData bool) // OnPacketAcknowledged notifies the sampler that the packetNumber is acknowledged. // Returns a bandwidth sample. If no bandwidth sample is available, // zero bandwidth is returned. OnPacketAcknowledged(ackTime time.Time, packetNumber int64) BandwidthSample // OnPacketLost informs the sampler that a packet is considered lost and // it should no longer keep track of it. OnPacketLost(packetNumber int64) // OnAppLimited informs the sampler that the connection is currently // app-limited, causing the sampler to enter the app-limited phase. // The phase will expire by itself. OnAppLimited() // RemoveObsoletePackets removes all the packets lower than the specified // packet number. RemoveObsoletePackets(leastUnacked int64) // TotalBytesAcked returns the total number of bytes currently acknowledged // by the receiver. TotalBytesAcked() int64 // IsAppLimited returns true if the sampler is in app-limited phase. IsAppLimited() bool // EndOfAppLimitedPhase returns the last packet number in the // app-limited phase. EndOfAppLimitedPhase() int64 }
BandwidthSamplerInterface is an interface common to any class that can provide bandwidth samples from the information per individual acknowledged packet.
func NewBandwidthSampler ¶
func NewBandwidthSampler() BandwidthSamplerInterface
type ConnectionStateOnSentPacket ¶
type ConnectionStateOnSentPacket struct {
// contains filtered or unexported fields
}
ConnectionStateOnSentPacket represents the information about a sent packet and the state of the connection at the moment the packet was sent, specifically the information about the most recently acknowledged packet at that moment.
func NewConnectionStateOnSentPacketFromSampler ¶
func NewConnectionStateOnSentPacketFromSampler(sendTime time.Time, size int64, sampler *BandwidthSampler) ConnectionStateOnSentPacket
NewConnectionStateOnSentPacketFromSampler constructs a new ConnectionStateOnSentPacket object from the current state of the bandwidth sampler.
type CubicSendAlgorithm ¶
type CubicSendAlgorithm struct {
// contains filtered or unexported fields
}
CubicSendAlgorithm implements cubic congestion algorithm.
func NewCubicSendAlgorithm ¶
func NewCubicSendAlgorithm(minWindowSize, maxWindowSize uint32) *CubicSendAlgorithm
NewCubicSendAlgorithm initializes a new CubicSendAlgorithm.
func (*CubicSendAlgorithm) CongestionWindowSize ¶
func (c *CubicSendAlgorithm) CongestionWindowSize() uint32
CongestionWindowSize returns the currect congestion window size.
func (*CubicSendAlgorithm) InSlowStart ¶
func (c *CubicSendAlgorithm) InSlowStart() bool
InSlowStart returns if cubic is in slow start mode.
func (*CubicSendAlgorithm) OnAck ¶
func (c *CubicSendAlgorithm) OnAck() uint32
OnAck updates the congestion window size from the received acknowledge.
func (*CubicSendAlgorithm) OnLoss ¶
func (c *CubicSendAlgorithm) OnLoss() uint32
OnLoss updates the congestion window size from the packet loss.
func (*CubicSendAlgorithm) OnTimeout ¶
func (c *CubicSendAlgorithm) OnTimeout() uint32
OnTimeout updates the congestion window size from the connection timeout.
type EntryWrapper ¶
type EntryWrapper[T any] struct { // contains filtered or unexported fields }
EntryWrapper is an element marked as present or not.
type LostPacketInfo ¶
func (LostPacketInfo) String ¶
func (i LostPacketInfo) String() string
type Pacer ¶
type Pacer struct {
// contains filtered or unexported fields
}
Pacer limits the speed of sending packets. Pacer is not thread safe. The caller should provide synchronization to avoid race condition.
type PacketNumberIndexedQueue ¶
type PacketNumberIndexedQueue[T any] struct { // contains filtered or unexported fields }
PacketNumberIndexedQueue is a queue of mostly continuous numbered entries which supports the following operations: - adding elements to the end of the queue, or at some point past the end - removing elements in any order - retrieving elements If all elements are inserted in order, all of the operations above are amortized O(1) time.
Internally, the data structure is a deque where each element is marked as present or not. The deque starts at the lowest present index. Whenever an element is removed, it's marked as not present, and the front of the deque is cleared of elements that are not present.
The tail of the queue is not cleared due to the assumption of entries being inserted in order, though removing all elements of the queue will return it to its initial state.
Note that this data structure is inherently hazardous, since an addition of just two entries will cause it to consume all of the memory available. Because of that, it is not a general-purpose container and should not be used as one.
func NewPacketNumberIndexedQueue ¶
func NewPacketNumberIndexedQueue[T any]() *PacketNumberIndexedQueue[T]
func (*PacketNumberIndexedQueue[T]) Emplace ¶
func (p *PacketNumberIndexedQueue[T]) Emplace(packetNumber int64, args T) bool
Emplace inserts data associated packetNumber into (or past) the end of the queue, filling up the missing intermediate entries as necessary. Returns true if the element has been inserted successfully, false if it was already in the queue or inserted out of order.
func (*PacketNumberIndexedQueue[T]) FirstPacket ¶
func (p *PacketNumberIndexedQueue[T]) FirstPacket() int64
func (*PacketNumberIndexedQueue[T]) GetEntry ¶
func (p *PacketNumberIndexedQueue[T]) GetEntry(packetNumber int64) *T
GetEntry retrieves the entry associated with the packet number. Returns the pointer to the entry in case of success, or nil if the entry does not exist.
func (*PacketNumberIndexedQueue[T]) IsEmpty ¶
func (p *PacketNumberIndexedQueue[T]) IsEmpty() bool
func (*PacketNumberIndexedQueue[T]) LastPacket ¶
func (p *PacketNumberIndexedQueue[T]) LastPacket() int64
func (*PacketNumberIndexedQueue[T]) Remove ¶
func (p *PacketNumberIndexedQueue[T]) Remove(packetNumber int64) bool
Remove removes data associated with packetNumber and frees the slots in the queue as necessary.
type RTTStats ¶
type RTTStats struct {
// contains filtered or unexported fields
}
RTTStats provides round-trip statistics
func NewRTTStats ¶
func NewRTTStats() *RTTStats
NewRTTStats makes a properly initialized RTTStats object
func (*RTTStats) ExpireSmoothedMetrics ¶
func (r *RTTStats) ExpireSmoothedMetrics()
ExpireSmoothedMetrics causes the smoothed_rtt to be increased to the latest_rtt if the latest_rtt is larger. The mean deviation is increased to the most recent deviation if it's larger.
func (*RTTStats) LatestRTT ¶
LatestRTT returns the most recent rtt measurement. May return Zero if no valid updates have occurred.
func (*RTTStats) MaxAckDelay ¶
MaxAckDelay gets the max_ack_delay advertised by the peer
func (*RTTStats) MeanDeviation ¶
MeanDeviation gets the mean deviation
func (*RTTStats) MinRTT ¶
MinRTT Returns the minRTT for the entire connection. May return Zero if no valid updates have occurred.
func (*RTTStats) Reset ¶
func (r *RTTStats) Reset()
Reset is called when connection migrates and rtt measurement needs to be reset.
func (*RTTStats) SetInitialRTT ¶
SetInitialRTT sets the initial RTT. It is used during the 0-RTT handshake when restoring the RTT stats from the session state.
func (*RTTStats) SetMaxAckDelay ¶
SetMaxAckDelay sets the max_ack_delay
func (*RTTStats) SetRTOMultiplier ¶
SetRTOMultiplier sets the retransmission timeout multiplier.
func (*RTTStats) SmoothedRTT ¶
SmoothedRTT returns the smoothed RTT for the connection. May return Zero if no valid updates have occurred.
type WindowedFilter ¶
WindowedFilter implements a windowed filter algorithm for tracking the minimum (or maximum) estimate of a stream of samples over some fixed time interval.
func NewWindowedFilter ¶
func NewWindowedFilter[V mathext.Number](windowLength int64, zeroValue V, compare func(V, V) int) *WindowedFilter[V]
NewWindowedFilter initializes a new WindowedFilter.
func (*WindowedFilter[T]) GetBest ¶
func (wf *WindowedFilter[T]) GetBest() T
GetBest returns the best estimate.
func (*WindowedFilter[T]) GetSecondBest ¶
func (wf *WindowedFilter[T]) GetSecondBest() T
GetSecondBest returns the second best estimate.
func (*WindowedFilter[T]) GetThirdBest ¶
func (wf *WindowedFilter[T]) GetThirdBest() T
GetThirdBest returns the third best estimate.
func (*WindowedFilter[T]) Reset ¶
func (wf *WindowedFilter[T]) Reset(newSample T, newTime int64)
Reset resets all estimates to new sample.
func (*WindowedFilter[V]) SetWindowLength ¶
func (wf *WindowedFilter[V]) SetWindowLength(windowLength int64)
SetWindowLength changes the window length. Does not update any current samples.
func (*WindowedFilter[V]) Update ¶
func (wf *WindowedFilter[V]) Update(newSample V, newTime int64)
Update updates best estimates with newSample, and expires and updates best estimates as necessary.