From 8f8b18645c1124003a53208098febb57b96d935f Mon Sep 17 00:00:00 2001 From: Andy Balholm Date: Fri, 15 May 2020 10:43:19 -0700 Subject: [PATCH] Read multiple bytes in findMatchLengthWithLimit Use 64- or 32-bit loads instead of reading a byte at a time. The original C source did something like this, in a very C-ish way. It needed to be simplified to translate it to Go. The exact way this works was suggested by the assembly code in github.com/golang/snappy. --- brotli_test.go | 3 ++- find_match_length.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/brotli_test.go b/brotli_test.go index 8c87979..c465694 100644 --- a/brotli_test.go +++ b/brotli_test.go @@ -461,8 +461,9 @@ func BenchmarkEncodeLevelsReset(b *testing.B) { w := NewWriterLevel(buf, level) w.Write(opticks) w.Close() - b.Run(fmt.Sprintf("%d(%.1f%%)", level, float64(buf.Len())/float64(len(opticks))*100), func(b *testing.B) { + b.Run(fmt.Sprintf("%d", level), func(b *testing.B) { b.ReportAllocs() + b.ReportMetric(float64(len(opticks))/float64(buf.Len()), "ratio") b.SetBytes(int64(len(opticks))) for i := 0; i < b.N; i++ { w.Reset(ioutil.Discard) diff --git a/find_match_length.go b/find_match_length.go index 6730119..09d2ae6 100644 --- a/find_match_length.go +++ b/find_match_length.go @@ -1,5 +1,11 @@ package brotli +import ( + "encoding/binary" + "math/bits" + "runtime" +) + /* Copyright 2010 Google Inc. All Rights Reserved. Distributed under MIT license. @@ -10,6 +16,28 @@ package brotli func findMatchLengthWithLimit(s1 []byte, s2 []byte, limit uint) uint { var matched uint = 0 _, _ = s1[limit-1], s2[limit-1] // bounds check + switch runtime.GOARCH { + case "amd64": + // Compare 8 bytes at at time. + for matched+8 <= limit { + w1 := binary.LittleEndian.Uint64(s1[matched:]) + w2 := binary.LittleEndian.Uint64(s2[matched:]) + if w1 != w2 { + return matched + uint(bits.TrailingZeros64(w1^w2)>>3) + } + matched += 8 + } + case "386": + // Compare 4 bytes at at time. + for matched+4 <= limit { + w1 := binary.LittleEndian.Uint32(s1[matched:]) + w2 := binary.LittleEndian.Uint32(s2[matched:]) + if w1 != w2 { + return matched + uint(bits.TrailingZeros32(w1^w2)>>3) + } + matched += 4 + } + } for matched < limit && s1[matched] == s2[matched] { matched++ }