...

Source file src/testing/benchmark_test.go

Documentation: testing

		 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  	})
	 180  }
	 181  

View as plain text