github.com/AndrienkoAleksandr/go@v0.0.19/src/testing/benchmark_test.go (about) 1 // Copyright 2013 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 testing_test 6 7 import ( 8 "bytes" 9 "runtime" 10 "sort" 11 "strings" 12 "sync/atomic" 13 "testing" 14 "text/template" 15 "time" 16 ) 17 18 var prettyPrintTests = []struct { 19 v float64 20 expected string 21 }{ 22 {0, " 0 x"}, 23 {1234.1, " 1234 x"}, 24 {-1234.1, " -1234 x"}, 25 {999.950001, " 1000 x"}, 26 {999.949999, " 999.9 x"}, 27 {99.9950001, " 100.0 x"}, 28 {99.9949999, " 99.99 x"}, 29 {-99.9949999, " -99.99 x"}, 30 {0.000999950001, " 0.001000 x"}, 31 {0.000999949999, " 0.0009999 x"}, // smallest case 32 {0.0000999949999, " 0.0001000 x"}, 33 } 34 35 func TestPrettyPrint(t *testing.T) { 36 for _, tt := range prettyPrintTests { 37 buf := new(strings.Builder) 38 testing.PrettyPrint(buf, tt.v, "x") 39 if tt.expected != buf.String() { 40 t.Errorf("prettyPrint(%v): expected %q, actual %q", tt.v, tt.expected, buf.String()) 41 } 42 } 43 } 44 45 func TestResultString(t *testing.T) { 46 // Test fractional ns/op handling 47 r := testing.BenchmarkResult{ 48 N: 100, 49 T: 240 * time.Nanosecond, 50 } 51 if r.NsPerOp() != 2 { 52 t.Errorf("NsPerOp: expected 2, actual %v", r.NsPerOp()) 53 } 54 if want, got := " 100\t 2.400 ns/op", r.String(); want != got { 55 t.Errorf("String: expected %q, actual %q", want, got) 56 } 57 58 // Test sub-1 ns/op (issue #31005) 59 r.T = 40 * time.Nanosecond 60 if want, got := " 100\t 0.4000 ns/op", r.String(); want != got { 61 t.Errorf("String: expected %q, actual %q", want, got) 62 } 63 64 // Test 0 ns/op 65 r.T = 0 66 if want, got := " 100", r.String(); want != got { 67 t.Errorf("String: expected %q, actual %q", want, got) 68 } 69 } 70 71 func TestRunParallel(t *testing.T) { 72 if testing.Short() { 73 t.Skip("skipping in short mode") 74 } 75 testing.Benchmark(func(b *testing.B) { 76 procs := uint32(0) 77 iters := uint64(0) 78 b.SetParallelism(3) 79 b.RunParallel(func(pb *testing.PB) { 80 atomic.AddUint32(&procs, 1) 81 for pb.Next() { 82 atomic.AddUint64(&iters, 1) 83 } 84 }) 85 if want := uint32(3 * runtime.GOMAXPROCS(0)); procs != want { 86 t.Errorf("got %v procs, want %v", procs, want) 87 } 88 if iters != uint64(b.N) { 89 t.Errorf("got %v iters, want %v", iters, b.N) 90 } 91 }) 92 } 93 94 func TestRunParallelFail(t *testing.T) { 95 testing.Benchmark(func(b *testing.B) { 96 b.RunParallel(func(pb *testing.PB) { 97 // The function must be able to log/abort 98 // w/o crashing/deadlocking the whole benchmark. 99 b.Log("log") 100 b.Error("error") 101 }) 102 }) 103 } 104 105 func TestRunParallelFatal(t *testing.T) { 106 testing.Benchmark(func(b *testing.B) { 107 b.RunParallel(func(pb *testing.PB) { 108 for pb.Next() { 109 if b.N > 1 { 110 b.Fatal("error") 111 } 112 } 113 }) 114 }) 115 } 116 117 func TestRunParallelSkipNow(t *testing.T) { 118 testing.Benchmark(func(b *testing.B) { 119 b.RunParallel(func(pb *testing.PB) { 120 for pb.Next() { 121 if b.N > 1 { 122 b.SkipNow() 123 } 124 } 125 }) 126 }) 127 } 128 129 func ExampleB_RunParallel() { 130 // Parallel benchmark for text/template.Template.Execute on a single object. 131 testing.Benchmark(func(b *testing.B) { 132 templ := template.Must(template.New("test").Parse("Hello, {{.}}!")) 133 // RunParallel will create GOMAXPROCS goroutines 134 // and distribute work among them. 135 b.RunParallel(func(pb *testing.PB) { 136 // Each goroutine has its own bytes.Buffer. 137 var buf bytes.Buffer 138 for pb.Next() { 139 // The loop body is executed b.N times total across all goroutines. 140 buf.Reset() 141 templ.Execute(&buf, "World") 142 } 143 }) 144 }) 145 } 146 147 func TestReportMetric(t *testing.T) { 148 res := testing.Benchmark(func(b *testing.B) { 149 b.ReportMetric(12345, "ns/op") 150 b.ReportMetric(0.2, "frobs/op") 151 }) 152 // Test built-in overriding. 153 if res.NsPerOp() != 12345 { 154 t.Errorf("NsPerOp: expected %v, actual %v", 12345, res.NsPerOp()) 155 } 156 // Test stringing. 157 res.N = 1 // Make the output stable 158 want := " 1\t 12345 ns/op\t 0.2000 frobs/op" 159 if want != res.String() { 160 t.Errorf("expected %q, actual %q", want, res.String()) 161 } 162 } 163 164 func ExampleB_ReportMetric() { 165 // This reports a custom benchmark metric relevant to a 166 // specific algorithm (in this case, sorting). 167 testing.Benchmark(func(b *testing.B) { 168 var compares int64 169 for i := 0; i < b.N; i++ { 170 s := []int{5, 4, 3, 2, 1} 171 sort.Slice(s, func(i, j int) bool { 172 compares++ 173 return s[i] < s[j] 174 }) 175 } 176 // This metric is per-operation, so divide by b.N and 177 // report it as a "/op" unit. 178 b.ReportMetric(float64(compares)/float64(b.N), "compares/op") 179 // This metric is per-time, so divide by b.Elapsed and 180 // report it as a "/ns" unit. 181 b.ReportMetric(float64(compares)/float64(b.Elapsed().Nanoseconds()), "compares/ns") 182 }) 183 } 184 185 func ExampleB_ReportMetric_parallel() { 186 // This reports a custom benchmark metric relevant to a 187 // specific algorithm (in this case, sorting) in parallel. 188 testing.Benchmark(func(b *testing.B) { 189 var compares atomic.Int64 190 b.RunParallel(func(pb *testing.PB) { 191 for pb.Next() { 192 s := []int{5, 4, 3, 2, 1} 193 sort.Slice(s, func(i, j int) bool { 194 // Because RunParallel runs the function many 195 // times in parallel, we must increment the 196 // counter atomically to avoid racing writes. 197 compares.Add(1) 198 return s[i] < s[j] 199 }) 200 } 201 }) 202 203 // NOTE: Report each metric once, after all of the parallel 204 // calls have completed. 205 206 // This metric is per-operation, so divide by b.N and 207 // report it as a "/op" unit. 208 b.ReportMetric(float64(compares.Load())/float64(b.N), "compares/op") 209 // This metric is per-time, so divide by b.Elapsed and 210 // report it as a "/ns" unit. 211 b.ReportMetric(float64(compares.Load())/float64(b.Elapsed().Nanoseconds()), "compares/ns") 212 }) 213 }