benchmark.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright (c) 2012 The Go Authors. All rights reserved.
  2. //
  3. // Redistribution and use in source and binary forms, with or without
  4. // modification, are permitted provided that the following conditions are
  5. // met:
  6. //
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above
  10. // copyright notice, this list of conditions and the following disclaimer
  11. // in the documentation and/or other materials provided with the
  12. // distribution.
  13. // * Neither the name of Google Inc. nor the names of its
  14. // contributors may be used to endorse or promote products derived from
  15. // this software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. package check
  29. import (
  30. "fmt"
  31. "runtime"
  32. "time"
  33. )
  34. var memStats runtime.MemStats
  35. // testingB is a type passed to Benchmark functions to manage benchmark
  36. // timing and to specify the number of iterations to run.
  37. type timer struct {
  38. start time.Time // Time test or benchmark started
  39. duration time.Duration
  40. N int
  41. bytes int64
  42. timerOn bool
  43. benchTime time.Duration
  44. // The initial states of memStats.Mallocs and memStats.TotalAlloc.
  45. startAllocs uint64
  46. startBytes uint64
  47. // The net total of this test after being run.
  48. netAllocs uint64
  49. netBytes uint64
  50. }
  51. // StartTimer starts timing a test. This function is called automatically
  52. // before a benchmark starts, but it can also used to resume timing after
  53. // a call to StopTimer.
  54. func (c *C) StartTimer() {
  55. if !c.timerOn {
  56. c.start = time.Now()
  57. c.timerOn = true
  58. runtime.ReadMemStats(&memStats)
  59. c.startAllocs = memStats.Mallocs
  60. c.startBytes = memStats.TotalAlloc
  61. }
  62. }
  63. // StopTimer stops timing a test. This can be used to pause the timer
  64. // while performing complex initialization that you don't
  65. // want to measure.
  66. func (c *C) StopTimer() {
  67. if c.timerOn {
  68. c.duration += time.Now().Sub(c.start)
  69. c.timerOn = false
  70. runtime.ReadMemStats(&memStats)
  71. c.netAllocs += memStats.Mallocs - c.startAllocs
  72. c.netBytes += memStats.TotalAlloc - c.startBytes
  73. }
  74. }
  75. // ResetTimer sets the elapsed benchmark time to zero.
  76. // It does not affect whether the timer is running.
  77. func (c *C) ResetTimer() {
  78. if c.timerOn {
  79. c.start = time.Now()
  80. runtime.ReadMemStats(&memStats)
  81. c.startAllocs = memStats.Mallocs
  82. c.startBytes = memStats.TotalAlloc
  83. }
  84. c.duration = 0
  85. c.netAllocs = 0
  86. c.netBytes = 0
  87. }
  88. // SetBytes informs the number of bytes that the benchmark processes
  89. // on each iteration. If this is called in a benchmark it will also
  90. // report MB/s.
  91. func (c *C) SetBytes(n int64) {
  92. c.bytes = n
  93. }
  94. func (c *C) nsPerOp() int64 {
  95. if c.N <= 0 {
  96. return 0
  97. }
  98. return c.duration.Nanoseconds() / int64(c.N)
  99. }
  100. func (c *C) mbPerSec() float64 {
  101. if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 {
  102. return 0
  103. }
  104. return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds()
  105. }
  106. func (c *C) timerString() string {
  107. if c.N <= 0 {
  108. return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9)
  109. }
  110. mbs := c.mbPerSec()
  111. mb := ""
  112. if mbs != 0 {
  113. mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
  114. }
  115. nsop := c.nsPerOp()
  116. ns := fmt.Sprintf("%10d ns/op", nsop)
  117. if c.N > 0 && nsop < 100 {
  118. // The format specifiers here make sure that
  119. // the ones digits line up for all three possible formats.
  120. if nsop < 10 {
  121. ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
  122. } else {
  123. ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
  124. }
  125. }
  126. memStats := ""
  127. if c.benchMem {
  128. allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N))
  129. allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N))
  130. memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs)
  131. }
  132. return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats)
  133. }
  134. func min(x, y int) int {
  135. if x > y {
  136. return y
  137. }
  138. return x
  139. }
  140. func max(x, y int) int {
  141. if x < y {
  142. return y
  143. }
  144. return x
  145. }
  146. // roundDown10 rounds a number down to the nearest power of 10.
  147. func roundDown10(n int) int {
  148. var tens = 0
  149. // tens = floor(log_10(n))
  150. for n > 10 {
  151. n = n / 10
  152. tens++
  153. }
  154. // result = 10^tens
  155. result := 1
  156. for i := 0; i < tens; i++ {
  157. result *= 10
  158. }
  159. return result
  160. }
  161. // roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
  162. func roundUp(n int) int {
  163. base := roundDown10(n)
  164. if n < (2 * base) {
  165. return 2 * base
  166. }
  167. if n < (5 * base) {
  168. return 5 * base
  169. }
  170. return 10 * base
  171. }