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
|
//go:generate go run genalphabet.go
|
||||||
|
|
||||||
var bigRadix = big.NewInt(58)
|
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)
|
var bigZero = big.NewInt(0)
|
||||||
|
|
||||||
// Decode decodes a modified base58 string to a byte slice.
|
// Decode decodes a modified base58 string to a byte slice.
|
||||||
|
@ -51,10 +52,32 @@ func Encode(b []byte) string {
|
||||||
x.SetBytes(b)
|
x.SetBytes(b)
|
||||||
|
|
||||||
answer := make([]byte, 0, len(b)*136/100)
|
answer := make([]byte, 0, len(b)*136/100)
|
||||||
for x.Cmp(bigZero) > 0 {
|
|
||||||
mod := new(big.Int)
|
mod := new(big.Int)
|
||||||
x.DivMod(x, bigRadix, mod)
|
for x.Cmp(bigZero) > 0 {
|
||||||
answer = append(answer, alphabet[mod.Int64()])
|
// 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
|
// leading zero bytes
|
||||||
|
|
|
@ -11,25 +11,37 @@ import (
|
||||||
"github.com/btcsuite/btcutil/base58"
|
"github.com/btcsuite/btcutil/base58"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkBase58Encode(b *testing.B) {
|
var (
|
||||||
b.StopTimer()
|
raw5k = bytes.Repeat([]byte{0xff}, 5000)
|
||||||
data := bytes.Repeat([]byte{0xff}, 5000)
|
raw100k = bytes.Repeat([]byte{0xff}, 100*1000)
|
||||||
b.SetBytes(int64(len(data)))
|
encoded5k = base58.Encode(raw5k)
|
||||||
b.StartTimer()
|
encoded100k = base58.Encode(raw100k)
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkBase58Encode_5K(b *testing.B) {
|
||||||
|
b.SetBytes(int64(len(raw5k)))
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
base58.Encode(data)
|
base58.Encode(raw5k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkBase58Decode(b *testing.B) {
|
func BenchmarkBase58Encode_100K(b *testing.B) {
|
||||||
b.StopTimer()
|
b.SetBytes(int64(len(raw100k)))
|
||||||
data := bytes.Repeat([]byte{0xff}, 5000)
|
|
||||||
encoded := base58.Encode(data)
|
|
||||||
b.SetBytes(int64(len(encoded)))
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
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