187 lines
4.3 KiB
Go
187 lines
4.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
modulev1 "cosmossdk.io/api/cosmos/benchmark/module/v1"
|
|
"cosmossdk.io/tools/benchmark"
|
|
gen "cosmossdk.io/tools/benchmark/generator"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
|
|
)
|
|
|
|
func NewTxCmd(params *modulev1.GeneratorParams) *cobra.Command {
|
|
txCmd := &cobra.Command{
|
|
Use: "benchmark",
|
|
Short: "benchmark transaction subcommands",
|
|
DisableFlagParsing: true,
|
|
SuggestionsMinimumDistance: 2,
|
|
RunE: client.ValidateCmd,
|
|
}
|
|
|
|
txCmd.AddCommand(
|
|
NewLoadTestCmd(params),
|
|
)
|
|
|
|
return txCmd
|
|
}
|
|
|
|
func NewLoadTestCmd(params *modulev1.GeneratorParams) *cobra.Command {
|
|
var (
|
|
verbose bool
|
|
pause int64
|
|
numOps uint64
|
|
)
|
|
cmd := &cobra.Command{
|
|
Use: "load-test",
|
|
RunE: func(cmd *cobra.Command, args []string) (runErr error) {
|
|
clientCtx, err := client.GetClientTxContext(cmd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ctx, cancelFn := context.WithCancel(cmd.Context())
|
|
go func() {
|
|
sigCh := make(chan os.Signal, 1)
|
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
|
select {
|
|
case sig := <-sigCh:
|
|
cancelFn()
|
|
cmd.Printf("caught %s signal\n", sig.String())
|
|
case <-ctx.Done():
|
|
cancelFn()
|
|
}
|
|
}()
|
|
|
|
var (
|
|
successCount int
|
|
errCount int
|
|
since = time.Now()
|
|
last int
|
|
)
|
|
defer func() {
|
|
cmd.Printf("done! success_tx=%d err_tx=%d\n", successCount, errCount)
|
|
}()
|
|
accNum, accSeq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, clientCtx.FromAddress)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
txf, err := clienttx.NewFactoryCLI(clientCtx, cmd.Flags())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
txf = txf.WithAccountNumber(accNum).WithChainID(clientCtx.ChainID).WithGas(1_000_000_000)
|
|
|
|
storeKeys, err := gen.StoreKeys("benchmark", params.Seed, params.BucketCount)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var seed uint64
|
|
for _, c := range clientCtx.FromAddress {
|
|
// root the generator seed in the account address
|
|
seed += uint64(c)
|
|
}
|
|
g := gen.NewGenerator(gen.Options{
|
|
HomeDir: clientCtx.HomeDir,
|
|
GeneratorParams: params,
|
|
InsertWeight: 0.25,
|
|
DeleteWeight: 0.05,
|
|
UpdateWeight: 0.50,
|
|
GetWeight: 0.20,
|
|
},
|
|
gen.WithGenesis(),
|
|
gen.WithSeed(seed),
|
|
)
|
|
if err = g.Load(); err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err = g.Close(); err != nil {
|
|
runErr = errors.Join(runErr, err)
|
|
}
|
|
}()
|
|
|
|
begin := time.Now()
|
|
ops := make([]*benchmark.Op, numOps)
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil
|
|
default:
|
|
}
|
|
if time.Since(since) > 5*time.Second {
|
|
cmd.Printf(
|
|
"success_tx=%d err_tx=%d seq=%d rate=%.2f/s overall=%.2f/s\n",
|
|
successCount, errCount, accSeq,
|
|
float64(successCount-last)/time.Since(since).Seconds(),
|
|
float64(successCount)/time.Since(begin).Seconds(),
|
|
)
|
|
since = time.Now()
|
|
last = successCount
|
|
}
|
|
|
|
for j := range numOps {
|
|
bucket, op, err := g.Next()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
op.Actor = storeKeys[bucket]
|
|
ops[j] = op
|
|
}
|
|
msg := &benchmark.MsgLoadTest{
|
|
Caller: clientCtx.FromAddress,
|
|
Ops: ops,
|
|
}
|
|
txf = txf.WithSequence(accSeq)
|
|
tx, err := txf.BuildUnsignedTx(msg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = clienttx.Sign(clientCtx.CmdContext, txf, clientCtx.From, tx, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
txBytes, err := clientCtx.TxConfig.TxEncoder()(tx.GetTx())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res, err := clientCtx.BroadcastTxAsync(txBytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res.Code != 0 {
|
|
if verbose {
|
|
err = clientCtx.PrintProto(res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
errCount++
|
|
} else {
|
|
accSeq++
|
|
successCount++
|
|
}
|
|
if pause > 0 {
|
|
time.Sleep(time.Duration(pause) * time.Microsecond)
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
flags.AddTxFlagsToCmd(cmd)
|
|
cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "print the response")
|
|
cmd.Flags().Uint64Var(&numOps, "ops", 1, "number of operations per transaction")
|
|
cmd.Flags().Int64Var(&pause, "pause", 0, "pause between transactions in microseconds")
|
|
|
|
return cmd
|
|
}
|