github.com/metacubex/mihomo@v1.18.5/transport/hysteria/congestion/pacer.go (about) 1 package congestion 2 3 import ( 4 "github.com/metacubex/quic-go/congestion" 5 "math" 6 "time" 7 ) 8 9 const ( 10 maxBurstPackets = 10 11 minPacingDelay = time.Millisecond 12 ) 13 14 // The pacer implements a token bucket pacing algorithm. 15 type pacer struct { 16 budgetAtLastSent congestion.ByteCount 17 maxDatagramSize congestion.ByteCount 18 lastSentTime time.Time 19 getBandwidth func() congestion.ByteCount // in bytes/s 20 } 21 22 func newPacer(getBandwidth func() congestion.ByteCount) *pacer { 23 p := &pacer{ 24 budgetAtLastSent: maxBurstPackets * initMaxDatagramSize, 25 maxDatagramSize: initMaxDatagramSize, 26 getBandwidth: getBandwidth, 27 } 28 return p 29 } 30 31 func (p *pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { 32 budget := p.Budget(sendTime) 33 if size > budget { 34 p.budgetAtLastSent = 0 35 } else { 36 p.budgetAtLastSent = budget - size 37 } 38 p.lastSentTime = sendTime 39 } 40 41 func (p *pacer) Budget(now time.Time) congestion.ByteCount { 42 if p.lastSentTime.IsZero() { 43 return p.maxBurstSize() 44 } 45 budget := p.budgetAtLastSent + (p.getBandwidth()*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9 46 return minByteCount(p.maxBurstSize(), budget) 47 } 48 49 func (p *pacer) maxBurstSize() congestion.ByteCount { 50 return maxByteCount( 51 congestion.ByteCount((minPacingDelay+time.Millisecond).Nanoseconds())*p.getBandwidth()/1e9, 52 maxBurstPackets*p.maxDatagramSize, 53 ) 54 } 55 56 // TimeUntilSend returns when the next packet should be sent. 57 // It returns the zero value of time.Time if a packet can be sent immediately. 58 func (p *pacer) TimeUntilSend() time.Time { 59 if p.budgetAtLastSent >= p.maxDatagramSize { 60 return time.Time{} 61 } 62 return p.lastSentTime.Add(maxDuration( 63 minPacingDelay, 64 time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/ 65 float64(p.getBandwidth())))*time.Nanosecond, 66 )) 67 } 68 69 func (p *pacer) SetMaxDatagramSize(s congestion.ByteCount) { 70 p.maxDatagramSize = s 71 } 72 73 func maxByteCount(a, b congestion.ByteCount) congestion.ByteCount { 74 if a < b { 75 return b 76 } 77 return a 78 } 79 80 func minByteCount(a, b congestion.ByteCount) congestion.ByteCount { 81 if a < b { 82 return a 83 } 84 return b 85 }