Skip to content

Commit aa5165d

Browse files
committed
encoding/hex: simplify decoder arithmetic
Remove all multiplications and divisions from the main decoding loop. name old time/op new time/op delta Decode/256-8 323ns ± 0% 293ns ± 0% -9.29% (p=0.000 n=5+4) Decode/1024-8 1.26µs ± 0% 1.14µs ± 0% -9.48% (p=0.000 n=6+5) Decode/4096-8 4.99µs ± 0% 4.51µs ± 0% -9.55% (p=0.002 n=6+6) Decode/16384-8 20.0µs ± 0% 18.1µs ± 0% -9.54% (p=0.002 n=6+6) name old speed new speed delta Decode/256-8 791MB/s ± 0% 872MB/s ± 0% +10.34% (p=0.002 n=6+6) Decode/1024-8 814MB/s ± 0% 899MB/s ± 0% +10.48% (p=0.004 n=6+5) Decode/4096-8 821MB/s ± 0% 908MB/s ± 0% +10.55% (p=0.002 n=6+6) Decode/16384-8 821MB/s ± 0% 908MB/s ± 0% +10.54% (p=0.002 n=6+6) Change-Id: Ie9f91242ce04c130a77c1184379e3b9de38fe713 Reviewed-on: https://go-review.googlesource.com/c/151199 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 337a1bd commit aa5165d

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

src/encoding/hex/hex.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,23 +55,24 @@ func DecodedLen(x int) int { return x / 2 }
5555
// If the input is malformed, Decode returns the number
5656
// of bytes decoded before the error.
5757
func Decode(dst, src []byte) (int, error) {
58-
var i int
59-
for i = 0; i < len(src)/2; i++ {
60-
a, ok := fromHexChar(src[i*2])
58+
i, j := 0, 1
59+
for ; j < len(src); j += 2 {
60+
a, ok := fromHexChar(src[j-1])
6161
if !ok {
62-
return i, InvalidByteError(src[i*2])
62+
return i, InvalidByteError(src[j-1])
6363
}
64-
b, ok := fromHexChar(src[i*2+1])
64+
b, ok := fromHexChar(src[j])
6565
if !ok {
66-
return i, InvalidByteError(src[i*2+1])
66+
return i, InvalidByteError(src[j])
6767
}
6868
dst[i] = (a << 4) | b
69+
i++
6970
}
7071
if len(src)%2 == 1 {
7172
// Check for invalid char before reporting bad length,
7273
// since the invalid char (if present) is an earlier problem.
73-
if _, ok := fromHexChar(src[i*2]); !ok {
74-
return i, InvalidByteError(src[i*2])
74+
if _, ok := fromHexChar(src[j-1]); !ok {
75+
return i, InvalidByteError(src[j-1])
7576
}
7677
return i, ErrLength
7778
}

src/encoding/hex/hex_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,20 @@ func BenchmarkEncode(b *testing.B) {
249249
}
250250
}
251251

252+
func BenchmarkDecode(b *testing.B) {
253+
for _, size := range []int{256, 1024, 4096, 16384} {
254+
src := bytes.Repeat([]byte{'2', 'b', '7', '4', '4', 'f', 'a', 'a'}, size/8)
255+
sink = make([]byte, size/2)
256+
257+
b.Run(fmt.Sprintf("%v", size), func(b *testing.B) {
258+
b.SetBytes(int64(size))
259+
for i := 0; i < b.N; i++ {
260+
Decode(sink, src)
261+
}
262+
})
263+
}
264+
}
265+
252266
func BenchmarkDump(b *testing.B) {
253267
for _, size := range []int{256, 1024, 4096, 16384} {
254268
src := bytes.Repeat([]byte{2, 3, 5, 7, 9, 11, 13, 17}, size/8)

0 commit comments

Comments
 (0)