Skip to content

Commit

Permalink
Tweak block selection.
Browse files Browse the repository at this point in the history
  • Loading branch information
klauspost committed Jan 14, 2020
1 parent fcee6d8 commit 490fd07
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 13 deletions.
9 changes: 6 additions & 3 deletions flate/huffman_bit_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,8 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) {
}

// Add everything as literals
estBits := histogramSize(input, w.literalFreq[:], !eof && !sync) + 15 + w.lastHeader
const guessHeaderSizeBits = 400
estBits := histogramSize(input, w.literalFreq[:], !eof && !sync) + 15 + guessHeaderSizeBits

// Store bytes, if we don't get a reasonable improvement.
ssize, storable := w.storedSize(input)
Expand All @@ -819,8 +820,10 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) {
}

if w.lastHeader > 0 {
size := w.dynamicReuseSize(w.literalEncoding, huffOffset)
estBits += estBits >> w.logReusePenalty
size := w.dynamicReuseSize(w.literalEncoding, huffOffset) + w.lastHeader
if w.logReusePenalty > 0 {
estBits += estBits >> w.logReusePenalty
}

if estBits < size {
// We owe an EOB
Expand Down
1 change: 1 addition & 0 deletions flate/huffman_bit_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func testBlockHuff(t *testing.T, in, out string) {
}
var buf bytes.Buffer
bw := newHuffmanBitWriter(&buf)
bw.logReusePenalty = 8
bw.writeBlockHuff(false, all, false)
bw.flush()
got := buf.Bytes()
Expand Down
13 changes: 9 additions & 4 deletions flate/huffman_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,13 @@ func (s byFreq) Less(i, j int) bool {

func (s byFreq) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func atLeastOne(v float32) float32 {
if v < 1 {
return 1
}
return v
}

// histogramSize accumulates a histogram of b in h.
// An estimated size in bits is returned.
// Unassigned values are assigned '1' in the histogram.
Expand All @@ -365,15 +372,13 @@ func histogramSize(b []byte, h []uint16, fill bool) int {
for _, t := range b {
h[t]++
}
invTotal := float32(1.0 / float64(len(b)))
invTotal := 1.0 / float32(len(b))
shannon := float32(0.0)
single := float32(math.Ceil(-math.Log2(float64(invTotal))))
for i, v := range h[:] {
if v > 0 {
n := float32(v)
shannon += -mFastLog2(n*invTotal) * n
shannon += atLeastOne(-mFastLog2(n*invTotal)) * n
} else if fill {
shannon += single
h[i] = 1
}
}
Expand Down
Binary file modified flate/testdata/huffman-rand-limit.golden
Binary file not shown.
Binary file modified flate/testdata/huffman-text-shift.golden
Binary file not shown.
Binary file modified flate/testdata/huffman-text.golden
Binary file not shown.
5 changes: 1 addition & 4 deletions flate/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,7 @@ func (t *tokens) indexTokens(in []token) {
t.Reset()
for _, tok := range in {
if tok < matchType {
t.tokens[t.n] = tok
t.litHist[tok]++
t.n++
t.AddLiteral(tok.literal())
continue
}
t.AddMatch(uint32(tok.length()), tok.offset())
Expand Down Expand Up @@ -258,7 +256,6 @@ func (t *tokens) EstimatedBits() int {
}
}
}

return int(shannon) + bits
}

Expand Down
14 changes: 12 additions & 2 deletions flate/token_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package flate

import (
"bytes"
"io/ioutil"
"testing"
)
Expand All @@ -27,8 +28,17 @@ func loadTestTokens(t testFatal) *tokens {
func Test_tokens_EstimatedBits(t *testing.T) {
tok := loadTestTokens(t)
// The estimated size, update if method changes.
const expect = 196635
if n := tok.EstimatedBits(); n != expect {
const expect = 221057
n := tok.EstimatedBits()
var buf bytes.Buffer
wr := newHuffmanBitWriter(&buf)
wr.writeBlockDynamic(tok, true, nil, true)
if wr.err != nil {
t.Fatal(wr.err)
}
wr.flush()
t.Log("got:", n, "actual:", buf.Len()*8, "(header not part of estimate)")
if n != expect {
t.Error("want:", expect, "bits, got:", n)
}
}
Expand Down

0 comments on commit 490fd07

Please sign in to comment.