mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-07 08:07:42 +00:00
wgengine/bench: improved rate selection.
The old decay-based one took a while to converge. This new one (based very loosely on TCP BBR) seems to converge quickly on what seems to be the best speed. Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This commit is contained in:
parent
a92b9647c5
commit
a7fe1d7c46
@ -90,7 +90,7 @@ func main() {
|
|||||||
traf.Start(Addr1.IP, Addr2.IP, PayloadSize+ICMPMinSize, 0)
|
traf.Start(Addr1.IP, Addr2.IP, PayloadSize+ICMPMinSize, 0)
|
||||||
|
|
||||||
var cur, prev Snapshot
|
var cur, prev Snapshot
|
||||||
var pps float64
|
var pps int64
|
||||||
i := 0
|
i := 0
|
||||||
for {
|
for {
|
||||||
i += 1
|
i += 1
|
||||||
@ -104,7 +104,7 @@ func main() {
|
|||||||
if prev.WhenNsec == 0 {
|
if prev.WhenNsec == 0 {
|
||||||
logf("tx=%-6d rx=%-6d", d.TxPackets, d.RxPackets)
|
logf("tx=%-6d rx=%-6d", d.TxPackets, d.RxPackets)
|
||||||
} else {
|
} else {
|
||||||
logf("%v @%7.0f pkt/sec", d, pps)
|
logf("%v @%7d pkt/s", d, pps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ func runOnce(b *testing.B, setup SetupFunc, payload int) {
|
|||||||
traf.Start(Addr1.IP, Addr2.IP, payload, int64(b.N))
|
traf.Start(Addr1.IP, Addr2.IP, payload, int64(b.N))
|
||||||
|
|
||||||
var cur, prev Snapshot
|
var cur, prev Snapshot
|
||||||
var pps float64
|
var pps int64
|
||||||
i := 0
|
i := 0
|
||||||
for traf.Running() {
|
for traf.Running() {
|
||||||
i += 1
|
i += 1
|
||||||
@ -93,7 +93,7 @@ func runOnce(b *testing.B, setup SetupFunc, payload int) {
|
|||||||
d := cur.Sub(prev)
|
d := cur.Sub(prev)
|
||||||
|
|
||||||
if prev.WhenNsec != 0 {
|
if prev.WhenNsec != 0 {
|
||||||
logf("%v @%7.0f pkt/sec", d, pps)
|
logf("%v @%7d pkt/sec", d, pps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +74,9 @@ type TrafficGen struct {
|
|||||||
// caller wants to go.
|
// caller wants to go.
|
||||||
nsPerPacket int64
|
nsPerPacket int64
|
||||||
|
|
||||||
// bestPPS is the "best observed packets-per-second" in recent
|
// ppsHistory is the observed packets-per-second from recent
|
||||||
// memory.
|
// samples.
|
||||||
bestPPS float64
|
ppsHistory [5]int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTrafficGen creates a new, initially locked, TrafficGen.
|
// NewTrafficGen creates a new, initially locked, TrafficGen.
|
||||||
@ -221,28 +221,42 @@ func (t *TrafficGen) GotPacket(b []byte, ofs int) {
|
|||||||
// 1% to receive them, leading to a misleading throughput calculation.
|
// 1% to receive them, leading to a misleading throughput calculation.
|
||||||
//
|
//
|
||||||
// Call this function multiple times per second.
|
// Call this function multiple times per second.
|
||||||
func (t *TrafficGen) Adjust() (pps float64) {
|
func (t *TrafficGen) Adjust() (pps int64) {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
|
d := t.cur.Sub(t.prev)
|
||||||
|
|
||||||
// don't adjust rate until the first full period *after* receiving
|
// don't adjust rate until the first full period *after* receiving
|
||||||
// the first packet. This skips any handshake time in the underlying
|
// the first packet. This skips any handshake time in the underlying
|
||||||
// transport.
|
// transport.
|
||||||
if t.prev.LastSeqRx == 0 {
|
if t.prev.LastSeqRx == 0 || d.DurationNsec == 0 {
|
||||||
t.prev = t.cur
|
t.prev = t.cur
|
||||||
return 0 // no estimate yet, continue at max speed
|
return 0 // no estimate yet, continue at max speed
|
||||||
}
|
}
|
||||||
|
|
||||||
d := t.cur.Sub(t.prev)
|
pps = int64(d.RxPackets) * 1e9 / int64(d.DurationNsec)
|
||||||
t.bestPPS *= 0.97
|
|
||||||
pps = float64(d.RxPackets) * 1e9 / float64(d.DurationNsec)
|
// We use a rate selection algorithm based loosely on TCP BBR.
|
||||||
if pps > 0 && t.prev.WhenNsec > 0 {
|
// Basically, we set the transmit rate to be a bit higher than
|
||||||
if pps > t.bestPPS {
|
// the best observed transmit rate in the last several time
|
||||||
t.bestPPS = pps
|
// periods. This guarantees some packet loss, but should converge
|
||||||
|
// quickly on a rate near the sustainable maximum.
|
||||||
|
bestPPS := pps
|
||||||
|
for _, p := range t.ppsHistory {
|
||||||
|
if p > bestPPS {
|
||||||
|
bestPPS = p
|
||||||
}
|
}
|
||||||
t.nsPerPacket = int64(1e9 / t.bestPPS)
|
}
|
||||||
|
if pps > 0 && t.prev.WhenNsec > 0 {
|
||||||
|
copy(t.ppsHistory[1:], t.ppsHistory[0:len(t.ppsHistory)-1])
|
||||||
|
t.ppsHistory[0] = pps
|
||||||
|
}
|
||||||
|
if bestPPS > 0 {
|
||||||
|
pps = bestPPS * 103 / 100
|
||||||
|
t.nsPerPacket = int64(1e9 / pps)
|
||||||
}
|
}
|
||||||
t.prev = t.cur
|
t.prev = t.cur
|
||||||
|
|
||||||
return t.bestPPS
|
return pps
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user