github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/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  }