Commit d2aa5f95 authored by Marcel van Lohuizen's avatar Marcel van Lohuizen

compress/flate: simplify using subtests and sub-benchmarks

This causes the large files to be loaded only once per benchmark.

This CL also serves as an example use case of sub(tests|-benchmarks).

This CL ensures that names are identical to the original
except for an added slashes. Things could be
simplified further if this restriction were dropped.

Change-Id: I45e303e158e3152e33d0d751adfef784713bf997
Reviewed-on: https://go-review.googlesource.com/23420Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: 's avatarJoe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 89283781
......@@ -22,82 +22,77 @@ func TestNlitOutOfRange(t *testing.T) {
"\x75\xc4\xf8\x0f\x12\x11\xb9\xb4\x4b\x09\xa0\xbe\x8b\x91\x4c")))
}
const (
digits = iota
twain
)
var testfiles = []string{
var suites = []struct{ name, file string }{
// Digits is the digits of the irrational number e. Its decimal representation
// does not repeat, but there are only 10 possible digits, so it should be
// reasonably compressible.
digits: "../testdata/e.txt",
{"Digits", "../testdata/e.txt"},
// Twain is Mark Twain's classic English novel.
twain: "../testdata/Mark.Twain-Tom.Sawyer.txt",
{"Twain", "../testdata/Mark.Twain-Tom.Sawyer.txt"},
}
func benchmarkDecode(b *testing.B, testfile, level, n int) {
b.ReportAllocs()
b.StopTimer()
b.SetBytes(int64(n))
buf0, err := ioutil.ReadFile(testfiles[testfile])
if err != nil {
b.Fatal(err)
}
if len(buf0) == 0 {
b.Fatalf("test file %q has no data", testfiles[testfile])
}
compressed := new(bytes.Buffer)
w, err := NewWriter(compressed, level)
if err != nil {
b.Fatal(err)
}
for i := 0; i < n; i += len(buf0) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
func BenchmarkDecode(b *testing.B) {
doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
b.ReportAllocs()
b.StopTimer()
b.SetBytes(int64(n))
compressed := new(bytes.Buffer)
w, err := NewWriter(compressed, level)
if err != nil {
b.Fatal(err)
}
io.Copy(w, bytes.NewReader(buf0))
}
w.Close()
buf1 := compressed.Bytes()
buf0, compressed, w = nil, nil, nil
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
}
for i := 0; i < n; i += len(buf0) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
}
io.Copy(w, bytes.NewReader(buf0))
}
w.Close()
buf1 := compressed.Bytes()
buf0, compressed, w = nil, nil, nil
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
}
})
}
// These short names are so that gofmt doesn't break the BenchmarkXxx function
// bodies below over multiple lines.
const (
speed = BestSpeed
default_ = DefaultCompression
compress = BestCompression
huffman = HuffmanOnly
)
var levelTests = []struct {
name string
level int
}{
{"Huffman", HuffmanOnly},
{"Speed", BestSpeed},
{"Default", DefaultCompression},
{"Compression", BestCompression},
}
func BenchmarkDecodeDigitsHuffman1e4(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e4) }
func BenchmarkDecodeDigitsHuffman1e5(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e5) }
func BenchmarkDecodeDigitsHuffman1e6(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e6) }
func BenchmarkDecodeDigitsSpeed1e4(b *testing.B) { benchmarkDecode(b, digits, speed, 1e4) }
func BenchmarkDecodeDigitsSpeed1e5(b *testing.B) { benchmarkDecode(b, digits, speed, 1e5) }
func BenchmarkDecodeDigitsSpeed1e6(b *testing.B) { benchmarkDecode(b, digits, speed, 1e6) }
func BenchmarkDecodeDigitsDefault1e4(b *testing.B) { benchmarkDecode(b, digits, default_, 1e4) }
func BenchmarkDecodeDigitsDefault1e5(b *testing.B) { benchmarkDecode(b, digits, default_, 1e5) }
func BenchmarkDecodeDigitsDefault1e6(b *testing.B) { benchmarkDecode(b, digits, default_, 1e6) }
func BenchmarkDecodeDigitsCompress1e4(b *testing.B) { benchmarkDecode(b, digits, compress, 1e4) }
func BenchmarkDecodeDigitsCompress1e5(b *testing.B) { benchmarkDecode(b, digits, compress, 1e5) }
func BenchmarkDecodeDigitsCompress1e6(b *testing.B) { benchmarkDecode(b, digits, compress, 1e6) }
func BenchmarkDecodeTwainHuffman1e4(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e4) }
func BenchmarkDecodeTwainHuffman1e5(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e5) }
func BenchmarkDecodeTwainHuffman1e6(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e6) }
func BenchmarkDecodeTwainSpeed1e4(b *testing.B) { benchmarkDecode(b, twain, speed, 1e4) }
func BenchmarkDecodeTwainSpeed1e5(b *testing.B) { benchmarkDecode(b, twain, speed, 1e5) }
func BenchmarkDecodeTwainSpeed1e6(b *testing.B) { benchmarkDecode(b, twain, speed, 1e6) }
func BenchmarkDecodeTwainDefault1e4(b *testing.B) { benchmarkDecode(b, twain, default_, 1e4) }
func BenchmarkDecodeTwainDefault1e5(b *testing.B) { benchmarkDecode(b, twain, default_, 1e5) }
func BenchmarkDecodeTwainDefault1e6(b *testing.B) { benchmarkDecode(b, twain, default_, 1e6) }
func BenchmarkDecodeTwainCompress1e4(b *testing.B) { benchmarkDecode(b, twain, compress, 1e4) }
func BenchmarkDecodeTwainCompress1e5(b *testing.B) { benchmarkDecode(b, twain, compress, 1e5) }
func BenchmarkDecodeTwainCompress1e6(b *testing.B) { benchmarkDecode(b, twain, compress, 1e6) }
var sizes = []struct {
name string
n int
}{
{"1e4", 1e4},
{"1e5", 1e5},
{"1e6", 1e6},
}
func doBench(b *testing.B, f func(b *testing.B, buf []byte, level, n int)) {
for _, suite := range suites {
buf, err := ioutil.ReadFile(suite.file)
if err != nil {
b.Fatal(err)
}
if len(buf) == 0 {
b.Fatalf("test file %q has no data", suite.file)
}
for _, l := range levelTests {
for _, s := range sizes {
b.Run(suite.name+"/"+l.name+"/"+s.name, func(b *testing.B) {
f(b, buf, l.level, s.n)
})
}
}
}
}
......@@ -14,62 +14,33 @@ import (
"testing"
)
func benchmarkEncoder(b *testing.B, testfile, level, n int) {
b.StopTimer()
b.SetBytes(int64(n))
buf0, err := ioutil.ReadFile(testfiles[testfile])
if err != nil {
b.Fatal(err)
}
if len(buf0) == 0 {
b.Fatalf("test file %q has no data", testfiles[testfile])
}
buf1 := make([]byte, n)
for i := 0; i < n; i += len(buf0) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
func BenchmarkEncode(b *testing.B) {
doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
b.StopTimer()
b.SetBytes(int64(n))
buf1 := make([]byte, n)
for i := 0; i < n; i += len(buf0) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
}
copy(buf1[i:], buf0)
}
copy(buf1[i:], buf0)
}
buf0 = nil
w, err := NewWriter(ioutil.Discard, level)
if err != nil {
b.Fatal(err)
}
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
w.Reset(ioutil.Discard)
w.Write(buf1)
w.Close()
}
buf0 = nil
w, err := NewWriter(ioutil.Discard, level)
if err != nil {
b.Fatal(err)
}
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
w.Reset(ioutil.Discard)
w.Write(buf1)
w.Close()
}
})
}
func BenchmarkEncodeDigitsHuffman1e4(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e4) }
func BenchmarkEncodeDigitsHuffman1e5(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e5) }
func BenchmarkEncodeDigitsHuffman1e6(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e6) }
func BenchmarkEncodeDigitsSpeed1e4(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e4) }
func BenchmarkEncodeDigitsSpeed1e5(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e5) }
func BenchmarkEncodeDigitsSpeed1e6(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e6) }
func BenchmarkEncodeDigitsDefault1e4(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e4) }
func BenchmarkEncodeDigitsDefault1e5(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e5) }
func BenchmarkEncodeDigitsDefault1e6(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e6) }
func BenchmarkEncodeDigitsCompress1e4(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e4) }
func BenchmarkEncodeDigitsCompress1e5(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e5) }
func BenchmarkEncodeDigitsCompress1e6(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e6) }
func BenchmarkEncodeTwainHuffman1e4(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e4) }
func BenchmarkEncodeTwainHuffman1e5(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e5) }
func BenchmarkEncodeTwainHuffman1e6(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e6) }
func BenchmarkEncodeTwainSpeed1e4(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e4) }
func BenchmarkEncodeTwainSpeed1e5(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e5) }
func BenchmarkEncodeTwainSpeed1e6(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e6) }
func BenchmarkEncodeTwainDefault1e4(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e4) }
func BenchmarkEncodeTwainDefault1e5(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e5) }
func BenchmarkEncodeTwainDefault1e6(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e6) }
func BenchmarkEncodeTwainCompress1e4(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e4) }
func BenchmarkEncodeTwainCompress1e5(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e5) }
func BenchmarkEncodeTwainCompress1e6(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e6) }
// errorWriter is a writer that fails after N writes.
type errorWriter struct {
N int
......@@ -141,17 +112,12 @@ func TestWriteError(t *testing.T) {
// Test if two runs produce identical results
// even when writing different sizes to the Writer.
func TestDeterministicL0(t *testing.T) { testDeterministic(0, t) }
func TestDeterministicL1(t *testing.T) { testDeterministic(1, t) }
func TestDeterministicL2(t *testing.T) { testDeterministic(2, t) }
func TestDeterministicL3(t *testing.T) { testDeterministic(3, t) }
func TestDeterministicL4(t *testing.T) { testDeterministic(4, t) }
func TestDeterministicL5(t *testing.T) { testDeterministic(5, t) }
func TestDeterministicL6(t *testing.T) { testDeterministic(6, t) }
func TestDeterministicL7(t *testing.T) { testDeterministic(7, t) }
func TestDeterministicL8(t *testing.T) { testDeterministic(8, t) }
func TestDeterministicL9(t *testing.T) { testDeterministic(9, t) }
func TestDeterministicLM2(t *testing.T) { testDeterministic(-2, t) }
func TestDeterministic(t *testing.T) {
for i := 0; i <= 9; i++ {
t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) })
}
t.Run("LM2", func(t *testing.T) { testDeterministic(-2, t) })
}
func testDeterministic(i int, t *testing.T) {
// Test so much we cross a good number of block boundaries.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment