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 29package check 30 31import ( 32 "fmt" 33 "runtime" 34 "time" 35) 36 37var memStats runtime.MemStats 38 39// testingB is a type passed to Benchmark functions to manage benchmark 40// timing and to specify the number of iterations to run. 41type timer struct { 42 start time.Time // Time test or benchmark started 43 duration time.Duration 44 N int 45 bytes int64 46 timerOn bool 47 benchTime time.Duration 48 // The initial states of memStats.Mallocs and memStats.TotalAlloc. 49 startAllocs uint64 50 startBytes uint64 51 // The net total of this test after being run. 52 netAllocs uint64 53 netBytes uint64 54} 55 56// StartTimer starts timing a test. This function is called automatically 57// before a benchmark starts, but it can also used to resume timing after 58// a call to StopTimer. 59func (c *C) StartTimer() { 60 if !c.timerOn { 61 c.start = time.Now() 62 c.timerOn = true 63 64 runtime.ReadMemStats(&memStats) 65 c.startAllocs = memStats.Mallocs 66 c.startBytes = memStats.TotalAlloc 67 } 68} 69 70// StopTimer stops timing a test. This can be used to pause the timer 71// while performing complex initialization that you don't 72// want to measure. 73func (c *C) StopTimer() { 74 if c.timerOn { 75 c.duration += time.Now().Sub(c.start) 76 c.timerOn = false 77 runtime.ReadMemStats(&memStats) 78 c.netAllocs += memStats.Mallocs - c.startAllocs 79 c.netBytes += memStats.TotalAlloc - c.startBytes 80 } 81} 82 83// ResetTimer sets the elapsed benchmark time to zero. 84// It does not affect whether the timer is running. 85func (c *C) ResetTimer() { 86 if c.timerOn { 87 c.start = time.Now() 88 runtime.ReadMemStats(&memStats) 89 c.startAllocs = memStats.Mallocs 90 c.startBytes = memStats.TotalAlloc 91 } 92 c.duration = 0 93 c.netAllocs = 0 94 c.netBytes = 0 95} 96 97// SetBytes informs the number of bytes that the benchmark processes 98// on each iteration. If this is called in a benchmark it will also 99// report MB/s. 100func (c *C) SetBytes(n int64) { 101 c.bytes = n 102} 103 104func (c *C) nsPerOp() int64 { 105 if c.N <= 0 { 106 return 0 107 } 108 return c.duration.Nanoseconds() / int64(c.N) 109} 110 111func (c *C) mbPerSec() float64 { 112 if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 { 113 return 0 114 } 115 return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds() 116} 117 118func (c *C) timerString() string { 119 if c.N <= 0 { 120 return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9) 121 } 122 mbs := c.mbPerSec() 123 mb := "" 124 if mbs != 0 { 125 mb = fmt.Sprintf("\t%7.2f MB/s", mbs) 126 } 127 nsop := c.nsPerOp() 128 ns := fmt.Sprintf("%10d ns/op", nsop) 129 if c.N > 0 && nsop < 100 { 130 // The format specifiers here make sure that 131 // the ones digits line up for all three possible formats. 132 if nsop < 10 { 133 ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N)) 134 } else { 135 ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N)) 136 } 137 } 138 memStats := "" 139 if c.benchMem { 140 allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N)) 141 allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N)) 142 memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs) 143 } 144 return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats) 145} 146 147func min(x, y int) int { 148 if x > y { 149 return y 150 } 151 return x 152} 153 154func max(x, y int) int { 155 if x < y { 156 return y 157 } 158 return x 159} 160 161// roundDown10 rounds a number down to the nearest power of 10. 162func roundDown10(n int) int { 163 var tens = 0 164 // tens = floor(log_10(n)) 165 for n > 10 { 166 n = n / 10 167 tens++ 168 } 169 // result = 10^tens 170 result := 1 171 for i := 0; i < tens; i++ { 172 result *= 10 173 } 174 return result 175} 176 177// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX]. 178func roundUp(n int) int { 179 base := roundDown10(n) 180 if n < (2 * base) { 181 return 2 * base 182 } 183 if n < (5 * base) { 184 return 5 * base 185 } 186 return 10 * base 187} 188