github.com/m3db/m3@v1.5.0/src/dbnode/encoding/m3tsz/m3tsz_benchmark_test.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package m3tsz 22 23 import ( 24 "math" 25 "math/big" 26 "strconv" 27 "strings" 28 "testing" 29 ) 30 31 const ( 32 smallDpFloat = 123.456 33 largeDpFloat = 123.4567890123 34 intFloat = 123.0 35 ) 36 37 func BenchmarkMathPow(b *testing.B) { 38 for n := 0; n < b.N; n++ { 39 _ = smallDpFloat * math.Pow10(1) 40 } 41 } 42 43 func BenchmarkManualMult(b *testing.B) { 44 for n := 0; n < b.N; n++ { 45 _ = smallDpFloat * 10.0 46 } 47 } 48 49 func BenchmarkSliceLookup(b *testing.B) { 50 for n := 0; n < b.N; n++ { 51 _ = largeDpFloat * multipliers[6] 52 } 53 } 54 55 func BenchmarkFuncPointer(b *testing.B) { 56 benchPointer(b, funcNormal) 57 } 58 59 func BenchmarkBoolCheckTrue(b *testing.B) { 60 benchBoolCheck(b, true) 61 } 62 63 func BenchmarkBoolCheckFalse(b *testing.B) { 64 benchBoolCheck(b, false) 65 } 66 67 func BenchmarkMathModf(b *testing.B) { 68 for n := 0; n < b.N; n++ { 69 math.Modf(largeDpFloat) 70 } 71 } 72 73 func BenchmarkMathNextafter(b *testing.B) { 74 for n := 0; n < b.N; n++ { 75 math.Nextafter(largeDpFloat, 2) 76 } 77 } 78 79 func BenchmarkFormatFloat(b *testing.B) { 80 for n := 0; n < b.N; n++ { 81 strconv.FormatFloat(largeDpFloat, 'f', -1, 64) 82 } 83 } 84 85 func BenchmarkMathConversionInt(b *testing.B) { 86 benchMathConversion(b, intFloat) 87 } 88 89 func BenchmarkNoCheckConversionInt(b *testing.B) { 90 benchNoCheckConversion(b, intFloat) 91 } 92 93 func BenchmarkStringConversionInt(b *testing.B) { 94 benchStringConversion(b, intFloat) 95 } 96 97 func BenchmarkMathConversionSmall(b *testing.B) { 98 benchMathConversion(b, smallDpFloat) 99 } 100 101 func BenchmarkNoCheckConversionSmall(b *testing.B) { 102 benchNoCheckConversion(b, smallDpFloat) 103 } 104 105 func BenchmarkStringConversionSmall(b *testing.B) { 106 benchStringConversion(b, smallDpFloat) 107 } 108 109 func BenchmarkMathConversionLarge(b *testing.B) { 110 benchMathConversion(b, largeDpFloat) 111 } 112 113 func BenchmarkNoCheckConversionLarge(b *testing.B) { 114 benchNoCheckConversion(b, largeDpFloat) 115 } 116 117 func BenchmarkStringConversionLarge(b *testing.B) { 118 benchStringConversion(b, largeDpFloat) 119 } 120 121 func BenchmarkMathConversionLargeConst(b *testing.B) { 122 benchMathConstConversion(b, largeDpFloat) 123 } 124 125 func BenchmarkStringConversionLargeConst(b *testing.B) { 126 benchStringConstConversion(b, largeDpFloat) 127 } 128 129 func benchMathConversion(b *testing.B, val float64) { 130 for n := 0; n < b.N; n++ { 131 convertToIntFloat(val, 0) 132 } 133 } 134 135 func benchMathConstConversion(b *testing.B, val float64) { 136 var dec uint8 137 for n := 0; n < b.N; n++ { 138 _, dec, _, _ = convertToIntFloat(val, dec) 139 } 140 } 141 142 func benchStringConstConversion(b *testing.B, val float64) { 143 var dec uint8 144 for n := 0; n < b.N; n++ { 145 _, dec, _ = convertToIntString(val, dec) 146 } 147 } 148 149 func benchStringConversion(b *testing.B, val float64) { 150 for n := 0; n < b.N; n++ { 151 convertToIntString(val, 0) 152 } 153 } 154 155 func benchNoCheckConversion(b *testing.B, val float64) { 156 for n := 0; n < b.N; n++ { 157 convertToIntFloatIntNoCheck(val, 0) 158 } 159 } 160 161 func benchPointer(b *testing.B, f writeFunc) { 162 for n := 0; n < b.N; n++ { 163 f(largeDpFloat) 164 } 165 } 166 167 func benchBoolCheck(b *testing.B, enabled bool) { 168 for n := 0; n < b.N; n++ { 169 if enabled { 170 funcNormal(largeDpFloat) 171 } else { 172 funcOpt(largeDpFloat) 173 } 174 } 175 } 176 177 type writeFunc func(v float64) 178 179 func funcNormal(v float64) {} 180 func funcOpt(v float64) {} 181 182 func convertToIntFloatIntNoCheck(v float64, curMaxMult uint8) (float64, uint8, bool) { 183 val := v * math.Pow10(int(curMaxMult)) 184 sign := 1.0 185 if v < 0 { 186 sign = -1.0 187 val = val * -1.0 188 } 189 190 for mult := curMaxMult; mult <= maxMult && val < maxOptInt; mult++ { 191 i, r := math.Modf(val) 192 if r == 0 { 193 return sign * i, mult, false 194 } else if r < 0.5 { 195 // Round down and check 196 if math.Nextafter(val, 0) <= i { 197 return sign * i, mult, false 198 } 199 } else { 200 // Round up and check 201 next := i + 1 202 if math.Nextafter(val, next) >= next { 203 return sign * next, mult, false 204 } 205 } 206 val = val * 10.0 207 } 208 209 return v, 0, true 210 } 211 212 func convertToIntString(v float64, curDec uint8) (float64, uint8, bool) { 213 val := big.NewFloat(v) 214 215 if curDec == 0 { 216 i, acc := val.Int64() 217 if acc == big.Exact { 218 return float64(i), 0, false 219 } 220 } 221 222 s := strconv.FormatFloat(v, 'f', -1, 64) 223 dec := uint8(len(s)-strings.Index(s, ".")) - 1 224 225 if dec < curDec { 226 dec = curDec 227 } else if dec > maxMult { 228 dec = maxMult 229 } 230 231 val.Mul(val, big.NewFloat(math.Pow10(int(dec)))) 232 i, _ := val.Int64() 233 if i != math.MaxInt64 && i != math.MinInt64 { 234 mv, _ := val.Float64() 235 i = roundFloat(mv, i) 236 return float64(i), dec, false 237 } 238 239 return v, 0, true 240 } 241 242 func roundFloat(v float64, i int64) int64 { 243 _, r := math.Modf(v) 244 if r < 0.5 { 245 return i 246 } 247 248 return i + 1 249 }