perf: optimize math.Int.Size for small values (#17497)
This commit is contained in:
parent
780cad872b
commit
952328a4ed
@ -34,6 +34,12 @@ Ref: https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.j
|
||||
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Improvements
|
||||
|
||||
* [#17497](https://github.com/cosmos/cosmos-sdk/pull/17497) Optimize math.Int.Size for values that fit in 53 bits.
|
||||
|
||||
## [math/v1.1.2](https://github.com/cosmos/cosmos-sdk/releases/tag/math/v1.1.2) - 2023-08-21
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@ -22,3 +22,15 @@ func FuzzLegacyNewDecFromStr(f *testing.F) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzSmallIntSize(f *testing.F) {
|
||||
f.Add(int64(2<<53 - 1))
|
||||
f.Add(-int64(2<<53 - 1))
|
||||
f.Fuzz(func(t *testing.T, input int64) {
|
||||
i := NewInt(input)
|
||||
exp, _ := i.Marshal()
|
||||
if i.Size() != len(exp) {
|
||||
t.Fatalf("input %d: i.Size()=%d, len(input)=%d", input, i.Size(), len(exp))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
19
math/int.go
19
math/int.go
@ -4,6 +4,7 @@ import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
stdmath "math"
|
||||
"math/big"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -429,6 +430,24 @@ func (i *Int) Unmarshal(data []byte) error {
|
||||
|
||||
// Size implements the gogo proto custom type interface.
|
||||
func (i *Int) Size() int {
|
||||
if i.i == nil {
|
||||
return 1
|
||||
}
|
||||
// A float64 can store 52 bits exactly, which allows us to use
|
||||
// math.Log10 to compute the size fast and garbage free.
|
||||
if i.i.BitLen() <= 52 {
|
||||
i64 := i.i.Int64()
|
||||
if i64 == 0 {
|
||||
return 1
|
||||
}
|
||||
size := 0
|
||||
if i64 < 0 {
|
||||
i64 = -i64
|
||||
size++
|
||||
}
|
||||
return size + 1 + int(stdmath.Log10(float64(i64)))
|
||||
}
|
||||
// Slow path.
|
||||
bz, _ := i.Marshal()
|
||||
return len(bz)
|
||||
}
|
||||
|
||||
@ -592,14 +592,16 @@ func TestNewIntFromString(t *testing.T) {
|
||||
}
|
||||
|
||||
func BenchmarkIntSize(b *testing.B) {
|
||||
var tests []math.Int
|
||||
for _, st := range sizeTests {
|
||||
ii, _ := math.NewIntFromString(st.s)
|
||||
tests = append(tests, ii)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, st := range sizeTests {
|
||||
ii, _ := math.NewIntFromString(st.s)
|
||||
for _, ii := range tests {
|
||||
got := ii.Size()
|
||||
if got != st.want {
|
||||
b.Errorf("%q:: got=%d, want=%d", st.s, got, st.want)
|
||||
}
|
||||
sink = got
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user