diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index c6fac5396e..f338af822e 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -24,6 +24,7 @@ import ( "os" "regexp" "slices" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -44,6 +45,7 @@ var blockTestCommand = &cli.Command{ RunFlag, WitnessCrossCheckFlag, FuzzFlag, + WorkersFlag, }, traceFlags), } @@ -52,16 +54,14 @@ func blockTestCmd(ctx *cli.Context) error { // If path is provided, run the tests at that path. if len(path) != 0 { - var ( - collected = collectFiles(path) - results []testResult - ) - for _, fname := range collected { - r, err := runBlockTest(ctx, fname) - if err != nil { - return err - } - results = append(results, r...) + collected := collectFiles(path) + workers := ctx.Int(WorkersFlag.Name) + if workers <= 0 { + workers = 1 + } + results, err := runBlockTestsParallel(ctx, collected, workers) + if err != nil { + return err } report(ctx, results) return nil @@ -85,6 +85,63 @@ func blockTestCmd(ctx *cli.Context) error { return nil } +func runBlockTestsParallel(ctx *cli.Context, files []string, workers int) ([]testResult, error) { + if workers == 1 { + var results []testResult + for _, fname := range files { + r, err := runBlockTest(ctx, fname) + if err != nil { + return nil, err + } + results = append(results, r...) + } + return results, nil + } + var ( + wg sync.WaitGroup + fileCh = make(chan struct { + index int + fname string + }, len(files)) + resultCh = make(chan fileResult, len(files)) + ) + for i, fname := range files { + fileCh <- struct { + index int + fname string + }{i, fname} + } + close(fileCh) + + for w := 0; w < workers; w++ { + wg.Add(1) + go func() { + defer wg.Done() + for item := range fileCh { + r, err := runBlockTest(ctx, item.fname) + resultCh <- fileResult{index: item.index, results: r, err: err} + } + }() + } + go func() { + wg.Wait() + close(resultCh) + }() + + ordered := make([]fileResult, len(files)) + for fr := range resultCh { + if fr.err != nil { + return nil, fr.err + } + ordered[fr.index] = fr + } + var results []testResult + for _, fr := range ordered { + results = append(results, fr.results...) + } + return results, nil +} + func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) { src, err := os.ReadFile(fname) if err != nil { @@ -92,7 +149,7 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) { } var tests map[string]*tests.BlockTest if err = json.Unmarshal(src, &tests); err != nil { - return nil, err + return nil, nil // Skip non-fixture JSON files } re, err := regexp.Compile(ctx.String(RunFlag.Name)) if err != nil {