mirror of
https://github.com/microsoft/ethr.git
synced 2024-09-20 06:46:14 +08:00
7f38d662d2
Initial version of -r for TCP bandwidth tests + few other enhancements: - Add timestamp in log messages. - Handle the case where timer tick is delayed on client side. Server side still needs work. - Use high value of GOMAXPROCS to fix starvation of some goroutines. - Support option to disable per connection statistics. If large number of sessions are used, then per connection stats were making it hard to read the results on console. - Synchronize stats timer between client/server. This makes server and client print similar test results. Earlier, under varying TCP throuhgput, results in server and client side were different due to different time periods for calculating throughput.
138 lines
2.9 KiB
Go
138 lines
2.9 KiB
Go
//-----------------------------------------------------------------------------
|
|
// Copyright (C) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license.
|
|
// See LICENSE.txt file in the project root for full license information.
|
|
//-----------------------------------------------------------------------------
|
|
package main
|
|
|
|
import (
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
type ethrNetStat struct {
|
|
netDevStats []ethrNetDevStat
|
|
tcpStats ethrTCPStat
|
|
}
|
|
|
|
type ethrNetDevStat struct {
|
|
interfaceName string
|
|
rxBytes uint64
|
|
txBytes uint64
|
|
rxPkts uint64
|
|
txPkts uint64
|
|
}
|
|
|
|
type ethrTCPStat struct {
|
|
segRetrans uint64
|
|
}
|
|
|
|
func getNetworkStats() ethrNetStat {
|
|
stats := ðrNetStat{}
|
|
|
|
getNetDevStats(stats)
|
|
sort.SliceStable(stats.netDevStats, func(i, j int) bool {
|
|
return stats.netDevStats[i].interfaceName < stats.netDevStats[j].interfaceName
|
|
})
|
|
getTCPStats(stats)
|
|
|
|
return *stats
|
|
}
|
|
|
|
func getNetDevStatDiff(curStats ethrNetDevStat, prevNetStats ethrNetStat, seconds uint64) ethrNetDevStat {
|
|
for _, prevStats := range prevNetStats.netDevStats {
|
|
if prevStats.interfaceName != curStats.interfaceName {
|
|
continue
|
|
}
|
|
|
|
if curStats.rxBytes >= prevStats.rxBytes {
|
|
curStats.rxBytes -= prevStats.rxBytes
|
|
} else {
|
|
curStats.rxBytes += (^uint64(0) - prevStats.rxBytes)
|
|
}
|
|
|
|
if curStats.txBytes >= prevStats.txBytes {
|
|
curStats.txBytes -= prevStats.txBytes
|
|
} else {
|
|
curStats.txBytes += (^uint64(0) - prevStats.txBytes)
|
|
}
|
|
|
|
if curStats.rxPkts >= prevStats.rxPkts {
|
|
curStats.rxPkts -= prevStats.rxPkts
|
|
} else {
|
|
curStats.rxPkts += (^uint64(0) - prevStats.rxPkts)
|
|
}
|
|
|
|
if curStats.txPkts >= prevStats.txPkts {
|
|
curStats.txPkts -= prevStats.txPkts
|
|
} else {
|
|
curStats.txPkts += (^uint64(0) - prevStats.txPkts)
|
|
}
|
|
|
|
break
|
|
}
|
|
curStats.rxBytes /= seconds
|
|
curStats.txBytes /= seconds
|
|
curStats.rxPkts /= seconds
|
|
curStats.txPkts /= seconds
|
|
return curStats
|
|
}
|
|
|
|
var statsEnabled bool
|
|
|
|
func startStatsTimer() {
|
|
if statsEnabled {
|
|
return
|
|
}
|
|
ticker := time.NewTicker(time.Second)
|
|
statsEnabled = true
|
|
go func() {
|
|
for statsEnabled {
|
|
select {
|
|
case <-ticker.C:
|
|
emitStats()
|
|
}
|
|
}
|
|
ticker.Stop()
|
|
return
|
|
}()
|
|
}
|
|
|
|
func stopStatsTimer() {
|
|
statsEnabled = false
|
|
}
|
|
|
|
var lastStatsTime time.Time = time.Now()
|
|
|
|
func timeToNextTick() time.Duration {
|
|
nextTick := lastStatsTime.Add(time.Second)
|
|
return time.Until(nextTick)
|
|
}
|
|
|
|
func emitStats() {
|
|
d := time.Since(lastStatsTime)
|
|
lastStatsTime = time.Now()
|
|
seconds := int64(d.Seconds())
|
|
if seconds < 1 {
|
|
seconds = 1
|
|
}
|
|
ui.emitTestResultBegin()
|
|
emitTestResults(uint64(seconds))
|
|
ui.emitTestResultEnd()
|
|
ui.emitStats(getNetworkStats())
|
|
ui.paint(uint64(seconds))
|
|
}
|
|
|
|
func emitTestResults(s uint64) {
|
|
gSessionLock.RLock()
|
|
defer gSessionLock.RUnlock()
|
|
for _, k := range gSessionKeys {
|
|
v := gSessions[k]
|
|
ui.emitTestResult(v, TCP, s)
|
|
ui.emitTestResult(v, UDP, s)
|
|
ui.emitTestResult(v, HTTP, s)
|
|
ui.emitTestResult(v, HTTPS, s)
|
|
ui.emitTestResult(v, ICMP, s)
|
|
}
|
|
}
|