Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Edit `my-config.json`:
| `--track-blocks` | false | Track block statistics |
| `--track-user-latency` | false | Track user latency metrics |
| `--prewarm` | false | Prewarm accounts before test |
| `--prewarm-tps` | 100 | Target transactions per second during prewarm (0 = unlimited) |
| `--prewarm-parallelism` | 100 | Maximum in-flight prewarm transactions |

## Examples

Expand Down Expand Up @@ -142,6 +144,8 @@ Available settings:
- `trackBlocks`: Track block statistics
- `trackUserLatency`: Track user latency metrics
- `prewarm`: Prewarm accounts before test
- `prewarmTPS`: Target transactions per second during prewarm (0 = unlimited)
- `prewarmParallelism`: Maximum number of concurrent prewarm transactions

## Available Scenarios

Expand Down
106 changes: 58 additions & 48 deletions config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,60 @@ import (

// Settings holds all CLI-configurable parameters
type Settings struct {
Workers int `json:"workers,omitempty"`
TPS float64 `json:"tps,omitempty"`
StatsInterval Duration `json:"statsInterval,omitempty"`
BufferSize int `json:"bufferSize,omitempty"`
DryRun bool `json:"dryRun,omitempty"`
Debug bool `json:"debug,omitempty"`
TrackReceipts bool `json:"trackReceipts,omitempty"`
TrackBlocks bool `json:"trackBlocks,omitempty"`
TrackUserLatency bool `json:"trackUserLatency,omitempty"`
Prewarm bool `json:"prewarm,omitempty"`
RampUp bool `json:"rampUp,omitempty"`
ReportPath string `json:"reportPath,omitempty"`
Workers int `json:"workers,omitempty"`
TPS float64 `json:"tps,omitempty"`
StatsInterval Duration `json:"statsInterval,omitempty"`
BufferSize int `json:"bufferSize,omitempty"`
DryRun bool `json:"dryRun,omitempty"`
Debug bool `json:"debug,omitempty"`
TrackReceipts bool `json:"trackReceipts,omitempty"`
TrackBlocks bool `json:"trackBlocks,omitempty"`
TrackUserLatency bool `json:"trackUserLatency,omitempty"`
Prewarm bool `json:"prewarm,omitempty"`
PrewarmTPS float64 `json:"prewarmTPS,omitempty"`
PrewarmParallelism int `json:"prewarmParallelism,omitempty"`
RampUp bool `json:"rampUp,omitempty"`
ReportPath string `json:"reportPath,omitempty"`
}

// DefaultSettings returns the default configuration values
func DefaultSettings() Settings {
return Settings{
Workers: 1,
TPS: 0.0,
StatsInterval: Duration(10 * time.Second),
BufferSize: 1000,
DryRun: false,
Debug: false,
TrackReceipts: false,
TrackBlocks: false,
TrackUserLatency: false,
Prewarm: false,
RampUp: false,
ReportPath: "",
Workers: 1,
TPS: 0.0,
StatsInterval: Duration(10 * time.Second),
BufferSize: 1000,
DryRun: false,
Debug: false,
TrackReceipts: false,
TrackBlocks: false,
TrackUserLatency: false,
Prewarm: false,
PrewarmTPS: 100.0,
PrewarmParallelism: 100,
RampUp: false,
ReportPath: "",
}
}

// InitializeViper sets up Viper with CLI flags and defaults
func InitializeViper(cmd *cobra.Command) error {
// Bind flags to viper with error checking
flagBindings := map[string]string{
"statsInterval": "stats-interval",
"bufferSize": "buffer-size",
"tps": "tps",
"dryRun": "dry-run",
"debug": "debug",
"trackReceipts": "track-receipts",
"trackBlocks": "track-blocks",
"prewarm": "prewarm",
"trackUserLatency": "track-user-latency",
"workers": "workers",
"rampUp": "ramp-up",
"reportPath": "report-path",
"statsInterval": "stats-interval",
"bufferSize": "buffer-size",
"tps": "tps",
"dryRun": "dry-run",
"debug": "debug",
"trackReceipts": "track-receipts",
"trackBlocks": "track-blocks",
"prewarm": "prewarm",
"prewarmTPS": "prewarm-tps",
"prewarmParallelism": "prewarm-parallelism",
"trackUserLatency": "track-user-latency",
"workers": "workers",
"rampUp": "ramp-up",
"reportPath": "report-path",
}

for viperKey, flagName := range flagBindings {
Expand All @@ -78,6 +84,8 @@ func InitializeViper(cmd *cobra.Command) error {
viper.SetDefault("trackReceipts", defaults.TrackReceipts)
viper.SetDefault("trackBlocks", defaults.TrackBlocks)
viper.SetDefault("prewarm", defaults.Prewarm)
viper.SetDefault("prewarmTPS", defaults.PrewarmTPS)
viper.SetDefault("prewarmParallelism", defaults.PrewarmParallelism)
viper.SetDefault("trackUserLatency", defaults.TrackUserLatency)
viper.SetDefault("workers", defaults.Workers)
viper.SetDefault("rampUp", defaults.RampUp)
Expand Down Expand Up @@ -108,17 +116,19 @@ func LoadSettings(settings *Settings) error {
// ResolveSettings gets the final resolved settings from Viper
func ResolveSettings() Settings {
return Settings{
Workers: viper.GetInt("workers"),
TPS: viper.GetFloat64("tps"),
StatsInterval: Duration(viper.GetDuration("statsInterval")),
BufferSize: viper.GetInt("bufferSize"),
DryRun: viper.GetBool("dryRun"),
Debug: viper.GetBool("debug"),
TrackReceipts: viper.GetBool("trackReceipts"),
TrackBlocks: viper.GetBool("trackBlocks"),
TrackUserLatency: viper.GetBool("trackUserLatency"),
Prewarm: viper.GetBool("prewarm"),
RampUp: viper.GetBool("rampUp"),
ReportPath: viper.GetString("reportPath"),
Workers: viper.GetInt("workers"),
TPS: viper.GetFloat64("tps"),
StatsInterval: Duration(viper.GetDuration("statsInterval")),
BufferSize: viper.GetInt("bufferSize"),
DryRun: viper.GetBool("dryRun"),
Debug: viper.GetBool("debug"),
TrackReceipts: viper.GetBool("trackReceipts"),
TrackBlocks: viper.GetBool("trackBlocks"),
TrackUserLatency: viper.GetBool("trackUserLatency"),
Prewarm: viper.GetBool("prewarm"),
PrewarmTPS: viper.GetFloat64("prewarmTPS"),
PrewarmParallelism: viper.GetInt("prewarmParallelism"),
RampUp: viper.GetBool("rampUp"),
ReportPath: viper.GetString("reportPath"),
}
}
28 changes: 16 additions & 12 deletions config/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ func TestArgumentPrecedence(t *testing.T) {
cmd.Flags().Bool("track-receipts", false, "Track receipts")
cmd.Flags().Bool("track-blocks", false, "Track blocks")
cmd.Flags().Bool("prewarm", false, "Prewarm")
cmd.Flags().Float64("prewarm-tps", 0, "Prewarm TPS")
cmd.Flags().Int("prewarm-parallelism", 0, "Prewarm parallelism")
cmd.Flags().Bool("track-user-latency", false, "Track user latency")
cmd.Flags().Int("buffer-size", 0, "Buffer size")
cmd.Flags().Bool("ramp-up", false, "Ramp up loadtest")
Expand Down Expand Up @@ -121,18 +123,20 @@ func TestDefaultSettings(t *testing.T) {
defaults := DefaultSettings()

expected := Settings{
Workers: 1,
TPS: 0.0,
StatsInterval: Duration(10 * time.Second),
BufferSize: 1000,
DryRun: false,
Debug: false,
TrackReceipts: false,
TrackBlocks: false,
TrackUserLatency: false,
Prewarm: false,
RampUp: false,
ReportPath: "",
Workers: 1,
TPS: 0.0,
StatsInterval: Duration(10 * time.Second),
BufferSize: 1000,
DryRun: false,
Debug: false,
TrackReceipts: false,
TrackBlocks: false,
TrackUserLatency: false,
Prewarm: false,
PrewarmTPS: 100.0,
PrewarmParallelism: 100,
RampUp: false,
ReportPath: "",
}

if defaults != expected {
Expand Down
10 changes: 9 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func init() {
rootCmd.Flags().Bool("track-receipts", false, "Track receipts")
rootCmd.Flags().Bool("track-blocks", false, "Track blocks")
rootCmd.Flags().Bool("prewarm", false, "Prewarm accounts with self-transactions")
rootCmd.Flags().Float64("prewarm-tps", 100, "Target transactions per second during prewarm (0 = unlimited)")
rootCmd.Flags().Int("prewarm-parallelism", 100, "Maximum number of in-flight prewarm transactions (0 = default)")
rootCmd.Flags().Bool("track-user-latency", false, "Track user latency")
rootCmd.Flags().IntP("workers", "w", 0, "Number of workers")
rootCmd.Flags().IntP("nodes", "n", 0, "Number of nodes/endpoints to use (0 = use all)")
Expand Down Expand Up @@ -234,9 +236,15 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
if settings.Prewarm {
log.Printf("🔥 Creating prewarm generator...")
prewarmGen := generator.NewPrewarmGenerator(cfg, gen)
dispatcher.SetPrewarmGenerator(prewarmGen)
dispatcher.SetPrewarmGenerator(prewarmGen, cfg.Endpoints[0], settings.PrewarmTPS, settings.PrewarmParallelism)
log.Printf("✅ Prewarm generator ready")
log.Printf("📝 Prewarm mode: Accounts will be prewarmed")
if settings.PrewarmParallelism > 1 {
log.Printf("🔥 Prewarm parallelism: %d in-flight transactions", settings.PrewarmParallelism)
}
if settings.PrewarmTPS > 0 {
log.Printf("🔥 Prewarm TPS limit: %.2f", settings.PrewarmTPS)
}
}

// Start the sender (starts all workers)
Expand Down
Loading
Loading