diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 235fed6630..98351dddbc 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -74,37 +74,41 @@ func readGenesis(genesisPath string) *core.Genesis { return genesis } -type execStats struct { - time time.Duration // The execution time. - allocs int64 // The number of heap allocations during execution. - bytesAllocated int64 // The cumulative number of bytes allocated during execution. +type ExecStats struct { + Time time.Duration `json:"time"` // The execution Time. + Allocs int64 `json:"allocs"` // The number of heap allocations during execution. + BytesAllocated int64 `json:"bytesAllocated"` // The cumulative number of bytes allocated during execution. + GasUsed uint64 `json:"gasUsed"` // the amount of gas used during execution } -func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []byte, gasLeft uint64, stats execStats, err error) { +func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []byte, stats ExecStats, err error) { + var gasUsed uint64 if bench { result := testing.Benchmark(func(b *testing.B) { for i := 0; i < b.N; i++ { - output, gasLeft, err = execFunc() + output, gasUsed, err = execFunc() } }) - // Get the average execution time from the benchmarking result. // There are other useful stats here that could be reported. - stats.time = time.Duration(result.NsPerOp()) - stats.allocs = result.AllocsPerOp() - stats.bytesAllocated = result.AllocedBytesPerOp() + stats.Time = time.Duration(result.NsPerOp()) + stats.Allocs = result.AllocsPerOp() + stats.BytesAllocated = result.AllocedBytesPerOp() + stats.GasUsed = gasUsed } else { + g var memStatsBefore, memStatsAfter goruntime.MemStats goruntime.ReadMemStats(&memStatsBefore) startTime := time.Now() - output, gasLeft, err = execFunc() - stats.time = time.Since(startTime) + output, gasUsed, err = execFunc() + stats.Time = time.Since(startTime) goruntime.ReadMemStats(&memStatsAfter) - stats.allocs = int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs) - stats.bytesAllocated = int64(memStatsAfter.TotalAlloc - memStatsBefore.TotalAlloc) + stats.Allocs = int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs) + stats.BytesAllocated = int64(memStatsAfter.TotalAlloc - memStatsBefore.TotalAlloc) + stats.GasUsed = gasUsed } - return output, gasLeft, stats, err + return output, stats, err } func runCmd(ctx *cli.Context) error { @@ -264,12 +268,13 @@ func runCmd(ctx *cli.Context) error { statedb.SetCode(receiver, code) } execFunc = func() ([]byte, uint64, error) { - return runtime.Call(receiver, input, &runtimeConfig) + output, gasLeft, err := runtime.Call(receiver, input, &runtimeConfig) + return output, initialGas - gasLeft, err } } bench := ctx.Bool(BenchFlag.Name) - output, leftOverGas, stats, err := timedExec(bench, execFunc) + output, stats, err := timedExec(bench, execFunc) if ctx.Bool(DumpFlag.Name) { root, err := statedb.Commit(genesisConfig.Number, true) @@ -299,7 +304,7 @@ func runCmd(ctx *cli.Context) error { execution time: %v allocations: %d allocated bytes: %d -`, initialGas-leftOverGas, stats.time, stats.allocs, stats.bytesAllocated) +`, stats.GasUsed, stats.Time, stats.Allocs, stats.BytesAllocated) } if tracer == nil { fmt.Printf("%#x\n", output) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index f1868e5b05..76300c2e11 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -20,10 +20,6 @@ import ( "bufio" "encoding/json" "fmt" - "os" - "testing" - "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" @@ -32,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" + "os" ) var ( @@ -67,12 +64,13 @@ var stateTestCommand = &cli.Command{ // StatetestResult contains the execution status after running a state test, any // error that might have occurred and a dump of the final state if requested. type StatetestResult struct { - Name string `json:"name"` - Pass bool `json:"pass"` - Root *common.Hash `json:"stateRoot,omitempty"` - Fork string `json:"fork"` - Error string `json:"error,omitempty"` - State *state.Dump `json:"state,omitempty"` + Name string `json:"name"` + Pass bool `json:"pass"` + Root *common.Hash `json:"stateRoot,omitempty"` + Fork string `json:"fork"` + Error string `json:"error,omitempty"` + State *state.Dump `json:"state,omitempty"` + BenchStats *ExecStats `json:"benchStats,omitempty"` } func stateTestCmd(ctx *cli.Context) error { @@ -177,6 +175,13 @@ func runStateTest(ctx *cli.Context, fname string, cfg vm.Config, dump bool, benc result.Pass, result.Error = false, err.Error() } }) + if bench { + _, stats, _ := timedExec(true, func() ([]byte, uint64, error) { + _, _, gasUsed, _ := test.test.RunNoVerify(test.st, cfg, false, rawdb.HashScheme) + return nil, gasUsed, nil + }) + result.BenchStats = &stats + } results = append(results, *result) } out, _ := json.MarshalIndent(results, "", " ") @@ -187,23 +192,6 @@ func runStateTest(ctx *cli.Context, fname string, cfg vm.Config, dump bool, benc } else if len(matchingTests) != 1 { return fmt.Errorf("can only benchmark single state test case (more than one matching params)") } - var gasUsed uint64 - result := testing.Benchmark(func(b *testing.B) { - for i := 0; i < b.N; i++ { - test := matchingTests[0] - _, _, gasUsed, _ = test.test.RunNoVerify(test.st, cfg, false, rawdb.HashScheme) - } - }) - var stats execStats - // Get the average execution time from the benchmarking result. - // There are other useful stats here that could be reported. - stats.time = time.Duration(result.NsPerOp()) - stats.allocs = result.AllocsPerOp() - stats.bytesAllocated = result.AllocedBytesPerOp() - fmt.Fprintf(os.Stderr, `EVM gas used: %d -execution time: %v -allocations: %d -allocated bytes: %d -`, gasUsed, stats.time, stats.allocs, stats.bytesAllocated) + return nil }