benchmark_test.go 4.4 KB

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