From d2aa5f95cce5055d71a77166a60b574cd3f8ecd5 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Wed, 25 May 2016 11:19:17 +0200 Subject: [PATCH] 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/23420 Reviewed-by: Russ Cox Run-TryBot: Marcel van Lohuizen Reviewed-by: Joe Tsai TryBot-Result: Gobot Gobot --- src/compress/flate/reader_test.go | 133 ++++++++++++++---------------- src/compress/flate/writer_test.go | 94 +++++++-------------- 2 files changed, 94 insertions(+), 133 deletions(-) diff --git a/src/compress/flate/reader_test.go b/src/compress/flate/reader_test.go index b336278c07..b0a16ce18b 100644 --- a/src/compress/flate/reader_test.go +++ b/src/compress/flate/reader_test.go @@ -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) + }) + } + } + } +} diff --git a/src/compress/flate/writer_test.go b/src/compress/flate/writer_test.go index 7967cd739c..21cd0b22ee 100644 --- a/src/compress/flate/writer_test.go +++ b/src/compress/flate/writer_test.go @@ -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. -- 2.50.0