GoPLS Viewer

Home|gopls/cmd/benchcmp/benchcmp.go
1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7import (
8    "flag"
9    "fmt"
10    "os"
11    "sort"
12    "strconv"
13    "text/tabwriter"
14
15    "golang.org/x/tools/benchmark/parse"
16)
17
18var (
19    changedOnly = flag.Bool("changed"false"show only benchmarks that have changed")
20    magSort     = flag.Bool("mag"false"sort benchmarks by magnitude of change")
21    best        = flag.Bool("best"false"compare best times from old and new")
22)
23
24const usageFooter = `
25Each input file should be from:
26    go test -run=NONE -bench=. > [old,new].txt
27
28Benchcmp compares old and new for each benchmark.
29
30If -test.benchmem=true is added to the "go test" command
31benchcmp will also compare memory allocations.
32`
33
34func main() {
35    fmt.Fprintf(os.Stderr"benchcmp is deprecated in favor of benchstat: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat\n")
36    flag.Usage = func() {
37        fmt.Fprintf(os.Stderr"usage: %s old.txt new.txt\n\n"os.Args[0])
38        flag.PrintDefaults()
39        fmt.Fprint(os.StderrusageFooter)
40        os.Exit(2)
41    }
42    flag.Parse()
43    if flag.NArg() != 2 {
44        flag.Usage()
45    }
46
47    before := parseFile(flag.Arg(0))
48    after := parseFile(flag.Arg(1))
49
50    cmpswarnings := Correlate(beforeafter)
51
52    for _warn := range warnings {
53        fmt.Fprintln(os.Stderrwarn)
54    }
55
56    if len(cmps) == 0 {
57        fatal("benchcmp: no repeated benchmarks")
58    }
59
60    w := new(tabwriter.Writer)
61    w.Init(os.Stdout005' '0)
62    defer w.Flush()
63
64    var header bool // Has the header has been displayed yet for a given block?
65
66    if *magSort {
67        sort.Sort(ByDeltaNsPerOp(cmps))
68    } else {
69        sort.Sort(ByParseOrder(cmps))
70    }
71    for _cmp := range cmps {
72        if !cmp.Measured(parse.NsPerOp) {
73            continue
74        }
75        if delta := cmp.DeltaNsPerOp(); !*changedOnly || delta.Changed() {
76            if !header {
77                fmt.Fprint(w"benchmark\told ns/op\tnew ns/op\tdelta\n")
78                header = true
79            }
80            fmt.Fprintf(w"%s\t%s\t%s\t%s\n"cmp.Name(), formatNs(cmp.Before.NsPerOp), formatNs(cmp.After.NsPerOp), delta.Percent())
81        }
82    }
83
84    header = false
85    if *magSort {
86        sort.Sort(ByDeltaMBPerS(cmps))
87    }
88    for _cmp := range cmps {
89        if !cmp.Measured(parse.MBPerS) {
90            continue
91        }
92        if delta := cmp.DeltaMBPerS(); !*changedOnly || delta.Changed() {
93            if !header {
94                fmt.Fprint(w"\nbenchmark\told MB/s\tnew MB/s\tspeedup\n")
95                header = true
96            }
97            fmt.Fprintf(w"%s\t%.2f\t%.2f\t%s\n"cmp.Name(), cmp.Before.MBPerScmp.After.MBPerSdelta.Multiple())
98        }
99    }
100
101    header = false
102    if *magSort {
103        sort.Sort(ByDeltaAllocsPerOp(cmps))
104    }
105    for _cmp := range cmps {
106        if !cmp.Measured(parse.AllocsPerOp) {
107            continue
108        }
109        if delta := cmp.DeltaAllocsPerOp(); !*changedOnly || delta.Changed() {
110            if !header {
111                fmt.Fprint(w"\nbenchmark\told allocs\tnew allocs\tdelta\n")
112                header = true
113            }
114            fmt.Fprintf(w"%s\t%d\t%d\t%s\n"cmp.Name(), cmp.Before.AllocsPerOpcmp.After.AllocsPerOpdelta.Percent())
115        }
116    }
117
118    header = false
119    if *magSort {
120        sort.Sort(ByDeltaAllocedBytesPerOp(cmps))
121    }
122    for _cmp := range cmps {
123        if !cmp.Measured(parse.AllocedBytesPerOp) {
124            continue
125        }
126        if delta := cmp.DeltaAllocedBytesPerOp(); !*changedOnly || delta.Changed() {
127            if !header {
128                fmt.Fprint(w"\nbenchmark\told bytes\tnew bytes\tdelta\n")
129                header = true
130            }
131            fmt.Fprintf(w"%s\t%d\t%d\t%s\n"cmp.Name(), cmp.Before.AllocedBytesPerOpcmp.After.AllocedBytesPerOpcmp.DeltaAllocedBytesPerOp().Percent())
132        }
133    }
134}
135
136func fatal(msg interface{}) {
137    fmt.Fprintln(os.Stderrmsg)
138    os.Exit(1)
139}
140
141func parseFile(path stringparse.Set {
142    ferr := os.Open(path)
143    if err != nil {
144        fatal(err)
145    }
146    defer f.Close()
147    bberr := parse.ParseSet(f)
148    if err != nil {
149        fatal(err)
150    }
151    if *best {
152        selectBest(bb)
153    }
154    return bb
155}
156
157func selectBest(bs parse.Set) {
158    for namebb := range bs {
159        if len(bb) < 2 {
160            continue
161        }
162        ord := bb[0].Ord
163        best := bb[0]
164        for _b := range bb {
165            if b.NsPerOp < best.NsPerOp {
166                b.Ord = ord
167                best = b
168            }
169        }
170        bs[name] = []*parse.Benchmark{best}
171    }
172}
173
174// formatNs formats ns measurements to expose a useful amount of
175// precision. It mirrors the ns precision logic of testing.B.
176func formatNs(ns float64string {
177    prec := 0
178    switch {
179    case ns < 10:
180        prec = 2
181    case ns < 100:
182        prec = 1
183    }
184    return strconv.FormatFloat(ns'f'prec64)
185}
186
MembersX
parseFile.f
selectBest.RangeStmt_3780.BlockStmt.RangeStmt_3879.b
formatNs
sort
main.RangeStmt_1274.warn
parseFile.bb
main.cmps
main.RangeStmt_2117.BlockStmt.delta
main.RangeStmt_3018.cmp
fatal
fatal.msg
parseFile
main.RangeStmt_2117.cmp
main.RangeStmt_2556.BlockStmt.delta
main.RangeStmt_1666.BlockStmt.delta
selectBest.bs
selectBest.RangeStmt_3780.bb
selectBest.RangeStmt_3780.BlockStmt.ord
main.after
main.w
main.before
main.RangeStmt_3018.BlockStmt.delta
formatNs.prec
flag
os
usageFooter
main.warnings
main.RangeStmt_2556.cmp
parseFile.path
tabwriter
parse
parseFile.err
selectBest.RangeStmt_3780.name
strconv
main.header
main.RangeStmt_1666.cmp
selectBest
formatNs.ns
fmt
main
Members
X