Skip to content

Commit

Permalink
Merge pull request #65 from klauspost/backport_go17_changes
Browse files Browse the repository at this point in the history
Rewrite level 2+3+4 compression (#61)
  • Loading branch information
klauspost authored Oct 25, 2016
2 parents 1e65806 + 3a22e98 commit d696edd
Show file tree
Hide file tree
Showing 4 changed files with 680 additions and 384 deletions.
25 changes: 13 additions & 12 deletions flate/deflate.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,19 @@ type compressionLevel struct {
// See https://blog.klauspost.com/rebalancing-deflate-compression-levels/
var levels = []compressionLevel{
{}, // 0
// Level 1+2 uses snappy algorithm - values not used
// Level 1-4 uses specialized algorithm - values not used
{0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 2},
// For levels 3-6 we don't bother trying with lazy matches.
{0, 0, 0, 0, 0, 3},
{0, 0, 0, 0, 0, 4},
// For levels 5-6 we don't bother trying with lazy matches.
// Lazy matching is at least 30% slower, with 1.5% increase.
{4, 0, 8, 4, 4, 3},
{4, 0, 12, 6, 5, 4},
{6, 0, 24, 16, 6, 5},
{8, 0, 32, 32, 7, 6},
{6, 0, 12, 8, 12, 5},
{8, 0, 24, 16, 16, 6},
// Levels 7-9 use increasingly more lazy matching
// and increasingly stringent conditions for "good enough".
{4, 8, 16, 16, skipNever, 7},
{6, 16, 32, 64, skipNever, 8},
{8, 8, 24, 16, skipNever, 7},
{10, 16, 24, 64, skipNever, 8},
{32, 258, 258, 4096, skipNever, 9},
}

Expand Down Expand Up @@ -696,7 +696,7 @@ func (d *compressor) deflateLazy() {
// If we have a long run of no matches, skip additional bytes
// Resets when d.ii overflows after 64KB.
if d.ii > 31 {
n := int(d.ii >> 6)
n := int(d.ii >> 5)
for j := 0; j < n; j++ {
if d.index >= d.windowEnd-1 {
break
Expand Down Expand Up @@ -853,7 +853,7 @@ func (d *compressor) deflateSSE() {
}
} else {
d.ii++
end := d.index + int(d.ii>>uint(d.fastSkipHashing)) + 1
end := d.index + int(d.ii>>5) + 1
if end > d.windowEnd {
end = d.windowEnd
}
Expand Down Expand Up @@ -1099,6 +1099,7 @@ func (d *compressor) storeSnappy() {
}
d.tokens.n = 0
d.windowEnd = 0
d.snap.Reset()
return
}
}
Expand Down Expand Up @@ -1163,15 +1164,15 @@ func (d *compressor) init(w io.Writer, level int) (err error) {
d.window = make([]byte, maxStoreBlockSize)
d.fill = (*compressor).fillBlock
d.step = (*compressor).storeHuff
case level >= 1 && level <= 3:
case level >= 1 && level <= 4:
d.snap = newSnappy(level)
d.window = make([]byte, maxStoreBlockSize)
d.fill = (*compressor).fillBlock
d.step = (*compressor).storeSnappy
case level == DefaultCompression:
level = 5
fallthrough
case 4 <= level && level <= 9:
case 5 <= level && level <= 9:
d.compressionLevel = levels[level]
d.initDeflate()
d.fill = (*compressor).fillDeflate
Expand Down
82 changes: 81 additions & 1 deletion flate/deflate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ var deflateInflateStringTests = []deflateInflateStringTest{
{
"../testdata/Mark.Twain-Tom.Sawyer.txt",
"Mark.Twain-Tom.Sawyer",
[...]int{407330, 195000, 185361, 180974, 169160, 164476, 162936, 160506, 160295, 160295, 233460 + 100},
[...]int{387999, 185000, 182361, 179974, 174124, 168819, 162936, 160506, 160295, 160295, 233460 + 100},
},
}

Expand Down Expand Up @@ -566,3 +566,83 @@ func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error))
}
t.Logf("got %d bytes", len(out1))
}

// TestBestSpeed tests that round-tripping through deflate and then inflate
// recovers the original input. The Write sizes are near the thresholds in the
// compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize
// (65535).
func TestBestSpeed(t *testing.T) {
abc := make([]byte, 128)
for i := range abc {
abc[i] = byte(i)
}
abcabc := bytes.Repeat(abc, 131072/len(abc))
var want []byte

testCases := [][]int{
{65536, 0},
{65536, 1},
{65536, 1, 256},
{65536, 1, 65536},
{65536, 14},
{65536, 15},
{65536, 16},
{65536, 16, 256},
{65536, 16, 65536},
{65536, 127},
{65536, 128},
{65536, 128, 256},
{65536, 128, 65536},
{65536, 129},
{65536, 65536, 256},
{65536, 65536, 65536},
}

for i, tc := range testCases {
for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} {
tc[0] = firstN
outer:
for _, flush := range []bool{false, true} {
buf := new(bytes.Buffer)
want = want[:0]

w, err := NewWriter(buf, BestSpeed)
if err != nil {
t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err)
continue
}
for _, n := range tc {
want = append(want, abcabc[:n]...)
if _, err := w.Write(abcabc[:n]); err != nil {
t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err)
continue outer
}
if !flush {
continue
}
if err := w.Flush(); err != nil {
t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err)
continue outer
}
}
if err := w.Close(); err != nil {
t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err)
continue
}

r := NewReader(buf)
got, err := ioutil.ReadAll(r)
if err != nil {
t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err)
continue
}
r.Close()

if !bytes.Equal(got, want) {
t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush)
continue
}
}
}
}
}
Loading

0 comments on commit d696edd

Please sign in to comment.