base58: optimize Encode
Before: BenchmarkBase58Encode_5K-32 46 23934763 ns/op 0.21 MB/s BenchmarkBase58Encode_100K-32 1 9351948600 ns/op 0.01 MB/s After: BenchmarkBase58Encode_5K-32 501 2419129 ns/op 2.07 MB/s BenchmarkBase58Encode_100K-32 2 923507950 ns/op 0.11 MB/s
This commit is contained in:
parent
a21f014935
commit
ed1fc7ad99
2 changed files with 52 additions and 17 deletions
|
@ -11,6 +11,7 @@ import (
|
|||
//go:generate go run genalphabet.go
|
||||
|
||||
var bigRadix = big.NewInt(58)
|
||||
var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10
|
||||
var bigZero = big.NewInt(0)
|
||||
|
||||
// Decode decodes a modified base58 string to a byte slice.
|
||||
|
@ -51,10 +52,32 @@ func Encode(b []byte) string {
|
|||
x.SetBytes(b)
|
||||
|
||||
answer := make([]byte, 0, len(b)*136/100)
|
||||
for x.Cmp(bigZero) > 0 {
|
||||
mod := new(big.Int)
|
||||
x.DivMod(x, bigRadix, mod)
|
||||
answer = append(answer, alphabet[mod.Int64()])
|
||||
for x.Cmp(bigZero) > 0 {
|
||||
// Calculating with big.Int is slow for each iteration.
|
||||
// x, mod = x / 58, x % 58
|
||||
//
|
||||
// Instead we can try to do as much calculations on int64.
|
||||
// x, mod = x / 58^10, x % 58^10
|
||||
//
|
||||
// Which will give us mod, which is 10 digit base58 number.
|
||||
// We'll loop that 10 times to convert to the answer.
|
||||
|
||||
x.DivMod(x, bigRadix10, mod)
|
||||
if x.Cmp(bigZero) == 0 {
|
||||
// When x = 0, we need to ensure we don't add any extra zeros.
|
||||
m := mod.Int64()
|
||||
for m > 0 {
|
||||
answer = append(answer, alphabet[m%58])
|
||||
m /= 58
|
||||
}
|
||||
} else {
|
||||
m := mod.Int64()
|
||||
for i := 0; i < 10; i++ {
|
||||
answer = append(answer, alphabet[m%58])
|
||||
m /= 58
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// leading zero bytes
|
||||
|
|
|
@ -11,25 +11,37 @@ import (
|
|||
"github.com/btcsuite/btcutil/base58"
|
||||
)
|
||||
|
||||
func BenchmarkBase58Encode(b *testing.B) {
|
||||
b.StopTimer()
|
||||
data := bytes.Repeat([]byte{0xff}, 5000)
|
||||
b.SetBytes(int64(len(data)))
|
||||
b.StartTimer()
|
||||
var (
|
||||
raw5k = bytes.Repeat([]byte{0xff}, 5000)
|
||||
raw100k = bytes.Repeat([]byte{0xff}, 100*1000)
|
||||
encoded5k = base58.Encode(raw5k)
|
||||
encoded100k = base58.Encode(raw100k)
|
||||
)
|
||||
|
||||
func BenchmarkBase58Encode_5K(b *testing.B) {
|
||||
b.SetBytes(int64(len(raw5k)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
base58.Encode(data)
|
||||
base58.Encode(raw5k)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBase58Decode(b *testing.B) {
|
||||
b.StopTimer()
|
||||
data := bytes.Repeat([]byte{0xff}, 5000)
|
||||
encoded := base58.Encode(data)
|
||||
b.SetBytes(int64(len(encoded)))
|
||||
b.StartTimer()
|
||||
|
||||
func BenchmarkBase58Encode_100K(b *testing.B) {
|
||||
b.SetBytes(int64(len(raw100k)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
base58.Decode(encoded)
|
||||
base58.Encode(raw100k)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBase58Decode_5K(b *testing.B) {
|
||||
b.SetBytes(int64(len(encoded5k)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
base58.Decode(encoded5k)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBase58Decode_100K(b *testing.B) {
|
||||
b.SetBytes(int64(len(encoded100k)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
base58.Decode(encoded100k)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue