cmd/evm: Rework execution stats (#20792)

- Dump stats also for --bench flag.
- From memory stats only show number and size of allocations. This is what `test -bench` shows. I doubt others like number of GC runs are any useful, but can be added if requested.
- Now the mem stats are for single execution in case of --bench.
This commit is contained in:
Paweł Bylica 2020-04-01 12:40:07 +02:00 committed by GitHub
parent a5a9feab21
commit d56dc038d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -70,14 +70,13 @@ func readGenesis(genesisPath string) *core.Genesis {
return genesis return genesis
} }
func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, uint64, time.Duration, error) { type execStats struct {
var ( time time.Duration // The execution time.
output []byte allocs int64 // The number of heap allocations during execution.
gasLeft uint64 bytesAllocated int64 // The cumulative number of bytes allocated during execution.
execTime time.Duration }
err error
)
func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []byte, gasLeft uint64, stats execStats, err error) {
if bench { if bench {
result := testing.Benchmark(func(b *testing.B) { result := testing.Benchmark(func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -87,14 +86,21 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, uin
// Get the average execution time from the benchmarking result. // Get the average execution time from the benchmarking result.
// There are other useful stats here that could be reported. // There are other useful stats here that could be reported.
execTime = time.Duration(result.NsPerOp()) stats.time = time.Duration(result.NsPerOp())
stats.allocs = result.AllocsPerOp()
stats.bytesAllocated = result.AllocedBytesPerOp()
} else { } else {
var memStatsBefore, memStatsAfter goruntime.MemStats
goruntime.ReadMemStats(&memStatsBefore)
startTime := time.Now() startTime := time.Now()
output, gasLeft, err = execFunc() output, gasLeft, err = execFunc()
execTime = time.Since(startTime) stats.time = time.Since(startTime)
goruntime.ReadMemStats(&memStatsAfter)
stats.allocs = int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs)
stats.bytesAllocated = int64(memStatsAfter.TotalAlloc - memStatsBefore.TotalAlloc)
} }
return output, gasLeft, execTime, err return output, gasLeft, stats, err
} }
func runCmd(ctx *cli.Context) error { func runCmd(ctx *cli.Context) error {
@ -256,7 +262,8 @@ func runCmd(ctx *cli.Context) error {
} }
} }
output, leftOverGas, execTime, err := timedExec(ctx.GlobalBool(BenchFlag.Name), execFunc) bench := ctx.GlobalBool(BenchFlag.Name)
output, leftOverGas, stats, err := timedExec(bench, execFunc)
if ctx.GlobalBool(DumpFlag.Name) { if ctx.GlobalBool(DumpFlag.Name) {
statedb.Commit(true) statedb.Commit(true)
@ -286,17 +293,12 @@ func runCmd(ctx *cli.Context) error {
vm.WriteLogs(os.Stderr, statedb.Logs()) vm.WriteLogs(os.Stderr, statedb.Logs())
} }
if ctx.GlobalBool(StatDumpFlag.Name) { if bench || ctx.GlobalBool(StatDumpFlag.Name) {
var mem goruntime.MemStats fmt.Fprintf(os.Stderr, `EVM gas used: %d
goruntime.ReadMemStats(&mem) execution time: %v
fmt.Fprintf(os.Stderr, `evm execution time: %v
heap objects: %d
allocations: %d allocations: %d
total allocations: %d allocated bytes: %d
GC calls: %d `, initialGas-leftOverGas, stats.time, stats.allocs, stats.bytesAllocated)
Gas used: %d
`, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas)
} }
if tracer == nil { if tracer == nil {
fmt.Printf("0x%x\n", output) fmt.Printf("0x%x\n", output)