Skip to content

Commit aa63660

Browse files
authored
Improve throttling and add Title support (#141)
1 parent 46d0e62 commit aa63660

File tree

4 files changed

+74
-39
lines changed

4 files changed

+74
-39
lines changed

client.go

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,10 @@ func runTCPBandwidthTestHandler(test *ethrTest, conn net.Conn, wg *sync.WaitGrou
263263
for i := uint32(0); i < size; i++ {
264264
buff[i] = byte(i)
265265
}
266-
start, waitTime, sendRate := beginThrottle()
266+
bufferLen := len(buff)
267+
totalBytesToSend := test.clientParam.BwRate
268+
sentBytes := uint64(0)
269+
start, waitTime, bytesToSend := beginThrottle(totalBytesToSend, bufferLen)
267270
ExitForLoop:
268271
for {
269272
select {
@@ -273,19 +276,19 @@ ExitForLoop:
273276
n := 0
274277
var err error = nil
275278
if test.clientParam.Reverse {
276-
n, err = io.ReadFull(conn, buff)
279+
n, err = conn.Read(buff)
277280
} else {
278-
n, err = conn.Write(buff)
281+
n, err = conn.Write(buff[:bytesToSend])
279282
}
280-
if err != nil || n < int(size) {
283+
if err != nil {
281284
ui.printDbg("Error sending/receiving data on a connection for bandwidth test: %v", err)
282285
break ExitForLoop
283286
}
284-
atomic.AddUint64(&ec.bw, uint64(size))
285-
atomic.AddUint64(&test.testResult.bw, uint64(size))
286-
sendRate += uint64(size)
287-
if test.clientParam.BwRate > 0 && !test.clientParam.Reverse && sendRate >= test.clientParam.BwRate {
288-
start, waitTime, sendRate = enforceThrottle(start, waitTime)
287+
atomic.AddUint64(&ec.bw, uint64(n))
288+
atomic.AddUint64(&test.testResult.bw, uint64(n))
289+
if !test.clientParam.Reverse {
290+
sentBytes += uint64(n)
291+
start, waitTime, sentBytes, bytesToSend = enforceThrottle(start, waitTime, totalBytesToSend, sentBytes, bufferLen)
289292
}
290293
}
291294
}
@@ -968,30 +971,32 @@ func runUDPBandwidthAndPpsTest(test *ethrTest) {
968971
lserver, lport, _ := net.SplitHostPort(conn.LocalAddr().String())
969972
ui.printMsg("[%3d] local %s port %s connected to %s port %s",
970973
ec.fd, lserver, lport, rserver, rport)
971-
blen := len(buff)
972-
start, waitTime, sendRate := beginThrottle()
974+
bufferLen := len(buff)
975+
totalBytesToSend := test.clientParam.BwRate
976+
sentBytes := uint64(0)
977+
start, waitTime, bytesToSend := beginThrottle(totalBytesToSend, bufferLen)
973978
ExitForLoop:
974979
for {
975980
select {
976981
case <-test.done:
977982
break ExitForLoop
978983
default:
979-
n, err := conn.Write(buff)
984+
n, err := conn.Write(buff[:bytesToSend])
980985
if err != nil {
981986
ui.printDbg("%v", err)
982987
continue
983988
}
984-
if n < blen {
989+
if n < bytesToSend {
985990
ui.printDbg("Partial write: %d", n)
986991
continue
987992
}
988993
atomic.AddUint64(&ec.bw, uint64(n))
989994
atomic.AddUint64(&ec.pps, 1)
990995
atomic.AddUint64(&test.testResult.bw, uint64(n))
991996
atomic.AddUint64(&test.testResult.pps, 1)
992-
sendRate += uint64(size)
993-
if test.clientParam.BwRate > 0 && !test.clientParam.Reverse && sendRate >= test.clientParam.BwRate {
994-
start, waitTime, sendRate = enforceThrottle(start, waitTime)
997+
if !test.clientParam.Reverse {
998+
sentBytes += uint64(n)
999+
start, waitTime, sentBytes, bytesToSend = enforceThrottle(start, waitTime, totalBytesToSend, sentBytes, bufferLen)
9951000
}
9961001
}
9971002
}

ethr.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,6 @@ func main() {
208208
bwRate /= 8
209209
}
210210

211-
// Adjust the numbers so that data can be transfered in equal units.
212-
if bwRate > 0 {
213-
factor := (bwRate + bufLen - 1) / bufLen
214-
bufLen = bwRate / factor
215-
bwRate = bufLen * factor
216-
}
217-
218211
//
219212
// For Pkt/s, we always override the buffer size to be just 1 byte.
220213
// TODO: Evaluate in future, if we need to support > 1 byte packets for

server.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,22 +149,26 @@ func srvrRunTCPBandwidthTest(test *ethrTest, clientParam EthrClientParam, conn n
149149
for i := uint32(0); i < size; i++ {
150150
buff[i] = byte(i)
151151
}
152-
start, waitTime, sendRate := beginThrottle()
152+
bufferLen := len(buff)
153+
totalBytesToSend := test.clientParam.BwRate
154+
sentBytes := uint64(0)
155+
start, waitTime, bytesToSend := beginThrottle(totalBytesToSend, bufferLen)
153156
for {
157+
n := 0
154158
var err error
155159
if clientParam.Reverse {
156-
_, err = conn.Write(buff)
160+
n, err = conn.Write(buff[:bytesToSend])
157161
} else {
158-
_, err = io.ReadFull(conn, buff)
162+
n, err = conn.Read(buff)
159163
}
160164
if err != nil {
161165
ui.printDbg("Error sending/receiving data on a connection for bandwidth test: %v", err)
162166
break
163167
}
164-
sendRate += uint64(size)
165168
atomic.AddUint64(&test.testResult.bw, uint64(size))
166-
if clientParam.BwRate > 0 && clientParam.Reverse && sendRate >= clientParam.BwRate {
167-
start, waitTime, sendRate = enforceThrottle(start, waitTime)
169+
if clientParam.Reverse {
170+
sentBytes += uint64(n)
171+
start, waitTime, sentBytes, bytesToSend = enforceThrottle(start, waitTime, totalBytesToSend, sentBytes, bufferLen)
168172
}
169173
}
170174
}
@@ -239,6 +243,12 @@ func srvrRunUDPServer() error {
239243
ui.printDbg("Error listening on %s for UDP pkt/s tests: %v", gEthrPortStr, err)
240244
return err
241245
}
246+
// Set socket buffer to 4MB per CPU so we can queue 4MB per CPU in case Ethr is not
247+
// able to keep up temporarily.
248+
err = l.SetReadBuffer(runtime.NumCPU() * 4 * 1024 * 1024)
249+
if err != nil {
250+
ui.printDbg("Failed to set ReadBuffer on UDP socket: %v", err)
251+
}
242252
//
243253
// We use NumCPU here instead of NumThreads passed from client. The
244254
// reason is that for UDP, there is no connection, so all packets come
@@ -289,6 +299,7 @@ func srvrRunUDPPacketHandler(conn *net.UDPConn) {
289299
ui.printDbg("Error receiving data from UDP for bandwidth test: %v", err)
290300
continue
291301
}
302+
ethrUnused(remoteIP)
292303
ethrUnused(n)
293304
server, port, _ := net.SplitHostPort(remoteIP.String())
294305
test, found := tests[server]

utils.go

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,13 @@ func ethrDialEx(p EthrProtocol, dialAddr, localIP string, localPortNum uint16, t
397397
if ok {
398398
tcpconn.SetLinger(0)
399399
}
400+
udpconn, ok := conn.(*net.UDPConn)
401+
if ok {
402+
err = udpconn.SetWriteBuffer(4 * 1024 * 1024)
403+
if err != nil {
404+
ui.printDbg("Failed to set ReadBuffer on UDP socket: %v", err)
405+
}
406+
}
400407
}
401408
return
402409
}
@@ -432,20 +439,39 @@ func ethrLookupIP(server string) (net.IPAddr, string, error) {
432439
// This is a workaround to ensure we generate traffic at certain rate
433440
// and stats are printed correctly. We ensure that current interval lasts
434441
// 100ms after stats are printed, not perfect but workable.
435-
func beginThrottle() (start time.Time, waitTime time.Duration, sendRate uint64) {
442+
func beginThrottle(totalBytesToSend uint64, bufferLen int) (start time.Time, waitTime time.Duration, bytesToSend int) {
436443
start = time.Now()
437-
waitTime = time.Until(lastStatsTime.Add(time.Second + 100*time.Millisecond))
438-
sendRate = uint64(0)
444+
waitTime = time.Until(lastStatsTime.Add(time.Second + 50*time.Millisecond))
445+
bytesToSend = bufferLen
446+
if totalBytesToSend > 0 && totalBytesToSend < uint64(bufferLen) {
447+
bytesToSend = int(totalBytesToSend)
448+
}
439449
return
440450
}
441451

442-
func enforceThrottle(s time.Time, wt time.Duration) (start time.Time, waitTime time.Duration, sendRate uint64) {
443-
timeTaken := time.Since(s)
444-
if timeTaken < wt {
445-
time.Sleep(wt - timeTaken)
452+
func enforceThrottle(s time.Time, wt time.Duration, totalBytesToSend, oldSentBytes uint64, bufferLen int) (start time.Time, waitTime time.Duration, newSentBytes uint64, bytesToSend int) {
453+
start = s
454+
waitTime = wt
455+
newSentBytes = oldSentBytes
456+
bytesToSend = bufferLen
457+
if totalBytesToSend > 0 {
458+
remainingBytes := totalBytesToSend - oldSentBytes
459+
if remainingBytes > 0 {
460+
if remainingBytes < uint64(bufferLen) {
461+
bytesToSend = int(remainingBytes)
462+
}
463+
} else {
464+
timeTaken := time.Since(s)
465+
if timeTaken < wt {
466+
time.Sleep(wt - timeTaken)
467+
}
468+
start = time.Now()
469+
waitTime = time.Until(lastStatsTime.Add(time.Second + 50*time.Millisecond))
470+
newSentBytes = 0
471+
if totalBytesToSend < uint64(bufferLen) {
472+
bytesToSend = int(totalBytesToSend)
473+
}
474+
}
446475
}
447-
start = time.Now()
448-
waitTime = time.Until(lastStatsTime.Add(time.Second + 100*time.Millisecond))
449-
sendRate = 0
450476
return
451477
}

0 commit comments

Comments
 (0)