mirror of
https://github.com/microsoft/ethr.git
synced 2024-09-20 06:46:14 +08:00
Improve throttling and add Title support (#141)
This commit is contained in:
parent
46d0e6286c
commit
aa636603a7
37
client.go
37
client.go
|
@ -263,7 +263,10 @@ func runTCPBandwidthTestHandler(test *ethrTest, conn net.Conn, wg *sync.WaitGrou
|
||||||
for i := uint32(0); i < size; i++ {
|
for i := uint32(0); i < size; i++ {
|
||||||
buff[i] = byte(i)
|
buff[i] = byte(i)
|
||||||
}
|
}
|
||||||
start, waitTime, sendRate := beginThrottle()
|
bufferLen := len(buff)
|
||||||
|
totalBytesToSend := test.clientParam.BwRate
|
||||||
|
sentBytes := uint64(0)
|
||||||
|
start, waitTime, bytesToSend := beginThrottle(totalBytesToSend, bufferLen)
|
||||||
ExitForLoop:
|
ExitForLoop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -273,19 +276,19 @@ ExitForLoop:
|
||||||
n := 0
|
n := 0
|
||||||
var err error = nil
|
var err error = nil
|
||||||
if test.clientParam.Reverse {
|
if test.clientParam.Reverse {
|
||||||
n, err = io.ReadFull(conn, buff)
|
n, err = conn.Read(buff)
|
||||||
} else {
|
} else {
|
||||||
n, err = conn.Write(buff)
|
n, err = conn.Write(buff[:bytesToSend])
|
||||||
}
|
}
|
||||||
if err != nil || n < int(size) {
|
if err != nil {
|
||||||
ui.printDbg("Error sending/receiving data on a connection for bandwidth test: %v", err)
|
ui.printDbg("Error sending/receiving data on a connection for bandwidth test: %v", err)
|
||||||
break ExitForLoop
|
break ExitForLoop
|
||||||
}
|
}
|
||||||
atomic.AddUint64(&ec.bw, uint64(size))
|
atomic.AddUint64(&ec.bw, uint64(n))
|
||||||
atomic.AddUint64(&test.testResult.bw, uint64(size))
|
atomic.AddUint64(&test.testResult.bw, uint64(n))
|
||||||
sendRate += uint64(size)
|
if !test.clientParam.Reverse {
|
||||||
if test.clientParam.BwRate > 0 && !test.clientParam.Reverse && sendRate >= test.clientParam.BwRate {
|
sentBytes += uint64(n)
|
||||||
start, waitTime, sendRate = enforceThrottle(start, waitTime)
|
start, waitTime, sentBytes, bytesToSend = enforceThrottle(start, waitTime, totalBytesToSend, sentBytes, bufferLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -968,20 +971,22 @@ func runUDPBandwidthAndPpsTest(test *ethrTest) {
|
||||||
lserver, lport, _ := net.SplitHostPort(conn.LocalAddr().String())
|
lserver, lport, _ := net.SplitHostPort(conn.LocalAddr().String())
|
||||||
ui.printMsg("[%3d] local %s port %s connected to %s port %s",
|
ui.printMsg("[%3d] local %s port %s connected to %s port %s",
|
||||||
ec.fd, lserver, lport, rserver, rport)
|
ec.fd, lserver, lport, rserver, rport)
|
||||||
blen := len(buff)
|
bufferLen := len(buff)
|
||||||
start, waitTime, sendRate := beginThrottle()
|
totalBytesToSend := test.clientParam.BwRate
|
||||||
|
sentBytes := uint64(0)
|
||||||
|
start, waitTime, bytesToSend := beginThrottle(totalBytesToSend, bufferLen)
|
||||||
ExitForLoop:
|
ExitForLoop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-test.done:
|
case <-test.done:
|
||||||
break ExitForLoop
|
break ExitForLoop
|
||||||
default:
|
default:
|
||||||
n, err := conn.Write(buff)
|
n, err := conn.Write(buff[:bytesToSend])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.printDbg("%v", err)
|
ui.printDbg("%v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n < blen {
|
if n < bytesToSend {
|
||||||
ui.printDbg("Partial write: %d", n)
|
ui.printDbg("Partial write: %d", n)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -989,9 +994,9 @@ func runUDPBandwidthAndPpsTest(test *ethrTest) {
|
||||||
atomic.AddUint64(&ec.pps, 1)
|
atomic.AddUint64(&ec.pps, 1)
|
||||||
atomic.AddUint64(&test.testResult.bw, uint64(n))
|
atomic.AddUint64(&test.testResult.bw, uint64(n))
|
||||||
atomic.AddUint64(&test.testResult.pps, 1)
|
atomic.AddUint64(&test.testResult.pps, 1)
|
||||||
sendRate += uint64(size)
|
if !test.clientParam.Reverse {
|
||||||
if test.clientParam.BwRate > 0 && !test.clientParam.Reverse && sendRate >= test.clientParam.BwRate {
|
sentBytes += uint64(n)
|
||||||
start, waitTime, sendRate = enforceThrottle(start, waitTime)
|
start, waitTime, sentBytes, bytesToSend = enforceThrottle(start, waitTime, totalBytesToSend, sentBytes, bufferLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
ethr.go
7
ethr.go
|
@ -208,13 +208,6 @@ func main() {
|
||||||
bwRate /= 8
|
bwRate /= 8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust the numbers so that data can be transfered in equal units.
|
|
||||||
if bwRate > 0 {
|
|
||||||
factor := (bwRate + bufLen - 1) / bufLen
|
|
||||||
bufLen = bwRate / factor
|
|
||||||
bwRate = bufLen * factor
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// For Pkt/s, we always override the buffer size to be just 1 byte.
|
// For Pkt/s, we always override the buffer size to be just 1 byte.
|
||||||
// TODO: Evaluate in future, if we need to support > 1 byte packets for
|
// TODO: Evaluate in future, if we need to support > 1 byte packets for
|
||||||
|
|
23
server.go
23
server.go
|
@ -149,22 +149,26 @@ func srvrRunTCPBandwidthTest(test *ethrTest, clientParam EthrClientParam, conn n
|
||||||
for i := uint32(0); i < size; i++ {
|
for i := uint32(0); i < size; i++ {
|
||||||
buff[i] = byte(i)
|
buff[i] = byte(i)
|
||||||
}
|
}
|
||||||
start, waitTime, sendRate := beginThrottle()
|
bufferLen := len(buff)
|
||||||
|
totalBytesToSend := test.clientParam.BwRate
|
||||||
|
sentBytes := uint64(0)
|
||||||
|
start, waitTime, bytesToSend := beginThrottle(totalBytesToSend, bufferLen)
|
||||||
for {
|
for {
|
||||||
|
n := 0
|
||||||
var err error
|
var err error
|
||||||
if clientParam.Reverse {
|
if clientParam.Reverse {
|
||||||
_, err = conn.Write(buff)
|
n, err = conn.Write(buff[:bytesToSend])
|
||||||
} else {
|
} else {
|
||||||
_, err = io.ReadFull(conn, buff)
|
n, err = conn.Read(buff)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.printDbg("Error sending/receiving data on a connection for bandwidth test: %v", err)
|
ui.printDbg("Error sending/receiving data on a connection for bandwidth test: %v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
sendRate += uint64(size)
|
|
||||||
atomic.AddUint64(&test.testResult.bw, uint64(size))
|
atomic.AddUint64(&test.testResult.bw, uint64(size))
|
||||||
if clientParam.BwRate > 0 && clientParam.Reverse && sendRate >= clientParam.BwRate {
|
if clientParam.Reverse {
|
||||||
start, waitTime, sendRate = enforceThrottle(start, waitTime)
|
sentBytes += uint64(n)
|
||||||
|
start, waitTime, sentBytes, bytesToSend = enforceThrottle(start, waitTime, totalBytesToSend, sentBytes, bufferLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,6 +243,12 @@ func srvrRunUDPServer() error {
|
||||||
ui.printDbg("Error listening on %s for UDP pkt/s tests: %v", gEthrPortStr, err)
|
ui.printDbg("Error listening on %s for UDP pkt/s tests: %v", gEthrPortStr, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Set socket buffer to 4MB per CPU so we can queue 4MB per CPU in case Ethr is not
|
||||||
|
// able to keep up temporarily.
|
||||||
|
err = l.SetReadBuffer(runtime.NumCPU() * 4 * 1024 * 1024)
|
||||||
|
if err != nil {
|
||||||
|
ui.printDbg("Failed to set ReadBuffer on UDP socket: %v", err)
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// We use NumCPU here instead of NumThreads passed from client. The
|
// We use NumCPU here instead of NumThreads passed from client. The
|
||||||
// reason is that for UDP, there is no connection, so all packets come
|
// reason is that for UDP, there is no connection, so all packets come
|
||||||
|
@ -289,6 +299,7 @@ func srvrRunUDPPacketHandler(conn *net.UDPConn) {
|
||||||
ui.printDbg("Error receiving data from UDP for bandwidth test: %v", err)
|
ui.printDbg("Error receiving data from UDP for bandwidth test: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
ethrUnused(remoteIP)
|
||||||
ethrUnused(n)
|
ethrUnused(n)
|
||||||
server, port, _ := net.SplitHostPort(remoteIP.String())
|
server, port, _ := net.SplitHostPort(remoteIP.String())
|
||||||
test, found := tests[server]
|
test, found := tests[server]
|
||||||
|
|
46
utils.go
46
utils.go
|
@ -397,6 +397,13 @@ func ethrDialEx(p EthrProtocol, dialAddr, localIP string, localPortNum uint16, t
|
||||||
if ok {
|
if ok {
|
||||||
tcpconn.SetLinger(0)
|
tcpconn.SetLinger(0)
|
||||||
}
|
}
|
||||||
|
udpconn, ok := conn.(*net.UDPConn)
|
||||||
|
if ok {
|
||||||
|
err = udpconn.SetWriteBuffer(4 * 1024 * 1024)
|
||||||
|
if err != nil {
|
||||||
|
ui.printDbg("Failed to set ReadBuffer on UDP socket: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -432,20 +439,39 @@ func ethrLookupIP(server string) (net.IPAddr, string, error) {
|
||||||
// This is a workaround to ensure we generate traffic at certain rate
|
// This is a workaround to ensure we generate traffic at certain rate
|
||||||
// and stats are printed correctly. We ensure that current interval lasts
|
// and stats are printed correctly. We ensure that current interval lasts
|
||||||
// 100ms after stats are printed, not perfect but workable.
|
// 100ms after stats are printed, not perfect but workable.
|
||||||
func beginThrottle() (start time.Time, waitTime time.Duration, sendRate uint64) {
|
func beginThrottle(totalBytesToSend uint64, bufferLen int) (start time.Time, waitTime time.Duration, bytesToSend int) {
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
waitTime = time.Until(lastStatsTime.Add(time.Second + 100*time.Millisecond))
|
waitTime = time.Until(lastStatsTime.Add(time.Second + 50*time.Millisecond))
|
||||||
sendRate = uint64(0)
|
bytesToSend = bufferLen
|
||||||
|
if totalBytesToSend > 0 && totalBytesToSend < uint64(bufferLen) {
|
||||||
|
bytesToSend = int(totalBytesToSend)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func enforceThrottle(s time.Time, wt time.Duration) (start time.Time, waitTime time.Duration, sendRate uint64) {
|
func enforceThrottle(s time.Time, wt time.Duration, totalBytesToSend, oldSentBytes uint64, bufferLen int) (start time.Time, waitTime time.Duration, newSentBytes uint64, bytesToSend int) {
|
||||||
timeTaken := time.Since(s)
|
start = s
|
||||||
if timeTaken < wt {
|
waitTime = wt
|
||||||
time.Sleep(wt - timeTaken)
|
newSentBytes = oldSentBytes
|
||||||
|
bytesToSend = bufferLen
|
||||||
|
if totalBytesToSend > 0 {
|
||||||
|
remainingBytes := totalBytesToSend - oldSentBytes
|
||||||
|
if remainingBytes > 0 {
|
||||||
|
if remainingBytes < uint64(bufferLen) {
|
||||||
|
bytesToSend = int(remainingBytes)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeTaken := time.Since(s)
|
||||||
|
if timeTaken < wt {
|
||||||
|
time.Sleep(wt - timeTaken)
|
||||||
|
}
|
||||||
|
start = time.Now()
|
||||||
|
waitTime = time.Until(lastStatsTime.Add(time.Second + 50*time.Millisecond))
|
||||||
|
newSentBytes = 0
|
||||||
|
if totalBytesToSend < uint64(bufferLen) {
|
||||||
|
bytesToSend = int(totalBytesToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
start = time.Now()
|
|
||||||
waitTime = time.Until(lastStatsTime.Add(time.Second + 100*time.Millisecond))
|
|
||||||
sendRate = 0
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue