+++ /dev/null
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "flag"
- "fmt"
- "os"
- "sort"
- "strconv"
- "text/tabwriter"
-
- "golang.org/x/tools/benchmark/parse"
-)
-
-var (
- changedOnly = flag.Bool("changed", false, "show only benchmarks that have changed")
- magSort = flag.Bool("mag", false, "sort benchmarks by magnitude of change")
- best = flag.Bool("best", false, "compare best times from old and new")
-)
-
-const usageFooter = `
-Each input file should be from:
- go test -run=NONE -bench=. > [old,new].txt
-
-Benchcmp compares old and new for each benchmark.
-
-If -test.benchmem=true is added to the "go test" command
-benchcmp will also compare memory allocations.
-`
-
-func main() {
- fmt.Fprintf(os.Stderr, "benchcmp is deprecated in favor of benchstat: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat\n")
- flag.Usage = func() {
- fmt.Fprintf(os.Stderr, "usage: %s old.txt new.txt\n\n", os.Args[0])
- flag.PrintDefaults()
- fmt.Fprint(os.Stderr, usageFooter)
- os.Exit(2)
- }
- flag.Parse()
- if flag.NArg() != 2 {
- flag.Usage()
- }
-
- before := parseFile(flag.Arg(0))
- after := parseFile(flag.Arg(1))
-
- cmps, warnings := Correlate(before, after)
-
- for _, warn := range warnings {
- fmt.Fprintln(os.Stderr, warn)
- }
-
- if len(cmps) == 0 {
- fatal("benchcmp: no repeated benchmarks")
- }
-
- w := new(tabwriter.Writer)
- w.Init(os.Stdout, 0, 0, 5, ' ', 0)
- defer w.Flush()
-
- var header bool // Has the header has been displayed yet for a given block?
-
- if *magSort {
- sort.Sort(ByDeltaNsPerOp(cmps))
- } else {
- sort.Sort(ByParseOrder(cmps))
- }
- for _, cmp := range cmps {
- if !cmp.Measured(parse.NsPerOp) {
- continue
- }
- if delta := cmp.DeltaNsPerOp(); !*changedOnly || delta.Changed() {
- if !header {
- fmt.Fprint(w, "benchmark\told ns/op\tnew ns/op\tdelta\n")
- header = true
- }
- fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", cmp.Name(), formatNs(cmp.Before.NsPerOp), formatNs(cmp.After.NsPerOp), delta.Percent())
- }
- }
-
- header = false
- if *magSort {
- sort.Sort(ByDeltaMBPerS(cmps))
- }
- for _, cmp := range cmps {
- if !cmp.Measured(parse.MBPerS) {
- continue
- }
- if delta := cmp.DeltaMBPerS(); !*changedOnly || delta.Changed() {
- if !header {
- fmt.Fprint(w, "\nbenchmark\told MB/s\tnew MB/s\tspeedup\n")
- header = true
- }
- fmt.Fprintf(w, "%s\t%.2f\t%.2f\t%s\n", cmp.Name(), cmp.Before.MBPerS, cmp.After.MBPerS, delta.Multiple())
- }
- }
-
- header = false
- if *magSort {
- sort.Sort(ByDeltaAllocsPerOp(cmps))
- }
- for _, cmp := range cmps {
- if !cmp.Measured(parse.AllocsPerOp) {
- continue
- }
- if delta := cmp.DeltaAllocsPerOp(); !*changedOnly || delta.Changed() {
- if !header {
- fmt.Fprint(w, "\nbenchmark\told allocs\tnew allocs\tdelta\n")
- header = true
- }
- fmt.Fprintf(w, "%s\t%d\t%d\t%s\n", cmp.Name(), cmp.Before.AllocsPerOp, cmp.After.AllocsPerOp, delta.Percent())
- }
- }
-
- header = false
- if *magSort {
- sort.Sort(ByDeltaAllocedBytesPerOp(cmps))
- }
- for _, cmp := range cmps {
- if !cmp.Measured(parse.AllocedBytesPerOp) {
- continue
- }
- if delta := cmp.DeltaAllocedBytesPerOp(); !*changedOnly || delta.Changed() {
- if !header {
- fmt.Fprint(w, "\nbenchmark\told bytes\tnew bytes\tdelta\n")
- header = true
- }
- fmt.Fprintf(w, "%s\t%d\t%d\t%s\n", cmp.Name(), cmp.Before.AllocedBytesPerOp, cmp.After.AllocedBytesPerOp, cmp.DeltaAllocedBytesPerOp().Percent())
- }
- }
-}
-
-func fatal(msg interface{}) {
- fmt.Fprintln(os.Stderr, msg)
- os.Exit(1)
-}
-
-func parseFile(path string) parse.Set {
- f, err := os.Open(path)
- if err != nil {
- fatal(err)
- }
- defer f.Close()
- bb, err := parse.ParseSet(f)
- if err != nil {
- fatal(err)
- }
- if *best {
- selectBest(bb)
- }
- return bb
-}
-
-func selectBest(bs parse.Set) {
- for name, bb := range bs {
- if len(bb) < 2 {
- continue
- }
- ord := bb[0].Ord
- best := bb[0]
- for _, b := range bb {
- if b.NsPerOp < best.NsPerOp {
- b.Ord = ord
- best = b
- }
- }
- bs[name] = []*parse.Benchmark{best}
- }
-}
-
-// formatNs formats ns measurements to expose a useful amount of
-// precision. It mirrors the ns precision logic of testing.B.
-func formatNs(ns float64) string {
- prec := 0
- switch {
- case ns < 10:
- prec = 2
- case ns < 100:
- prec = 1
- }
- return strconv.FormatFloat(ns, 'f', prec, 64)
-}