Skip to content

Commit 811b187

Browse files
committed
encoding/base64: slight decoding speed-up
First, use a dummy slice access on decode64 and decode32 to ensure that there is a single bounds check for src. Second, move the PutUint64/PutUint32 calls out of these functions, meaning that they are simpler and smaller. This may also open the door to inlineability in the future, but for now, they both go past the budget. While at it, get rid of the ilen and olen variables, which have no impact whatsoever on performance. At least, not measurable by any of the benchmarks. name old time/op new time/op delta DecodeString/2-4 54.3ns ± 1% 55.2ns ± 2% +1.60% (p=0.017 n=5+6) DecodeString/4-4 66.6ns ± 1% 66.8ns ± 2% ~ (p=0.903 n=6+6) DecodeString/8-4 79.3ns ± 2% 79.6ns ± 1% ~ (p=0.448 n=6+6) DecodeString/64-4 300ns ± 1% 281ns ± 3% -6.54% (p=0.002 n=6+6) DecodeString/8192-4 27.4µs ± 1% 23.7µs ± 2% -13.47% (p=0.002 n=6+6) name old speed new speed delta DecodeString/2-4 73.7MB/s ± 1% 72.5MB/s ± 2% -1.55% (p=0.026 n=5+6) DecodeString/4-4 120MB/s ± 1% 120MB/s ± 2% ~ (p=0.851 n=6+6) DecodeString/8-4 151MB/s ± 2% 151MB/s ± 1% ~ (p=0.485 n=6+6) DecodeString/64-4 292MB/s ± 1% 313MB/s ± 3% +7.03% (p=0.002 n=6+6) DecodeString/8192-4 399MB/s ± 1% 461MB/s ± 2% +15.58% (p=0.002 n=6+6) For #19636. Change-Id: I0dfbdafa2a41dc4c582f63aef94b90b8e473731c Reviewed-on: https://go-review.googlesource.com/113776 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 1484270 commit 811b187

File tree

1 file changed

+32
-34
lines changed

1 file changed

+32
-34
lines changed

src/encoding/base64/base64.go

+32-34
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,9 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
465465
}
466466

467467
si := 0
468-
ilen := len(src)
469-
olen := len(dst)
470-
for strconv.IntSize >= 64 && ilen-si >= 8 && olen-n >= 8 {
471-
if ok := enc.decode64(dst[n:], src[si:]); ok {
468+
for strconv.IntSize >= 64 && len(src)-si >= 8 && len(dst)-n >= 8 {
469+
if dn, ok := enc.decode64(src[si:]); ok {
470+
binary.BigEndian.PutUint64(dst[n:], dn)
472471
n += 6
473472
si += 8
474473
} else {
@@ -481,8 +480,9 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
481480
}
482481
}
483482

484-
for ilen-si >= 4 && olen-n >= 4 {
485-
if ok := enc.decode32(dst[n:], src[si:]); ok {
483+
for len(src)-si >= 4 && len(dst)-n >= 4 {
484+
if dn, ok := enc.decode32(src[si:]); ok {
485+
binary.BigEndian.PutUint32(dst[n:], dn)
486486
n += 3
487487
si += 4
488488
} else {
@@ -506,72 +506,70 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
506506
return n, err
507507
}
508508

509-
// decode32 tries to decode 4 base64 char into 3 bytes.
510-
// len(dst) and len(src) must both be >= 4.
511-
// Returns true if decode succeeded.
512-
func (enc *Encoding) decode32(dst, src []byte) bool {
513-
var dn, n uint32
509+
// decode32 tries to decode 4 base64 characters into 3 bytes, and returns those
510+
// bytes. len(src) must be >= 4.
511+
// Returns (0, false) if decoding failed.
512+
func (enc *Encoding) decode32(src []byte) (dn uint32, ok bool) {
513+
var n uint32
514+
_ = src[3]
514515
if n = uint32(enc.decodeMap[src[0]]); n == 0xff {
515-
return false
516+
return 0, false
516517
}
517518
dn |= n << 26
518519
if n = uint32(enc.decodeMap[src[1]]); n == 0xff {
519-
return false
520+
return 0, false
520521
}
521522
dn |= n << 20
522523
if n = uint32(enc.decodeMap[src[2]]); n == 0xff {
523-
return false
524+
return 0, false
524525
}
525526
dn |= n << 14
526527
if n = uint32(enc.decodeMap[src[3]]); n == 0xff {
527-
return false
528+
return 0, false
528529
}
529530
dn |= n << 8
530-
531-
binary.BigEndian.PutUint32(dst, dn)
532-
return true
531+
return dn, true
533532
}
534533

535-
// decode64 tries to decode 8 base64 char into 6 bytes.
536-
// len(dst) and len(src) must both be >= 8.
537-
// Returns true if decode succeeded.
538-
func (enc *Encoding) decode64(dst, src []byte) bool {
539-
var dn, n uint64
534+
// decode64 tries to decode 8 base64 characters into 6 bytes, and returns those
535+
// bytes. len(src) must be >= 8.
536+
// Returns (0, false) if decoding failed.
537+
func (enc *Encoding) decode64(src []byte) (dn uint64, ok bool) {
538+
var n uint64
539+
_ = src[7]
540540
if n = uint64(enc.decodeMap[src[0]]); n == 0xff {
541-
return false
541+
return 0, false
542542
}
543543
dn |= n << 58
544544
if n = uint64(enc.decodeMap[src[1]]); n == 0xff {
545-
return false
545+
return 0, false
546546
}
547547
dn |= n << 52
548548
if n = uint64(enc.decodeMap[src[2]]); n == 0xff {
549-
return false
549+
return 0, false
550550
}
551551
dn |= n << 46
552552
if n = uint64(enc.decodeMap[src[3]]); n == 0xff {
553-
return false
553+
return 0, false
554554
}
555555
dn |= n << 40
556556
if n = uint64(enc.decodeMap[src[4]]); n == 0xff {
557-
return false
557+
return 0, false
558558
}
559559
dn |= n << 34
560560
if n = uint64(enc.decodeMap[src[5]]); n == 0xff {
561-
return false
561+
return 0, false
562562
}
563563
dn |= n << 28
564564
if n = uint64(enc.decodeMap[src[6]]); n == 0xff {
565-
return false
565+
return 0, false
566566
}
567567
dn |= n << 22
568568
if n = uint64(enc.decodeMap[src[7]]); n == 0xff {
569-
return false
569+
return 0, false
570570
}
571571
dn |= n << 16
572-
573-
binary.BigEndian.PutUint64(dst, dn)
574-
return true
572+
return dn, true
575573
}
576574

577575
type newlineFilteringReader struct {

0 commit comments

Comments
 (0)