From c18470a5f1114f8c5469c311502050e88d2ca9bb Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Tue, 28 Sep 2021 16:47:35 -0400 Subject: [PATCH] e2e: use network size in load generator (#7019) --- test/e2e/runner/evidence.go | 4 ++-- test/e2e/runner/load.go | 37 ++++++++++++++++--------------------- test/e2e/runner/main.go | 30 ++++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/test/e2e/runner/evidence.go b/test/e2e/runner/evidence.go index e6c7c3f7a..25c4a1cc4 100644 --- a/test/e2e/runner/evidence.go +++ b/test/e2e/runner/evidence.go @@ -28,11 +28,11 @@ const lightClientEvidenceRatio = 4 // evidence and broadcasts it to a random node through the rpc endpoint `/broadcast_evidence`. // Evidence is random and can be a mixture of LightClientAttackEvidence and // DuplicateVoteEvidence. -func InjectEvidence(ctx context.Context, testnet *e2e.Testnet, amount int) error { +func InjectEvidence(ctx context.Context, r *rand.Rand, testnet *e2e.Testnet, amount int) error { // select a random node var targetNode *e2e.Node - for _, idx := range rand.Perm(len(testnet.Nodes)) { + for _, idx := range r.Perm(len(testnet.Nodes)) { targetNode = testnet.Nodes[idx] if targetNode.Mode == e2e.ModeSeed || targetNode.Mode == e2e.ModeLight { diff --git a/test/e2e/runner/load.go b/test/e2e/runner/load.go index 5e6e04f89..f31b436dd 100644 --- a/test/e2e/runner/load.go +++ b/test/e2e/runner/load.go @@ -14,15 +14,15 @@ import ( // Load generates transactions against the network until the given context is // canceled. -func Load(ctx context.Context, testnet *e2e.Testnet) error { +func Load(ctx context.Context, r *rand.Rand, testnet *e2e.Testnet) error { // Since transactions are executed across all nodes in the network, we need // to reduce transaction load for larger networks to avoid using too much // CPU. This gives high-throughput small networks and low-throughput large ones. // This also limits the number of TCP connections, since each worker has // a connection to all nodes. - concurrency := len(testnet.Nodes) * 8 - if concurrency > 64 { - concurrency = 64 + concurrency := len(testnet.Nodes) * 2 + if concurrency > 32 { + concurrency = 32 } chTx := make(chan types.Tx) @@ -38,7 +38,7 @@ func Load(ctx context.Context, testnet *e2e.Testnet) error { started := time.Now() - go loadGenerate(ctx, chTx, testnet.TxSize) + go loadGenerate(ctx, r, chTx, testnet.TxSize, len(testnet.Nodes)) for w := 0; w < concurrency; w++ { go loadProcess(ctx, testnet, chTx, chSuccess) @@ -85,7 +85,7 @@ func Load(ctx context.Context, testnet *e2e.Testnet) error { // generation is primarily the result of backpressure from the // broadcast transaction, though there is still some timer-based // limiting. -func loadGenerate(ctx context.Context, chTx chan<- types.Tx, size int64) { +func loadGenerate(ctx context.Context, r *rand.Rand, chTx chan<- types.Tx, txSize int64, networkSize int) { timer := time.NewTimer(0) defer timer.Stop() defer close(chTx) @@ -101,8 +101,8 @@ func loadGenerate(ctx context.Context, chTx chan<- types.Tx, size int64) { // This gives a reasonable load without putting too much data in the app. id := rand.Int63() % 100 // nolint: gosec - bz := make([]byte, size) - _, err := rand.Read(bz) // nolint: gosec + bz := make([]byte, txSize) + _, err := r.Read(bz) if err != nil { panic(fmt.Sprintf("Failed to read random bytes: %v", err)) } @@ -114,30 +114,25 @@ func loadGenerate(ctx context.Context, chTx chan<- types.Tx, size int64) { case chTx <- tx: // sleep for a bit before sending the // next transaction. - timer.Reset(loadGenerateWaitTime(size)) + timer.Reset(loadGenerateWaitTime(r, networkSize)) } } } -func loadGenerateWaitTime(size int64) time.Duration { +func loadGenerateWaitTime(r *rand.Rand, size int) time.Duration { const ( - min = int64(10 * time.Millisecond) - max = int64(100 * time.Millisecond) + min = int64(250 * time.Millisecond) + max = int64(time.Second) ) var ( - baseJitter = rand.Int63n(max-min+1) + min // nolint: gosec - sizeFactor = size * int64(time.Millisecond) - sizeJitter = rand.Int63n(sizeFactor-min+1) + min // nolint: gosec - waitTime = time.Duration(baseJitter + sizeJitter) + baseJitter = r.Int63n(max-min+1) + min + sizeFactor = int64(size) * min + sizeJitter = r.Int63n(sizeFactor-min+1) + min ) - if size == 1 { - return waitTime / 2 - } - - return waitTime + return time.Duration(baseJitter + sizeJitter) } // loadProcess processes transactions diff --git a/test/e2e/runner/main.go b/test/e2e/runner/main.go index 194e4c6e4..fb6ce4a8c 100644 --- a/test/e2e/runner/main.go +++ b/test/e2e/runner/main.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "math/rand" "os" "strconv" "time" @@ -13,9 +14,9 @@ import ( e2e "github.com/tendermint/tendermint/test/e2e/pkg" ) -var ( - logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) -) +const randomSeed = 2308084734268 + +var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) func main() { NewCLI().Run() @@ -67,6 +68,8 @@ func NewCLI() *CLI { return err } + r := rand.New(rand.NewSource(randomSeed)) // nolint: gosec + chLoadResult := make(chan error) ctx, cancel := context.WithCancel(cmd.Context()) defer cancel() @@ -74,7 +77,7 @@ func NewCLI() *CLI { lctx, loadCancel := context.WithCancel(ctx) defer loadCancel() go func() { - chLoadResult <- Load(lctx, cli.testnet) + chLoadResult <- Load(lctx, r, cli.testnet) }() startAt := time.Now() if err = Start(ctx, cli.testnet); err != nil { @@ -95,7 +98,7 @@ func NewCLI() *CLI { } if cli.testnet.Evidence > 0 { - if err = InjectEvidence(ctx, cli.testnet, cli.testnet.Evidence); err != nil { + if err = InjectEvidence(ctx, r, cli.testnet, cli.testnet.Evidence); err != nil { return err } if err = Wait(ctx, cli.testnet, 5); err != nil { // ensure chain progress @@ -212,7 +215,11 @@ func NewCLI() *CLI { Use: "load", Short: "Generates transaction load until the command is canceled", RunE: func(cmd *cobra.Command, args []string) (err error) { - return Load(context.Background(), cli.testnet) + return Load( + cmd.Context(), + rand.New(rand.NewSource(randomSeed)), // nolint: gosec + cli.testnet, + ) }, }) @@ -230,7 +237,12 @@ func NewCLI() *CLI { } } - return InjectEvidence(cmd.Context(), cli.testnet, amount) + return InjectEvidence( + cmd.Context(), + rand.New(rand.NewSource(randomSeed)), // nolint: gosec + cli.testnet, + amount, + ) }, }) @@ -302,10 +314,12 @@ Does not run any perbutations. ctx, cancel := context.WithCancel(cmd.Context()) defer cancel() + r := rand.New(rand.NewSource(randomSeed)) // nolint: gosec + lctx, loadCancel := context.WithCancel(ctx) defer loadCancel() go func() { - err := Load(lctx, cli.testnet) + err := Load(lctx, r, cli.testnet) chLoadResult <- err }()