Skip to content

feat(cli): add trafficgen command for load testing #7307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
220edbf
feat(cli): add trafficgen command for load testing
johnstcn Apr 18, 2023
737b475
skip test for now
johnstcn Apr 27, 2023
9b26587
make fmt
johnstcn Apr 27, 2023
c56d84e
lint
johnstcn Apr 27, 2023
e548892
swap order of waiting for read and write
johnstcn Apr 27, 2023
31ef743
close connection, add output formatting
johnstcn May 2, 2023
fafca95
do what the comment says
johnstcn May 2, 2023
65c6d88
move back under scaletest cmd
johnstcn May 2, 2023
0bfa9f6
integrate with scaletest harness
johnstcn May 2, 2023
da935a2
drain connection async
johnstcn May 3, 2023
5daa526
fix cancellation
johnstcn May 3, 2023
4f165be
handle deadline exceeded in drain
johnstcn May 3, 2023
31fa8be
address PR comments
johnstcn May 3, 2023
0817204
fixup! address PR comments
johnstcn May 3, 2023
a6d7870
ACTUALLY limit traffic instead of just blasting the firehose
johnstcn May 3, 2023
935dcbd
log config
johnstcn May 3, 2023
e2efeff
lint
johnstcn May 3, 2023
b105e67
chore(cli): scaletest: move logic for flushing traces into tracing pr…
johnstcn May 4, 2023
731b4db
remove unnecessary context-based I/O
johnstcn May 4, 2023
9dc28a2
refactor bytes per second to bytes per tick and tick interval
johnstcn May 4, 2023
7b98b35
rename trafficgen -> workspace-traffic
johnstcn May 4, 2023
b9c845f
make gen
johnstcn May 4, 2023
2574a00
use strategy.timeout instead of duration
johnstcn May 4, 2023
516ffa1
rm ctx from countReadWriter
johnstcn May 4, 2023
655d95a
fixup
johnstcn May 5, 2023
ca8b212
Merge remote-tracking branch 'origin/main' into cj/scaletest-trafficgen
johnstcn May 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor bytes per second to bytes per tick and tick interval
  • Loading branch information
johnstcn committed May 4, 2023
commit 9dc28a2ba6f33b55a839a4f7b7adf4f9f1d09e5f
26 changes: 17 additions & 9 deletions cli/scaletest.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,8 @@ func (r *RootCmd) scaletestCreateWorkspaces() *clibase.Cmd {
func (r *RootCmd) scaletestTrafficGen() *clibase.Cmd {
var (
duration time.Duration
bps int64
tickInterval time.Duration
bytesPerTick int64
client = &codersdk.Client{}
tracingFlags = &scaletestTracingFlags{}
strategy = &scaletestStrategyFlags{}
Expand Down Expand Up @@ -975,10 +976,10 @@ func (r *RootCmd) scaletestTrafficGen() *clibase.Cmd {

// Setup our workspace agent connection.
config := trafficgen.Config{
AgentID: agentID,
BytesPerSecond: bps,
Duration: duration,
TicksPerSecond: 10,
AgentID: agentID,
BytesPerTick: bytesPerTick,
Duration: duration,
TickInterval: tickInterval,
}

if err := config.Validate(); err != nil {
Expand Down Expand Up @@ -1029,11 +1030,18 @@ func (r *RootCmd) scaletestTrafficGen() *clibase.Cmd {
Value: clibase.DurationOf(&duration),
},
{
Flag: "bps",
Env: "CODER_SCALETEST_TRAFFICGEN_BPS",
Flag: "bytes-per-tick",
Env: "CODER_SCALETEST_TRAFFICGEN_BYTES_PER_TICK",
Default: "1024",
Description: "How much traffic to generate in bytes per second.",
Value: clibase.Int64Of(&bps),
Description: "How much traffic to generate per tick.",
Value: clibase.Int64Of(&bytesPerTick),
},
{
Flag: "tick-interval",
Env: "CODER_SCALETEST_TRAFFICGEN_TICK_INTERVAL",
Default: "100ms",
Description: "How often to send traffic.",
Value: clibase.DurationOf(&tickInterval),
},
}

Expand Down
3 changes: 2 additions & 1 deletion cli/scaletest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ func TestScaleTestTrafficGen(t *testing.T) {

inv, root := clitest.New(t, "scaletest", "trafficgen", ws.Name,
"--duration", "1s",
"--bps", "100",
"--bytes-per-tick", "1024",
"--tick-interval", "100ms",
)
clitest.SetupConfig(t, client, root)
var stdout, stderr bytes.Buffer
Expand Down
17 changes: 9 additions & 8 deletions scaletest/trafficgen/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,33 @@ import (
type Config struct {
// AgentID is the workspace agent ID to which to connect.
AgentID uuid.UUID `json:"agent_id"`
// BytesPerSecond is the number of bytes to send to the agent.

BytesPerSecond int64 `json:"bytes_per_second"`
// BytesPerTick is the number of bytes to send to the agent per tick.
BytesPerTick int64 `json:"bytes_per_tick"`

// Duration is the total duration for which to send traffic to the agent.
Duration time.Duration `json:"duration"`

// TicksPerSecond specifies how many times per second we send traffic.
TicksPerSecond int64 `json:"ticks_per_second"`
// TicksInterval specifies how many times per second we send traffic.
TickInterval time.Duration `json:"tick_interval"`
}

func (c Config) Validate() error {
if c.AgentID == uuid.Nil {
return xerrors.Errorf("validate agent_id: must not be nil")
}

if c.BytesPerSecond <= 0 {
return xerrors.Errorf("validate bytes_per_second: must be greater than zero")
if c.BytesPerTick <= 0 {
return xerrors.Errorf("validate bytes_per_tick: must be greater than zero")
}

if c.Duration <= 0 {
return xerrors.Errorf("validate duration: must be greater than zero")
}

if c.TicksPerSecond <= 0 {
return xerrors.Errorf("validate ticks_per_second: must be greater than zero")
if c.TickInterval <= 0 {
return xerrors.Errorf("validate tick_interval: must be greater than zero")
}

return nil
}
21 changes: 15 additions & 6 deletions scaletest/trafficgen/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ func (r *Runner) Run(ctx context.Context, _ string, logs io.Writer) error {
reconnect = uuid.New()
height uint16 = 25
width uint16 = 80
tickInterval = time.Second / time.Duration(r.cfg.TicksPerSecond)
bytesPerTick = r.cfg.BytesPerSecond / r.cfg.TicksPerSecond
tickInterval = r.cfg.TickInterval
bytesPerTick = r.cfg.BytesPerTick
)

logger.Info(ctx, "config",
Expand Down Expand Up @@ -149,7 +149,10 @@ func (*Runner) Cleanup(context.Context, string) error {
// drain drains from src until it returns io.EOF or ctx times out.
func drain(src io.Reader) error {
if _, err := io.Copy(io.Discard, src); err != nil {
if xerrors.Is(err, context.DeadlineExceeded) || xerrors.Is(err, websocket.CloseError{}) {
if xerrors.Is(err, context.DeadlineExceeded) {
return nil
}
if xerrors.As(err, &websocket.CloseError{}) {
return nil
}
return err
Expand All @@ -166,7 +169,10 @@ func writeRandomData(dst io.Writer, size int64, tick <-chan time.Time) error {
payload := "#" + mustRandStr(size-1)
ptyReq.Data = payload
if err := enc.Encode(ptyReq); err != nil {
if xerrors.Is(err, context.DeadlineExceeded) || xerrors.Is(err, websocket.CloseError{}) {
if xerrors.Is(err, context.DeadlineExceeded) {
return nil
}
if xerrors.As(err, &websocket.CloseError{}) {
return nil
}
return err
Expand Down Expand Up @@ -213,8 +219,11 @@ func (w *countReadWriter) BytesWritten() int64 {
return w.bytesWritten.Load()
}

func mustRandStr(len int64) string {
randStr, err := cryptorand.String(int(len))
func mustRandStr(l int64) string {
if l < 1 {
l = 1
}
randStr, err := cryptorand.String(int(l))
if err != nil {
panic(err)
}
Expand Down