// Copyright 2017 The Cockroach Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. package apd import ( "bytes" "fmt" "math/rand" "testing" ) // runBenches benchmarks a given function on random decimals on combinations of // three parameters: // // precision: desired output precision // inScale: the scale of the input decimal: the absolute value will be between // 10^inScale and 10^(inScale+1) // inNumDigits: number of digits in the input decimal; if negative the number // will be negative and the number of digits are the absolute value. func runBenches( b *testing.B, precision, inScale, inNumDigits []int, fn func(*testing.B, *Context, *Decimal), ) { for _, p := range precision { ctx := BaseContext.WithPrecision(uint32(p)) for _, s := range inScale { for _, d := range inNumDigits { numDigits := d negative := false if d < 0 { numDigits = -d negative = true } if numDigits > p { // Skip cases where we have more digits than the desired precision. continue } // Generate some random numbers with the given number of digits. nums := make([]Decimal, 20) for i := range nums { var buf bytes.Buffer if negative { buf.WriteByte('-') } buf.WriteByte('1' + byte(rand.Intn(9))) for j := 1; j < numDigits; j++ { buf.WriteByte('0' + byte(rand.Intn(10))) } if _, _, err := nums[i].SetString(buf.String()); err != nil { b.Fatal(err) } nums[i].Exponent = int32(s - numDigits) } b.Run( fmt.Sprintf("P%d/S%d/D%d", p, s, d), func(b *testing.B) { for i := 0; i <= b.N; i++ { fn(b, ctx, &nums[i%len(nums)]) } }, ) } } } } func BenchmarkExp(b *testing.B) { precision := []int{5, 10, 100} scale := []int{-4, -1, 2} digits := []int{-100, -10, -2, 2, 10, 100} runBenches( b, precision, scale, digits, func(b *testing.B, ctx *Context, x *Decimal) { if _, err := ctx.Exp(&Decimal{}, x); err != nil { b.Fatal(err) } }, ) } func BenchmarkLn(b *testing.B) { precision := []int{2, 10, 100} scale := []int{-100, -10, -2, 2, 10, 100} digits := []int{2, 10, 100} runBenches( b, precision, scale, digits, func(b *testing.B, ctx *Context, x *Decimal) { if _, err := ctx.Ln(&Decimal{}, x); err != nil { b.Fatal(err) } }, ) } func BenchmarkDecimalString(b *testing.B) { rng := rand.New(rand.NewSource(461210934723948)) corpus := func() []Decimal { res := make([]Decimal, 8192) for i := range res { _, err := res[i].SetFloat64(rng.Float64()) if err != nil { b.Fatal(err) } } return res }() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { _ = corpus[rng.Intn(len(corpus))].String() } } func BenchmarkDecimalSetFloat(b *testing.B) { rng := rand.New(rand.NewSource(461210934723948)) corpus := func() []float64 { res := make([]float64, 8192) for i := range res { res[i] = rng.ExpFloat64() } return res }() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { var d Decimal _, err := d.SetFloat64(corpus[rng.Intn(len(corpus))]) if err != nil { b.Fatal(err) } } }