...

Source file src/github.com/klauspost/compress/huff0/compress_test.go

Documentation: github.com/klauspost/compress/huff0

     1  package huff0
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"math/rand"
     8  	"os"
     9  	"path/filepath"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/klauspost/compress/flate"
    15  	"github.com/klauspost/compress/zip"
    16  )
    17  
    18  type inputFn func() ([]byte, error)
    19  
    20  var testfiles = []struct {
    21  	name  string
    22  	fn    inputFn
    23  	err1X error
    24  	err4X error
    25  }{
    26  	// Digits is the digits of the irrational number e. Its decimal representation
    27  	// does not repeat, but there are only 10 possible digits, so it should be
    28  	// reasonably compressible.
    29  	{name: "digits", fn: func() ([]byte, error) { return os.ReadFile("../testdata/e.txt") }},
    30  	// gettysburg.txt is a small plain text.
    31  	{name: "gettysburg", fn: func() ([]byte, error) { return os.ReadFile("../testdata/gettysburg.txt") }},
    32  	// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
    33  	{name: "twain", fn: func() ([]byte, error) { return os.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt") }},
    34  	// Random bytes
    35  	{name: "random", fn: func() ([]byte, error) { return os.ReadFile("../testdata/sharnd.out") }, err1X: ErrIncompressible, err4X: ErrIncompressible},
    36  	// Low entropy
    37  	{name: "low-ent.10k", fn: func() ([]byte, error) { return []byte(strings.Repeat("1221", 10000)), nil }},
    38  	// Super Low entropy
    39  	{name: "superlow-ent-10k", fn: func() ([]byte, error) { return []byte(strings.Repeat("1", 10000) + strings.Repeat("2", 500)), nil }},
    40  	// Zero bytes
    41  	{name: "zeroes", fn: func() ([]byte, error) { return make([]byte, 10000), nil }, err1X: ErrUseRLE, err4X: ErrUseRLE},
    42  	{name: "crash1", fn: func() ([]byte, error) { return os.ReadFile("../testdata/crash1.bin") }, err1X: ErrIncompressible, err4X: ErrIncompressible},
    43  	{name: "crash2", fn: func() ([]byte, error) { return os.ReadFile("../testdata/crash2.bin") }, err4X: ErrIncompressible},
    44  	{name: "crash3", fn: func() ([]byte, error) { return os.ReadFile("../testdata/crash3.bin") }, err1X: ErrIncompressible, err4X: ErrIncompressible},
    45  	{name: "endzerobits", fn: func() ([]byte, error) { return os.ReadFile("../testdata/endzerobits.bin") }, err1X: nil, err4X: ErrIncompressible},
    46  	{name: "endnonzero", fn: func() ([]byte, error) { return os.ReadFile("../testdata/endnonzero.bin") }, err4X: ErrIncompressible},
    47  	{name: "case1", fn: func() ([]byte, error) { return os.ReadFile("../testdata/case1.bin") }, err1X: nil},
    48  	{name: "case2", fn: func() ([]byte, error) { return os.ReadFile("../testdata/case2.bin") }, err1X: nil},
    49  	{name: "case3", fn: func() ([]byte, error) { return os.ReadFile("../testdata/case3.bin") }, err1X: nil},
    50  	{name: "pngdata.001", fn: func() ([]byte, error) { return os.ReadFile("../testdata/pngdata.bin") }, err1X: nil},
    51  	{name: "normcount2", fn: func() ([]byte, error) { return os.ReadFile("../testdata/normcount2.bin") }, err1X: nil},
    52  }
    53  
    54  type fuzzInput struct {
    55  	name string
    56  	fn   inputFn
    57  }
    58  
    59  // testfilesExtended is used for regression testing the decoder.
    60  // These files are expected to fail, but not crash
    61  var testfilesExtended []fuzzInput
    62  
    63  func init() {
    64  	data, err := os.ReadFile("testdata/regression.zip")
    65  	if err != nil {
    66  		panic(err)
    67  	}
    68  	zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
    69  	if err != nil {
    70  		panic(err)
    71  	}
    72  	for _, tt := range zr.File {
    73  		if tt.UncompressedSize64 == 0 {
    74  			continue
    75  		}
    76  		rc, err := tt.Open()
    77  		if err != nil {
    78  			panic(err)
    79  		}
    80  		b, err := io.ReadAll(rc)
    81  		if err != nil {
    82  			panic(err)
    83  		}
    84  		testfilesExtended = append(testfilesExtended, fuzzInput{
    85  			name: filepath.Base(tt.Name),
    86  			fn: func() ([]byte, error) {
    87  				return b, nil
    88  			},
    89  		})
    90  	}
    91  }
    92  
    93  func TestCompressRegression(t *testing.T) {
    94  	// Match the fuzz function
    95  	var testInput = func(t *testing.T, data []byte) int {
    96  		var enc Scratch
    97  		enc.WantLogLess = 5
    98  		comp, _, err := Compress1X(data, &enc)
    99  		if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
   100  			return 0
   101  		}
   102  		if err != nil {
   103  			panic(err)
   104  		}
   105  		if len(comp) >= len(data)-len(data)>>enc.WantLogLess {
   106  			panic(fmt.Errorf("too large output provided. got %d, but should be < %d", len(comp), len(data)-len(data)>>enc.WantLogLess))
   107  		}
   108  
   109  		dec, remain, err := ReadTable(comp, nil)
   110  		if err != nil {
   111  			panic(err)
   112  		}
   113  		out, err := dec.Decompress1X(remain)
   114  		if err != nil {
   115  			t.Error(err)
   116  		}
   117  		if !bytes.Equal(out, data) {
   118  			t.Error("decompression 1x mismatch")
   119  		}
   120  		// Reuse as 4X
   121  		enc.Reuse = ReusePolicyAllow
   122  		comp, reUsed, err := Compress4X(data, &enc)
   123  		if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
   124  			return 0
   125  		}
   126  		if err != nil {
   127  			panic(err)
   128  		}
   129  		if len(comp) >= len(data)-len(data)>>enc.WantLogLess {
   130  			panic(fmt.Errorf("too large output provided. got %d, but should be < %d", len(comp), len(data)-len(data)>>enc.WantLogLess))
   131  		}
   132  
   133  		remain = comp
   134  		if !reUsed {
   135  			dec, remain, err = ReadTable(comp, dec)
   136  			if err != nil {
   137  				panic(err)
   138  			}
   139  		}
   140  		out, err = dec.Decompress4X(remain, len(data))
   141  		if err != nil {
   142  			t.Error(err)
   143  		}
   144  		if !bytes.Equal(out, data) {
   145  			t.Error("decompression 4x with reuse mismatch")
   146  		}
   147  
   148  		enc.Reuse = ReusePolicyNone
   149  		comp, reUsed, err = Compress4X(data, &enc)
   150  		if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
   151  			return 0
   152  		}
   153  		if err != nil {
   154  			panic(err)
   155  		}
   156  		if reUsed {
   157  			panic("reused when asked not to")
   158  		}
   159  		if len(comp) >= len(data)-len(data)>>enc.WantLogLess {
   160  			panic(fmt.Errorf("too large output provided. got %d, but should be < %d", len(comp), len(data)-len(data)>>enc.WantLogLess))
   161  		}
   162  
   163  		dec, remain, err = ReadTable(comp, dec)
   164  		if err != nil {
   165  			panic(err)
   166  		}
   167  		out, err = dec.Decompress4X(remain, len(data))
   168  		if err != nil {
   169  			t.Error(err)
   170  		}
   171  		if !bytes.Equal(out, data) {
   172  			t.Error("decompression 4x mismatch")
   173  		}
   174  
   175  		// Reuse as 1X
   176  		dec.Reuse = ReusePolicyAllow
   177  		comp, reUsed, err = Compress1X(data, &enc)
   178  		if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
   179  			return 0
   180  		}
   181  		if err != nil {
   182  			panic(err)
   183  		}
   184  		if len(comp) >= len(data)-len(data)>>enc.WantLogLess {
   185  			panic(fmt.Errorf("too large output provided. got %d, but should be < %d", len(comp), len(data)-len(data)>>enc.WantLogLess))
   186  		}
   187  
   188  		remain = comp
   189  		if !reUsed {
   190  			dec, remain, err = ReadTable(comp, dec)
   191  			if err != nil {
   192  				panic(err)
   193  			}
   194  		}
   195  		out, err = dec.Decompress1X(remain)
   196  		if err != nil {
   197  			t.Error(err)
   198  		}
   199  		if !bytes.Equal(out, data) {
   200  			t.Error("decompression 1x with reuse mismatch")
   201  		}
   202  		return 1
   203  	}
   204  	for _, test := range testfiles {
   205  		t.Run(test.name, func(t *testing.T) {
   206  			buf0, err := test.fn()
   207  			if err != nil {
   208  				t.Fatal(err)
   209  			}
   210  			testInput(t, buf0)
   211  		})
   212  	}
   213  	for _, test := range testfilesExtended {
   214  		t.Run(test.name, func(t *testing.T) {
   215  			buf0, err := test.fn()
   216  			if err != nil {
   217  				t.Fatal(err)
   218  			}
   219  			testInput(t, buf0)
   220  		})
   221  	}
   222  }
   223  
   224  func TestCompress1X(t *testing.T) {
   225  	for _, test := range testfiles {
   226  		t.Run(test.name, func(t *testing.T) {
   227  			var s Scratch
   228  			buf0, err := test.fn()
   229  			if err != nil {
   230  				t.Fatal(err)
   231  			}
   232  			if len(buf0) > BlockSizeMax {
   233  				buf0 = buf0[:BlockSizeMax]
   234  			}
   235  			tbSz, dSz, reSz, _ := EstimateSizes(buf0, &s)
   236  			b, re, err := Compress1X(buf0, &s)
   237  			if err != test.err1X {
   238  				t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
   239  			}
   240  			if err != nil {
   241  				t.Log(test.name, err.Error())
   242  				return
   243  			}
   244  			if b == nil {
   245  				t.Error("got no output")
   246  				return
   247  			}
   248  			min := s.minSize(len(buf0))
   249  			if len(s.OutData) < min {
   250  				t.Errorf("output data length (%d) below shannon limit (%d)", len(s.OutData), min)
   251  			}
   252  			if len(s.OutTable) == 0 {
   253  				t.Error("got no table definition")
   254  			}
   255  			if re {
   256  				t.Error("claimed to have re-used.")
   257  			}
   258  			if len(s.OutData) == 0 {
   259  				t.Error("got no data output")
   260  			}
   261  			t.Logf("Estimate: table %d, got %d, data %d, got %d, reuse: %d", tbSz, len(s.OutTable), dSz, len(s.OutData), reSz)
   262  			t.Logf("%s: %d -> %d bytes (%.2f:1) re:%t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
   263  			s.Out = nil
   264  			bRe, _, err := Compress1X(b, &s)
   265  			if err == nil {
   266  				t.Log("Could re-compress to", len(bRe))
   267  			}
   268  		})
   269  	}
   270  }
   271  
   272  func TestCompress1XMustReuse(t *testing.T) {
   273  	for _, test := range testfiles {
   274  		t.Run(test.name, func(t *testing.T) {
   275  			var s Scratch
   276  			buf0, err := test.fn()
   277  			if err != nil {
   278  				t.Fatal(err)
   279  			}
   280  			if len(buf0) > BlockSizeMax {
   281  				buf0 = buf0[:BlockSizeMax]
   282  			}
   283  			b, re, err := Compress1X(buf0, &s)
   284  			if err != test.err1X {
   285  				t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
   286  			}
   287  			if err != nil {
   288  				t.Log(test.name, err.Error())
   289  				return
   290  			}
   291  			if b == nil {
   292  				t.Error("got no output")
   293  				return
   294  			}
   295  
   296  			min := s.minSize(len(buf0))
   297  			if len(s.OutData) < min {
   298  				t.Errorf("output data length (%d) below shannon limit (%d)", len(s.OutData), min)
   299  			}
   300  			if len(s.OutTable) == 0 {
   301  				t.Error("got no table definition")
   302  			}
   303  			if re {
   304  				t.Error("claimed to have re-used.")
   305  			}
   306  			if len(s.OutData) == 0 {
   307  				t.Error("got no data output")
   308  			}
   309  			t.Logf("%s: %d -> %d bytes (%.2f:1) re:%t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
   310  			table := s.OutTable
   311  			prevTable := s.prevTable
   312  			for i, v := range prevTable {
   313  				// Clear unused sections for comparison
   314  				if v.nBits == 0 {
   315  					prevTable[i].val = 0
   316  				}
   317  			}
   318  			b = s.OutData
   319  			actl := s.actualTableLog
   320  
   321  			// Use only the table data to recompress.
   322  			s = Scratch{}
   323  			s2 := &s
   324  			s.Reuse = ReusePolicyMust
   325  			s2, _, err = ReadTable(table, s2)
   326  			if err != nil {
   327  				t.Error("Could not read table", err)
   328  				return
   329  			}
   330  			if !reflect.DeepEqual(prevTable, s2.prevTable) {
   331  				t.Errorf("prevtable mismatch.\ngot %v\nwant %v", s2.prevTable, prevTable)
   332  			}
   333  			if actl != s.actualTableLog {
   334  				t.Errorf("tablelog mismatch, want %d, got %d", actl, s.actualTableLog)
   335  			}
   336  			b2, reused, err := Compress1X(buf0, s2)
   337  			if err != nil {
   338  				t.Error("Could not re-compress with prev table", err)
   339  			}
   340  			if !reused {
   341  				t.Error("didn't reuse...")
   342  				return
   343  			}
   344  			if len(b2) != len(b) {
   345  				t.Errorf("recompressed to different size, want %d, got %d", len(b), len(b2))
   346  				return
   347  			}
   348  
   349  			if !bytes.Equal(b, b2) {
   350  				for i := range b {
   351  					if b[i] != b2[i] {
   352  						t.Errorf("recompressed to different output. First mismatch at byte %d, (want %x != got %x)", i, b[i], b2[i])
   353  						return
   354  					}
   355  				}
   356  			}
   357  		})
   358  	}
   359  }
   360  
   361  func TestCompress4X(t *testing.T) {
   362  	for _, test := range testfiles {
   363  		t.Run(test.name, func(t *testing.T) {
   364  			var s Scratch
   365  			buf0, err := test.fn()
   366  			if err != nil {
   367  				t.Fatal(err)
   368  			}
   369  			if len(buf0) > BlockSizeMax {
   370  				buf0 = buf0[:BlockSizeMax]
   371  			}
   372  			b, re, err := Compress4X(buf0, &s)
   373  			if err != test.err4X {
   374  				t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err4X, err, err)
   375  			}
   376  			if err != nil {
   377  				t.Log(test.name, err.Error())
   378  				return
   379  			}
   380  			if b == nil {
   381  				t.Error("got no output")
   382  				return
   383  			}
   384  			if len(s.OutTable) == 0 {
   385  				t.Error("got no table definition")
   386  			}
   387  			if re {
   388  				t.Error("claimed to have re-used.")
   389  			}
   390  			if len(s.OutData) == 0 {
   391  				t.Error("got no data output")
   392  			}
   393  
   394  			t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
   395  		})
   396  	}
   397  }
   398  
   399  func TestCompress4XReuse(t *testing.T) {
   400  	rng := rand.NewSource(0x1337)
   401  	var s Scratch
   402  	s.Reuse = ReusePolicyAllow
   403  	for i := 0; i < 255; i++ {
   404  		if testing.Short() && i > 10 {
   405  			break
   406  		}
   407  		t.Run(fmt.Sprint("test-", i), func(t *testing.T) {
   408  			buf0 := make([]byte, BlockSizeMax)
   409  			for j := range buf0 {
   410  				buf0[j] = byte(int64(i) + (rng.Int63() & 3))
   411  			}
   412  			tbSz, dSz, reSz, _ := EstimateSizes(buf0, &s)
   413  			b, re, err := Compress4X(buf0, &s)
   414  			if err != nil {
   415  				t.Fatal(err)
   416  			}
   417  			if b == nil {
   418  				t.Error("got no output")
   419  				return
   420  			}
   421  			if len(s.OutData) == 0 {
   422  				t.Error("got no data output")
   423  			}
   424  			if re {
   425  				t.Error("claimed to have re-used. Unlikely.")
   426  			}
   427  			t.Logf("Estimate: table %d, got %d, data %d, got %d, reuse: %d", tbSz, len(s.OutTable), dSz, len(s.OutData), reSz)
   428  			t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", t.Name(), len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
   429  		})
   430  	}
   431  }
   432  
   433  func TestCompress4XReuseActually(t *testing.T) {
   434  	rng := rand.NewSource(0x1337)
   435  	var s Scratch
   436  	s.Reuse = ReusePolicyAllow
   437  	for i := 0; i < 255; i++ {
   438  		if testing.Short() && i > 10 {
   439  			break
   440  		}
   441  		t.Run(fmt.Sprint("test-", i), func(t *testing.T) {
   442  			buf0 := make([]byte, BlockSizeMax)
   443  			for j := range buf0 {
   444  				buf0[j] = byte(rng.Int63() & 7)
   445  			}
   446  
   447  			tbSz, dSz, reSz, _ := EstimateSizes(buf0, &s)
   448  			b, re, err := Compress4X(buf0, &s)
   449  			if err != nil {
   450  				t.Fatal(err)
   451  			}
   452  			if b == nil {
   453  				t.Error("got no output")
   454  				return
   455  			}
   456  			if len(s.OutData) == 0 {
   457  				t.Error("got no data output")
   458  			}
   459  			if re && i == 0 {
   460  				t.Error("Claimed to have re-used on first loop.")
   461  			}
   462  			if !re && i > 0 {
   463  				t.Error("Expected table to be reused")
   464  			}
   465  			t.Logf("Estimate: table %d, got %d, data %d, got %d, reuse: %d", tbSz, len(s.OutTable), dSz, len(s.OutData), reSz)
   466  			t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", t.Name(), len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
   467  		})
   468  	}
   469  }
   470  func TestCompress1XReuse(t *testing.T) {
   471  	for _, test := range testfiles {
   472  		t.Run(test.name, func(t *testing.T) {
   473  			var s Scratch
   474  			buf0, err := test.fn()
   475  			if err != nil {
   476  				t.Fatal(err)
   477  			}
   478  			if len(buf0) > BlockSizeMax {
   479  				buf0 = buf0[:BlockSizeMax]
   480  			}
   481  			b, _, err := Compress1X(buf0, &s)
   482  			if err != test.err1X {
   483  				t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
   484  			}
   485  			if err != nil {
   486  				t.Log(test.name, err.Error())
   487  				return
   488  			}
   489  			if b == nil {
   490  				t.Error("got no output")
   491  				return
   492  			}
   493  			firstData := len(s.OutData)
   494  			s.Reuse = ReusePolicyAllow
   495  			tbSz, dSz, reSz, _ := EstimateSizes(buf0, &s)
   496  			b, re, err := Compress1X(buf0, &s)
   497  			if err != nil {
   498  				t.Errorf("got secondary error %v (%T)", err, err)
   499  				return
   500  			}
   501  			if !re {
   502  				t.Error("Didn't re-use even if data was the same")
   503  			}
   504  			if len(s.OutTable) != 0 {
   505  				t.Error("got table definition, don't want any")
   506  			}
   507  			if len(s.OutData) == 0 {
   508  				t.Error("got no data output")
   509  			}
   510  			if len(b) != firstData {
   511  				t.Errorf("data length did not match first: %d, second:%d", firstData, len(b))
   512  			}
   513  			t.Logf("Estimate: table %d, got %d, data %d, got %d, reuse: %d", tbSz, len(s.OutTable), dSz, len(s.OutData), reSz)
   514  			t.Logf("%s: %d -> %d bytes (%.2f:1) %t", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re)
   515  		})
   516  	}
   517  }
   518  
   519  func BenchmarkDeflate(b *testing.B) {
   520  	for _, tt := range testfiles {
   521  		test := tt
   522  		if test.err1X != nil {
   523  			continue
   524  		}
   525  		b.Run(test.name, func(b *testing.B) {
   526  			dec, err := flate.NewWriter(io.Discard, flate.HuffmanOnly)
   527  			if err != nil {
   528  				b.Fatal(err)
   529  			}
   530  			if test.err1X != nil {
   531  				b.Skip("skipping")
   532  			}
   533  			buf0, err := test.fn()
   534  			if err != nil {
   535  				b.Fatal(err)
   536  			}
   537  			if len(buf0) > BlockSizeMax {
   538  				buf0 = buf0[:BlockSizeMax]
   539  			}
   540  			b.ResetTimer()
   541  			b.ReportAllocs()
   542  			b.SetBytes(int64(len(buf0)))
   543  			for i := 0; i < b.N; i++ {
   544  				dec.Reset(io.Discard)
   545  				n, err := dec.Write(buf0)
   546  				if err != nil {
   547  					b.Fatal(err)
   548  				}
   549  				if n != len(buf0) {
   550  					b.Fatal("mismatch", n, len(buf0))
   551  				}
   552  				dec.Close()
   553  			}
   554  		})
   555  	}
   556  }
   557  
   558  func BenchmarkCompress1XReuseNone(b *testing.B) {
   559  	for _, tt := range testfiles {
   560  		test := tt
   561  		if test.err1X != nil {
   562  			continue
   563  		}
   564  		b.Run(test.name, func(b *testing.B) {
   565  			var s Scratch
   566  			s.Reuse = ReusePolicyNone
   567  			buf0, err := test.fn()
   568  			if err != nil {
   569  				b.Fatal(err)
   570  			}
   571  			if len(buf0) > BlockSizeMax {
   572  				buf0 = buf0[:BlockSizeMax]
   573  			}
   574  			_, _, err = Compress1X(buf0, &s)
   575  			if err != test.err1X {
   576  				b.Fatal("unexpected error:", err)
   577  			}
   578  			b.ResetTimer()
   579  			b.ReportAllocs()
   580  			b.SetBytes(int64(len(buf0)))
   581  			for i := 0; i < b.N; i++ {
   582  				_, re, _ := Compress1X(buf0, &s)
   583  				if re {
   584  					b.Fatal("reused")
   585  				}
   586  			}
   587  		})
   588  	}
   589  }
   590  
   591  func BenchmarkCompress1XReuseAllow(b *testing.B) {
   592  	for _, tt := range testfiles {
   593  		test := tt
   594  		if test.err1X != nil {
   595  			continue
   596  		}
   597  		b.Run(test.name, func(b *testing.B) {
   598  			var s Scratch
   599  			s.Reuse = ReusePolicyAllow
   600  			buf0, err := test.fn()
   601  			if err != nil {
   602  				b.Fatal(err)
   603  			}
   604  			if len(buf0) > BlockSizeMax {
   605  				buf0 = buf0[:BlockSizeMax]
   606  			}
   607  			_, _, err = Compress1X(buf0, &s)
   608  			if err != test.err1X {
   609  				b.Fatal("unexpected error:", err)
   610  			}
   611  			b.ResetTimer()
   612  			b.ReportAllocs()
   613  			b.SetBytes(int64(len(buf0)))
   614  			for i := 0; i < b.N; i++ {
   615  				_, re, _ := Compress1X(buf0, &s)
   616  				if !re {
   617  					b.Fatal("not reused")
   618  				}
   619  			}
   620  		})
   621  	}
   622  }
   623  
   624  func BenchmarkCompress1XReusePrefer(b *testing.B) {
   625  	for _, tt := range testfiles {
   626  		test := tt
   627  		if test.err1X != nil {
   628  			continue
   629  		}
   630  		b.Run(test.name, func(b *testing.B) {
   631  			var s Scratch
   632  			s.Reuse = ReusePolicyPrefer
   633  			buf0, err := test.fn()
   634  			if err != nil {
   635  				b.Fatal(err)
   636  			}
   637  			if len(buf0) > BlockSizeMax {
   638  				buf0 = buf0[:BlockSizeMax]
   639  			}
   640  			_, _, err = Compress1X(buf0, &s)
   641  			if err != test.err1X {
   642  				b.Fatal("unexpected error:", err)
   643  			}
   644  			b.ResetTimer()
   645  			b.ReportAllocs()
   646  			b.SetBytes(int64(len(buf0)))
   647  			for i := 0; i < b.N; i++ {
   648  				_, re, _ := Compress1X(buf0, &s)
   649  				if !re {
   650  					b.Fatal("not reused")
   651  				}
   652  			}
   653  		})
   654  	}
   655  }
   656  
   657  func BenchmarkCompress4XReuseNone(b *testing.B) {
   658  	for _, tt := range testfiles {
   659  		test := tt
   660  		if test.err4X != nil {
   661  			continue
   662  		}
   663  		b.Run(test.name, func(b *testing.B) {
   664  			var s Scratch
   665  			s.Reuse = ReusePolicyNone
   666  			buf0, err := test.fn()
   667  			if err != nil {
   668  				b.Fatal(err)
   669  			}
   670  			if len(buf0) > BlockSizeMax {
   671  				buf0 = buf0[:BlockSizeMax]
   672  			}
   673  			_, _, err = Compress4X(buf0, &s)
   674  			if err != test.err1X {
   675  				b.Fatal("unexpected error:", err)
   676  			}
   677  			b.ResetTimer()
   678  			b.ReportAllocs()
   679  			b.SetBytes(int64(len(buf0)))
   680  			for i := 0; i < b.N; i++ {
   681  				_, re, _ := Compress4X(buf0, &s)
   682  				if re {
   683  					b.Fatal("reused")
   684  				}
   685  			}
   686  		})
   687  	}
   688  }
   689  
   690  func BenchmarkCompress4XReuseAllow(b *testing.B) {
   691  	for _, tt := range testfiles {
   692  		test := tt
   693  		if test.err4X != nil {
   694  			continue
   695  		}
   696  		b.Run(test.name, func(b *testing.B) {
   697  			var s Scratch
   698  			s.Reuse = ReusePolicyAllow
   699  			buf0, err := test.fn()
   700  			if err != nil {
   701  				b.Fatal(err)
   702  			}
   703  			if len(buf0) > BlockSizeMax {
   704  				buf0 = buf0[:BlockSizeMax]
   705  			}
   706  			_, _, err = Compress4X(buf0, &s)
   707  			if err != test.err1X {
   708  				b.Fatal("unexpected error:", err)
   709  			}
   710  			b.ResetTimer()
   711  			b.ReportAllocs()
   712  			b.SetBytes(int64(len(buf0)))
   713  			for i := 0; i < b.N; i++ {
   714  				_, re, _ := Compress4X(buf0, &s)
   715  				if !re {
   716  					b.Fatal("not reused")
   717  				}
   718  			}
   719  		})
   720  	}
   721  }
   722  
   723  func BenchmarkCompress4XReusePrefer(b *testing.B) {
   724  	for _, tt := range testfiles {
   725  		test := tt
   726  		if test.err4X != nil {
   727  			continue
   728  		}
   729  		b.Run(test.name, func(b *testing.B) {
   730  			var s Scratch
   731  			s.Reuse = ReusePolicyPrefer
   732  			buf0, err := test.fn()
   733  			if err != nil {
   734  				b.Fatal(err)
   735  			}
   736  			if len(buf0) > BlockSizeMax {
   737  				buf0 = buf0[:BlockSizeMax]
   738  			}
   739  			_, _, err = Compress4X(buf0, &s)
   740  			if err != test.err4X {
   741  				b.Fatal("unexpected error:", err)
   742  			}
   743  			b.ResetTimer()
   744  			b.ReportAllocs()
   745  			b.SetBytes(int64(len(buf0)))
   746  			for i := 0; i < b.N; i++ {
   747  				_, re, _ := Compress4X(buf0, &s)
   748  				if !re {
   749  					b.Fatal("not reused")
   750  				}
   751  			}
   752  		})
   753  	}
   754  }
   755  
   756  func BenchmarkCompress1XSizes(b *testing.B) {
   757  	test := testfiles[0]
   758  	sizes := []int{1e2, 2e2, 5e2, 1e3, 5e3, 1e4, 5e4}
   759  	for _, size := range sizes {
   760  		b.Run(test.name+"-"+fmt.Sprint(size), func(b *testing.B) {
   761  			var s Scratch
   762  			s.Reuse = ReusePolicyNone
   763  			buf0, err := test.fn()
   764  			if err != nil {
   765  				b.Fatal(err)
   766  			}
   767  			buf0 = buf0[:size]
   768  			_, _, err = Compress1X(buf0, &s)
   769  			if err != test.err1X {
   770  				b.Fatal("unexpected error:", err)
   771  			}
   772  			//b.Log("Size:", len(o))
   773  			b.ResetTimer()
   774  			b.ReportAllocs()
   775  			b.SetBytes(int64(len(buf0)))
   776  			for i := 0; i < b.N; i++ {
   777  				_, re, _ := Compress1X(buf0, &s)
   778  				if re {
   779  					b.Fatal("reused")
   780  				}
   781  			}
   782  		})
   783  	}
   784  }
   785  
   786  func BenchmarkCompress4XSizes(b *testing.B) {
   787  	test := testfiles[0]
   788  	sizes := []int{1e2, 2e2, 5e2, 1e3, 5e3, 1e4, 5e4}
   789  	for _, size := range sizes {
   790  		b.Run(test.name+"-"+fmt.Sprint(size), func(b *testing.B) {
   791  			var s Scratch
   792  			s.Reuse = ReusePolicyNone
   793  			buf0, err := test.fn()
   794  			if err != nil {
   795  				b.Fatal(err)
   796  			}
   797  			buf0 = buf0[:size]
   798  			_, _, err = Compress4X(buf0, &s)
   799  			if err != test.err1X {
   800  				b.Fatal("unexpected error:", err)
   801  			}
   802  			//b.Log("Size:", len(o))
   803  			b.ResetTimer()
   804  			b.ReportAllocs()
   805  			b.SetBytes(int64(len(buf0)))
   806  			for i := 0; i < b.N; i++ {
   807  				_, re, _ := Compress4X(buf0, &s)
   808  				if re {
   809  					b.Fatal("reused")
   810  				}
   811  			}
   812  		})
   813  	}
   814  }
   815  

View as plain text