github.com/jgbaldwinbrown/perf@v0.1.1/benchproc/example_test.go (about) 1 // Copyright 2021 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 5 package benchproc 6 7 import ( 8 "fmt" 9 "log" 10 "os" 11 12 "golang.org/x/perf/benchfmt" 13 "golang.org/x/perf/benchunit" 14 ) 15 16 // Example shows a complete benchmark processing pipeline that uses 17 // filtering, projection, accumulation, and sorting. 18 func Example() { 19 // Open the example benchmark data. 20 f, err := os.Open("testdata/suffixarray.bench") 21 if err != nil { 22 log.Fatal(err) 23 } 24 defer f.Close() 25 26 // Create a filter that extracts just "BenchmarkNew" on the value 27 // "go" of the name key "text". Typically, the filter expression 28 // would come from a command-line flag. 29 filter, err := NewFilter(".name:New /text:go") 30 if err != nil { 31 log.Fatal(err) 32 } 33 // Create a projection. This projection extracts "/bits=" and 34 // "/size=" from the benchmark name. It sorts bits in the 35 // default, first-observation order and size numerically. 36 // Typically, the projection expression would come from a 37 // command-line flag. 38 var pp ProjectionParser 39 projection, err := pp.Parse("/bits,/size@num", filter) 40 if err != nil { 41 log.Fatal(err) 42 } 43 // Create a projection that captures all configuration not 44 // captured by the above projection. We'll use this to check 45 // if there's unexpected variation in other configuration 46 // fields and report it. 47 residue := pp.Residue() 48 49 // We'll accumulate benchmark results by their projection. 50 // Projections create Keys, which are == if the projected 51 // values are ==, so they can be used as map keys. 52 bySize := make(map[Key][]float64) 53 var keys []Key 54 var residues []Key 55 56 // Read the benchmark results. 57 r := benchfmt.NewReader(f, "example") 58 for r.Scan() { 59 var res *benchfmt.Result 60 switch rec := r.Result(); rec := rec.(type) { 61 case *benchfmt.Result: 62 res = rec 63 case *benchfmt.SyntaxError: 64 // Report a non-fatal parse error. 65 log.Print(err) 66 continue 67 default: 68 // Unknown record type. Ignore. 69 continue 70 } 71 72 // Step 1: If necessary, transform the Result, for example to 73 // add configuration keys that could be used in filters and 74 // projections. This example doesn't need any transformation. 75 76 // Step 2: Filter the result. 77 if match, err := filter.Apply(res); !match { 78 // Result was fully excluded by the filter. 79 if err != nil { 80 // Print the reason we rejected this result. 81 log.Print(err) 82 } 83 continue 84 } 85 86 // Step 3: Project the result. This produces a Key 87 // that captures the "size" and "bits" from the result. 88 key := projection.Project(res) 89 90 // Accumulate the results by configuration. 91 speed, ok := res.Value("sec/op") 92 if !ok { 93 continue 94 } 95 if _, ok := bySize[key]; !ok { 96 keys = append(keys, key) 97 } 98 bySize[key] = append(bySize[key], speed) 99 100 // Collect residue configurations. 101 resConfig := residue.Project(res) 102 residues = append(residues, resConfig) 103 } 104 // Check for I/O errors. 105 if err := r.Err(); err != nil { 106 log.Fatal(err) 107 } 108 109 // Step 4: Sort the collected configurations using the order 110 // specified by the projection. 111 SortKeys(keys) 112 113 // Print the results. 114 fmt.Printf("%-24s %s\n", "config", "sec/op") 115 for _, config := range keys { 116 fmt.Printf("%-24s %s\n", config, benchunit.Scale(mean(bySize[config]), benchunit.Decimal)) 117 } 118 119 // Check if there was variation in any other configuration 120 // fields that wasn't captured by the projection and warn the 121 // user that something may be unexpected. 122 nonsingular := NonSingularFields(residues) 123 if len(nonsingular) > 0 { 124 fmt.Printf("warning: results vary in %s\n", nonsingular) 125 } 126 127 // Output: 128 // config sec/op 129 // /bits:32 /size:100K 4.650m 130 // /bits:32 /size:500K 26.18m 131 // /bits:32 /size:1M 51.39m 132 // /bits:32 /size:5M 306.7m 133 // /bits:32 /size:10M 753.0m 134 // /bits:32 /size:50M 5.814 135 // /bits:64 /size:100K 5.081m 136 // /bits:64 /size:500K 26.43m 137 // /bits:64 /size:1M 55.60m 138 // /bits:64 /size:5M 366.6m 139 // /bits:64 /size:10M 821.2m 140 // /bits:64 /size:50M 6.390 141 }