Skip to content

Commit 329ccb4

Browse files
committed
feat(benchmarks/rps): add latency output
Signed-off-by: René Jochum <jochumdev@gmail.com>
1 parent ce917cb commit 329ccb4

File tree

1 file changed

+58
-5
lines changed
  • benchmarks/rps/cmd/orb-rps-client

1 file changed

+58
-5
lines changed

benchmarks/rps/cmd/orb-rps-client/main.go

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77
"crypto/rand"
88
"errors"
99
"fmt"
10+
"math"
1011
"os"
1112
"runtime"
13+
"sort"
1214
"sync"
1315
"sync/atomic"
1416
"time"
@@ -38,6 +40,49 @@ import (
3840

3941
const serverName = "benchmarks.rps.server"
4042

43+
type latencyStats struct {
44+
latencies []time.Duration
45+
mu sync.Mutex
46+
}
47+
48+
func (l *latencyStats) add(d time.Duration) {
49+
l.mu.Lock()
50+
defer l.mu.Unlock()
51+
l.latencies = append(l.latencies, d)
52+
}
53+
54+
func (l *latencyStats) calculate() (time.Duration, time.Duration) {
55+
l.mu.Lock()
56+
defer l.mu.Unlock()
57+
58+
if len(l.latencies) == 0 {
59+
return 0, 0
60+
}
61+
62+
// Sort latencies for P99 calculation
63+
sort.Slice(l.latencies, func(i, j int) bool {
64+
return l.latencies[i] < l.latencies[j]
65+
})
66+
67+
// Calculate average
68+
var total time.Duration
69+
for _, d := range l.latencies {
70+
total += d
71+
}
72+
73+
avg := total / time.Duration(len(l.latencies))
74+
75+
// Calculate P99
76+
p99Index := int(math.Floor(float64(len(l.latencies)) * 0.99))
77+
if p99Index >= len(l.latencies) {
78+
p99Index = len(l.latencies) - 1
79+
}
80+
81+
p99 := l.latencies[p99Index]
82+
83+
return avg, p99
84+
}
85+
4186
type benchStats struct {
4287
ok atomic.Uint64
4388
error atomic.Uint64
@@ -52,6 +97,7 @@ func runConnection(
5297
msg []byte,
5398
opts []client.CallOption,
5499
stats *benchStats,
100+
latencyStats *latencyStats,
55101
) {
56102
defer wg.Done()
57103

@@ -63,6 +109,7 @@ func runConnection(
63109
case <-ctx.Done():
64110
return
65111
default:
112+
start := time.Now()
66113
// Run the query
67114
resp, err := client.Echo(
68115
ctx,
@@ -88,6 +135,7 @@ func runConnection(
88135
continue
89136
}
90137

138+
latencyStats.add(time.Since(start))
91139
stats.ok.Add(1)
92140
}
93141
}
@@ -113,10 +161,11 @@ func runBenchmark(
113161
logger log.Logger,
114162
msg []byte,
115163
opts []client.CallOption,
116-
) (uint64, uint64) {
164+
) (uint64, uint64, time.Duration, time.Duration) {
117165
var wg sync.WaitGroup
118166

119167
stats := &benchStats{}
168+
latencyStats := &latencyStats{latencies: make([]time.Duration, 0, 2000000)}
120169

121170
// Create benchmark context with timeout
122171
benchCtx, cancel := context.WithTimeout(ctx, time.Duration(duration)*time.Second)
@@ -126,7 +175,7 @@ func runBenchmark(
126175
for i := 0; i < connections; i++ {
127176
wg.Add(1)
128177

129-
go runConnection(benchCtx, &wg, cli, logger, msg, opts, stats)
178+
go runConnection(benchCtx, &wg, cli, logger, msg, opts, stats, latencyStats)
130179
}
131180

132181
// Wait for timeout or cancellation
@@ -135,11 +184,13 @@ func runBenchmark(
135184
// Wait for all goroutines to finish
136185
wg.Wait()
137186

138-
return stats.ok.Load(), stats.error.Load()
187+
avgLatency, p99Latency := latencyStats.calculate()
188+
return stats.ok.Load(), stats.error.Load(), avgLatency, p99Latency
139189
}
140190

141191
// bench is the main benchmark function.
142192
func bench(ctx context.Context, cfg *clientConfig, logger log.Logger, cli client.Type) error {
193+
143194
// Log configuration
144195
logger.Info("Configuration",
145196
"connections", cfg.Connections,
@@ -168,18 +219,20 @@ func bench(ctx context.Context, cfg *clientConfig, logger log.Logger, cli client
168219

169220
// Run warmup phase
170221
logger.Info("Warming up...")
171-
warmupOk, warmupErr := runBenchmark(ctx, 5, cfg.Connections, cli, logger, msg, opts)
222+
warmupOk, warmupErr, _, _ := runBenchmark(ctx, 5, cfg.Connections, cli, logger, msg, opts)
172223
logger.Debug("Warmup complete", "requests_ok", warmupOk, "requests_error", warmupErr)
173224

174225
// Run benchmark phase
175226
logger.Info("Running benchmark...")
176-
reqsOk, reqsError := runBenchmark(ctx, cfg.Duration, cfg.Connections, cli, logger, msg, opts)
227+
reqsOk, reqsError, avg, p99 := runBenchmark(ctx, cfg.Duration, cfg.Connections, cli, logger, msg, opts)
177228

178229
// Log results
179230
logger.Info("Summary",
180231
"requests_ok", reqsOk,
181232
"requests_error", reqsError,
182233
"qps", float64(reqsOk)/float64(cfg.Duration),
234+
"avg_latency_us", avg.Microseconds(),
235+
"p99_latency_us", p99.Microseconds(),
183236
"connections", cfg.Connections,
184237
"duration_seconds", cfg.Duration,
185238
"package_size", cfg.PackageSize,

0 commit comments

Comments
 (0)