/
stress.go
147 lines (131 loc) · 4.31 KB
/
stress.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"encoding/json"
"fmt"
"io"
"math/rand"
"runtime"
"time"
"v.io/v23/context"
"v.io/x/lib/cmdline"
"v.io/x/ref/lib/v23cmd"
"v.io/x/ref/runtime/internal/rpc/stress"
"v.io/x/ref/runtime/internal/rpc/stress/internal"
)
var (
duration time.Duration
workers int
maxChunkCnt int
maxPayloadSize int
outFormat string
)
func init() {
cmdStressTest.Flags.DurationVar(&duration, "duration", 1*time.Minute, "duration of the test to run")
cmdStressTest.Flags.IntVar(&workers, "workers", 1, "number of test workers to run")
cmdStressTest.Flags.IntVar(&maxChunkCnt, "max-chunk-count", 1000, "maximum number of chunks to send per streaming RPC")
cmdStressTest.Flags.IntVar(&maxPayloadSize, "max-payload-size", 10000, "maximum size of payload in bytes")
cmdStressTest.Flags.StringVar(&outFormat, "format", "text", "Stats output format; either text or json")
cmdStressStats.Flags.StringVar(&outFormat, "format", "text", "Stats output format; either text or json")
}
var cmdStressTest = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runStressTest),
Name: "stress",
Short: "Run stress test",
Long: "Run stress test",
ArgsName: "<server> ...",
ArgsLong: "<server> ... A list of servers to connect to.",
}
func runStressTest(ctx *context.T, env *cmdline.Env, args []string) error {
if len(args) == 0 {
return env.UsageErrorf("no server specified")
}
if outFormat != "text" && outFormat != "json" {
return env.UsageErrorf("invalid output format: %s\n", outFormat)
}
rnd := rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec
fmt.Fprintf(env.Stdout, "starting stress test against %d server(s) using %d core(s)...\n", len(args), runtime.NumCPU())
fmt.Fprintf(env.Stdout, "workers: %d, maxChunkCnt: %d, maxPayloadSize: %d, duration: %v\n", workers, maxChunkCnt, maxPayloadSize, duration)
start := time.Now()
done := make(chan stress.SumStats)
for i := 0; i < workers; i++ {
go func() {
var stats stress.SumStats
timeout := time.After(duration)
done:
for {
server := args[rnd.Intn(len(args))]
if rnd.Intn(2) == 0 {
internal.CallSum(ctx, server, maxPayloadSize, &stats)
} else {
internal.CallSumStream(ctx, server, maxChunkCnt, maxPayloadSize, &stats)
}
select {
case <-timeout:
break done
default:
}
}
done <- stats
}()
}
var merged stress.SumStats
for i := 0; i < workers; i++ {
stats := <-done
merged.SumCount += stats.SumCount
merged.SumStreamCount += stats.SumStreamCount
merged.BytesRecv += stats.BytesRecv
merged.BytesSent += stats.BytesSent
}
elapsed := time.Since(start)
fmt.Printf("done after %v\n", elapsed)
return outSumStats(env.Stdout, outFormat, "client stats:", &merged)
}
var cmdStressStats = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runStressStats),
Name: "stats",
Short: "Print out stress stats of servers",
Long: "Print out stress stats of servers",
ArgsName: "<server> ...",
ArgsLong: "<server> ... A list of servers to connect to.",
}
func runStressStats(ctx *context.T, env *cmdline.Env, args []string) error {
if len(args) == 0 {
return env.UsageErrorf("no server specified")
}
if outFormat != "text" && outFormat != "json" {
return env.UsageErrorf("invalid output format: %s\n", outFormat)
}
for _, server := range args {
stats, err := stress.StressClient(server).GetSumStats(ctx)
if err != nil {
return err
}
title := fmt.Sprintf("server stats(%s):", server)
if err := outSumStats(env.Stdout, outFormat, title, &stats); err != nil {
return err
}
}
return nil
}
func outSumStats(w io.Writer, format, title string, stats *stress.SumStats) error {
switch format {
case "text":
fmt.Fprintf(w, "%s\n", title)
fmt.Fprintf(w, "\tnumber of non-streaming RPCs:\t%d\n", stats.SumCount)
fmt.Fprintf(w, "\tnumber of streaming RPCs:\t%d\n", stats.SumStreamCount)
fmt.Fprintf(w, "\tnumber of bytes received:\t%d\n", stats.BytesRecv)
fmt.Fprintf(w, "\tnumber of bytes sent:\t\t%d\n", stats.BytesSent)
case "json":
b, err := json.Marshal(stats)
if err != nil {
return err
}
fmt.Fprintf(w, "%s%s\n", title, b)
default:
return fmt.Errorf("invalid output format: %s", format)
}
return nil
}