From: Rui Ueyama Date: Wed, 18 Jun 2014 19:05:46 +0000 (-0700) Subject: encoding/base64, encoding/base32: make Encode faster X-Git-Tag: go1.4beta1~1263 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2fbfe55e6374d212e49cff4c6723936af8e4ce89;p=gostls13.git encoding/base64, encoding/base32: make Encode faster Storing temporary values to a slice is slower than storing them to local variables of type byte. benchmark old MB/s new MB/s speedup BenchmarkEncodeToStringBase32 102.21 156.66 1.53x BenchmarkEncodeToStringBase64 124.25 177.91 1.43x LGTM=crawshaw R=golang-codereviews, crawshaw, bradfitz, dave CC=golang-codereviews https://golang.org/cl/109820045 --- diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go index 7613de24d2..ea5c0ae27c 100644 --- a/src/pkg/encoding/base32/base32.go +++ b/src/pkg/encoding/base32/base32.go @@ -73,45 +73,43 @@ func (enc *Encoding) Encode(dst, src []byte) { } for len(src) > 0 { - dst[0] = 0 - dst[1] = 0 - dst[2] = 0 - dst[3] = 0 - dst[4] = 0 - dst[5] = 0 - dst[6] = 0 - dst[7] = 0 + var b0, b1, b2, b3, b4, b5, b6, b7 byte // Unpack 8x 5-bit source blocks into a 5 byte // destination quantum switch len(src) { default: - dst[7] |= src[4] & 0x1F - dst[6] |= src[4] >> 5 + b7 |= src[4] & 0x1F + b6 |= src[4] >> 5 fallthrough case 4: - dst[6] |= (src[3] << 3) & 0x1F - dst[5] |= (src[3] >> 2) & 0x1F - dst[4] |= src[3] >> 7 + b6 |= (src[3] << 3) & 0x1F + b5 |= (src[3] >> 2) & 0x1F + b4 |= src[3] >> 7 fallthrough case 3: - dst[4] |= (src[2] << 1) & 0x1F - dst[3] |= (src[2] >> 4) & 0x1F + b4 |= (src[2] << 1) & 0x1F + b3 |= (src[2] >> 4) & 0x1F fallthrough case 2: - dst[3] |= (src[1] << 4) & 0x1F - dst[2] |= (src[1] >> 1) & 0x1F - dst[1] |= (src[1] >> 6) & 0x1F + b3 |= (src[1] << 4) & 0x1F + b2 |= (src[1] >> 1) & 0x1F + b1 |= (src[1] >> 6) & 0x1F fallthrough case 1: - dst[1] |= (src[0] << 2) & 0x1F - dst[0] |= src[0] >> 3 + b1 |= (src[0] << 2) & 0x1F + b0 |= src[0] >> 3 } // Encode 5-bit blocks using the base32 alphabet - for j := 0; j < 8; j++ { - dst[j] = enc.encode[dst[j]] - } + dst[0] = enc.encode[b0] + dst[1] = enc.encode[b1] + dst[2] = enc.encode[b2] + dst[3] = enc.encode[b3] + dst[4] = enc.encode[b4] + dst[5] = enc.encode[b5] + dst[6] = enc.encode[b6] + dst[7] = enc.encode[b7] // Pad the final quantum if len(src) < 5 { diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go index f56b996faa..5a68f06e1c 100644 --- a/src/pkg/encoding/base32/base32_test.go +++ b/src/pkg/encoding/base32/base32_test.go @@ -284,3 +284,19 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY== t.Error("Decoded results not equal") } } + +func BenchmarkEncodeToString(b *testing.B) { + data := make([]byte, 8192) + b.SetBytes(int64(len(data))) + for i := 0; i < b.N; i++ { + StdEncoding.EncodeToString(data) + } +} + +func BenchmarkDecodeString(b *testing.B) { + data := StdEncoding.EncodeToString(make([]byte, 8192)) + b.SetBytes(int64(len(data))) + for i := 0; i < b.N; i++ { + StdEncoding.DecodeString(data) + } +} diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go index 4f1fcad917..f89afd2b92 100644 --- a/src/pkg/encoding/base64/base64.go +++ b/src/pkg/encoding/base64/base64.go @@ -74,31 +74,29 @@ func (enc *Encoding) Encode(dst, src []byte) { } for len(src) > 0 { - dst[0] = 0 - dst[1] = 0 - dst[2] = 0 - dst[3] = 0 + var b0, b1, b2, b3 byte // Unpack 4x 6-bit source blocks into a 4 byte // destination quantum switch len(src) { default: - dst[3] |= src[2] & 0x3F - dst[2] |= src[2] >> 6 + b3 |= src[2] & 0x3F + b2 |= src[2] >> 6 fallthrough case 2: - dst[2] |= (src[1] << 2) & 0x3F - dst[1] |= src[1] >> 4 + b2 |= (src[1] << 2) & 0x3F + b1 |= src[1] >> 4 fallthrough case 1: - dst[1] |= (src[0] << 4) & 0x3F - dst[0] |= src[0] >> 2 + b1 |= (src[0] << 4) & 0x3F + b0 |= src[0] >> 2 } // Encode 6-bit blocks using the base64 alphabet - for j := 0; j < 4; j++ { - dst[j] = enc.encode[dst[j]] - } + dst[0] = enc.encode[b0] + dst[1] = enc.encode[b1] + dst[2] = enc.encode[b2] + dst[3] = enc.encode[b3] // Pad the final quantum if len(src) < 3 { diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go index 691edb755b..7d199bfa08 100644 --- a/src/pkg/encoding/base64/base64_test.go +++ b/src/pkg/encoding/base64/base64_test.go @@ -343,6 +343,14 @@ func TestDecoderIssue7733(t *testing.T) { } } +func BenchmarkEncodeToString(b *testing.B) { + data := make([]byte, 8192) + b.SetBytes(int64(len(data))) + for i := 0; i < b.N; i++ { + StdEncoding.EncodeToString(data) + } +} + func BenchmarkDecodeString(b *testing.B) { data := StdEncoding.EncodeToString(make([]byte, 8192)) b.SetBytes(int64(len(data)))