github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/core/dst/windowcc.go (about) 1 // Copyright 2014 The DST Authors. All rights reserved. 2 // Use of this source code is governed by an MIT-style 3 // license that can be found in the LICENSE file. 4 5 package dst 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 "time" 12 ) 13 14 type windowCC struct { 15 minWindow int 16 maxWindow int 17 currentWindow int 18 minRate int 19 maxRate int 20 currentRate int 21 targetRate int 22 23 curRTT time.Duration 24 minRTT time.Duration 25 26 statsFile io.WriteCloser 27 start time.Time 28 } 29 30 func newWindowCC() *windowCC { 31 var statsFile io.WriteCloser 32 33 if debugCC { 34 statsFile, _ = os.Create(fmt.Sprintf("cc-log-%d.csv", time.Now().Unix())) 35 fmt.Fprintf(statsFile, "ms,minWin,maxWin,curWin,minRate,maxRate,curRate,minRTT,curRTT\n") 36 } 37 38 return &windowCC{ 39 minWindow: 1, // Packets 40 maxWindow: 16 << 10, 41 currentWindow: 1, 42 43 minRate: 100, // PPS 44 maxRate: 80e3, // Roughly 1 Gbps at 1500 bytes per packet 45 currentRate: 100, 46 targetRate: 1000, 47 48 minRTT: 10 * time.Second, 49 statsFile: statsFile, 50 start: time.Now(), 51 } 52 } 53 54 func (w *windowCC) Ack() { 55 if w.curRTT > w.minRTT+100*time.Millisecond { 56 return 57 } 58 59 changed := false 60 61 if w.currentWindow < w.maxWindow { 62 w.currentWindow++ 63 changed = true 64 } 65 66 if w.currentRate != w.targetRate { 67 w.currentRate = (w.currentRate*7 + w.targetRate) / 8 68 changed = true 69 } 70 71 if changed && debugCC { 72 w.log() 73 log.Println("Ack", w.currentWindow, w.currentRate) 74 } 75 } 76 77 func (w *windowCC) NegAck() { 78 if w.currentWindow > w.minWindow { 79 w.currentWindow /= 2 80 } 81 if w.currentRate > w.minRate { 82 w.currentRate /= 2 83 } 84 if debugCC { 85 w.log() 86 log.Println("NegAck", w.currentWindow, w.currentRate) 87 } 88 } 89 90 func (w *windowCC) Exp() { 91 w.currentWindow = w.minWindow 92 if debugCC { 93 w.log() 94 log.Println("Exp", w.currentWindow, w.currentRate) 95 } 96 } 97 98 func (w *windowCC) SendWindow() int { 99 if w.currentWindow < w.minWindow { 100 return w.minWindow 101 } 102 if w.currentWindow > w.maxWindow { 103 return w.maxWindow 104 } 105 return w.currentWindow 106 } 107 108 func (w *windowCC) PacketRate() int { 109 if w.currentRate < w.minRate { 110 return w.minRate 111 } 112 if w.currentRate > w.maxRate { 113 return w.maxRate 114 } 115 return w.currentRate 116 } 117 118 func (w *windowCC) UpdateRTT(rtt time.Duration) { 119 w.curRTT = rtt 120 if w.curRTT < w.minRTT { 121 w.minRTT = w.curRTT 122 if debugCC { 123 log.Println("Min RTT", w.minRTT) 124 } 125 } 126 127 if w.curRTT > w.minRTT+200*time.Millisecond && w.targetRate > 2*w.minRate { 128 w.targetRate -= w.minRate 129 } else if w.curRTT < w.minRTT+20*time.Millisecond && w.targetRate < w.maxRate { 130 w.targetRate += w.minRate 131 } 132 133 if debugCC { 134 w.log() 135 log.Println("RTT", w.curRTT, "target rate", w.targetRate, "current rate", w.currentRate, "current window", w.currentWindow) 136 } 137 } 138 139 func (w *windowCC) log() { 140 if w.statsFile == nil { 141 return 142 } 143 fmt.Fprintf(w.statsFile, "%.02f,%d,%d,%d,%d,%d,%d,%.02f,%.02f\n", time.Since(w.start).Seconds()*1000, w.minWindow, w.maxWindow, w.currentWindow, w.minRate, w.maxRate, w.currentRate, w.minRTT.Seconds()*1000, w.curRTT.Seconds()*1000) 144 }