syncthing/vendor/github.com/cznic/zappy/zappy.go
2016-09-13 22:20:22 +02:00

241 lines
13 KiB
Go

// Copyright 2014 The zappy Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the SNAPPY-GO-LICENSE file.
/*
Package zappy implements the zappy block-based compression format. It aims for
a combination of good speed and reasonable compression.
Zappy is a format incompatible, API compatible fork of snappy[1]. The C++
snappy implementation is at [2].
Reasons for the fork
The snappy compression is pretty good. Yet it has one problem built into its
format definition[3] - the maximum length of a copy "instruction" is 64 bytes.
For some specific usage patterns with long runs of repeated data, it turns out
the compression is suboptimal. For example a 1:1000 "sparseness" 64kB bit index
with only few set bits is compressed to about 3kB (about 1000 of 64B copy, 3
byte "instructions").
Format description
Zappy uses much less complicated format than snappy. Each encoded block begins
with the uvarint-encoded[4] length of the decoded data, followed by a sequence
of chunks. Chunks begin and end on byte boundaries. The chunk starts with a
varint encoded number N:
N >= 0: N+1 literal bytes follow.
N < 0: copy -N bytes, starting at offset M (in the following uvarint).
Performance issues
Compression rate is roughly the same as of snappy for the reference data set:
testdata/html: snappy 23320, zappy 22943, 0.984, orig 102400
testdata/urls.10K: snappy 334437, zappy 355163, 1.062, orig 702087
testdata/house.jpg: snappy 126711, zappy 126694, 1.000, orig 126958
testdata/mapreduce-osdi-1.pdf: snappy 77227, zappy 77646, 1.005, orig 94330
testdata/html_x_4: snappy 92350, zappy 22956, 0.249, orig 409600
testdata/cp.html: snappy 11938, zappy 12961, 1.086, orig 24603
testdata/fields.c: snappy 4825, zappy 5395, 1.118, orig 11150
testdata/grammar.lsp: snappy 1814, zappy 1933, 1.066, orig 3721
testdata/kennedy.xls: snappy 423518, zappy 440597, 1.040, orig 1029744
testdata/alice29.txt: snappy 89550, zappy 104016, 1.162, orig 152089
testdata/asyoulik.txt: snappy 79583, zappy 91345, 1.148, orig 125179
testdata/lcet10.txt: snappy 238761, zappy 275488, 1.154, orig 426754
testdata/plrabn12.txt: snappy 324567, zappy 376885, 1.161, orig 481861
testdata/ptt5: snappy 96350, zappy 91465, 0.949, orig 513216
testdata/sum: snappy 18927, zappy 20015, 1.057, orig 38240
testdata/xargs.1: snappy 2532, zappy 2793, 1.103, orig 4227
testdata/geo.protodata: snappy 23362, zappy 20759, 0.889, orig 118588
testdata/kppkn.gtb: snappy 73962, zappy 87200, 1.179, orig 184320
TOTAL: snappy 2043734, zappy 2136254, 1.045, orig 4549067
Zappy has better RLE handling (1/1000+1 non zero bytes in each index):
Sparse bit index 16 B: snappy 9, zappy 9, 1.000
Sparse bit index 32 B: snappy 10, zappy 10, 1.000
Sparse bit index 64 B: snappy 11, zappy 10, 0.909
Sparse bit index 128 B: snappy 16, zappy 14, 0.875
Sparse bit index 256 B: snappy 22, zappy 14, 0.636
Sparse bit index 512 B: snappy 36, zappy 16, 0.444
Sparse bit index 1024 B: snappy 57, zappy 18, 0.316
Sparse bit index 2048 B: snappy 111, zappy 32, 0.288
Sparse bit index 4096 B: snappy 210, zappy 31, 0.148
Sparse bit index 8192 B: snappy 419, zappy 75, 0.179
Sparse bit index 16384 B: snappy 821, zappy 138, 0.168
Sparse bit index 32768 B: snappy 1627, zappy 232, 0.143
Sparse bit index 65536 B: snappy 3243, zappy 451, 0.139
When compiled with CGO_ENABLED=1, zappy is now faster than Go snappy.
Old=Go snappy, new=zappy:
benchmark old MB/s new MB/s speedup
BenchmarkWordsDecode1e3 148.98 189.04 1.27x
BenchmarkWordsDecode1e4 150.29 182.51 1.21x
BenchmarkWordsDecode1e5 145.79 182.95 1.25x
BenchmarkWordsDecode1e6 167.43 187.69 1.12x
BenchmarkWordsEncode1e3 47.11 145.69 3.09x
BenchmarkWordsEncode1e4 81.47 136.50 1.68x
BenchmarkWordsEncode1e5 78.86 127.93 1.62x
BenchmarkWordsEncode1e6 96.81 142.95 1.48x
Benchmark_UFlat0 316.87 463.19 1.46x
Benchmark_UFlat1 231.56 350.32 1.51x
Benchmark_UFlat2 3656.68 8258.39 2.26x
Benchmark_UFlat3 892.56 1270.09 1.42x
Benchmark_UFlat4 315.84 959.08 3.04x
Benchmark_UFlat5 211.70 301.55 1.42x
Benchmark_UFlat6 211.59 258.29 1.22x
Benchmark_UFlat7 209.80 272.21 1.30x
Benchmark_UFlat8 254.59 301.70 1.19x
Benchmark_UFlat9 163.39 192.66 1.18x
Benchmark_UFlat10 155.46 189.70 1.22x
Benchmark_UFlat11 170.11 198.95 1.17x
Benchmark_UFlat12 148.32 178.78 1.21x
Benchmark_UFlat13 359.25 579.99 1.61x
Benchmark_UFlat14 197.27 291.33 1.48x
Benchmark_UFlat15 185.75 248.07 1.34x
Benchmark_UFlat16 362.74 582.66 1.61x
Benchmark_UFlat17 222.95 240.01 1.08x
Benchmark_ZFlat0 188.66 311.89 1.65x
Benchmark_ZFlat1 101.46 201.34 1.98x
Benchmark_ZFlat2 93.62 244.50 2.61x
Benchmark_ZFlat3 102.79 243.34 2.37x
Benchmark_ZFlat4 191.64 625.32 3.26x
Benchmark_ZFlat5 103.09 169.39 1.64x
Benchmark_ZFlat6 110.35 182.57 1.65x
Benchmark_ZFlat7 89.56 190.53 2.13x
Benchmark_ZFlat8 154.05 235.68 1.53x
Benchmark_ZFlat9 87.58 133.51 1.52x
Benchmark_ZFlat10 82.08 127.51 1.55x
Benchmark_ZFlat11 91.36 138.91 1.52x
Benchmark_ZFlat12 79.24 123.02 1.55x
Benchmark_ZFlat13 217.04 374.26 1.72x
Benchmark_ZFlat14 100.33 168.03 1.67x
Benchmark_ZFlat15 80.79 160.46 1.99x
Benchmark_ZFlat16 213.32 375.79 1.76x
Benchmark_ZFlat17 135.37 197.13 1.46x
The package builds with CGO_ENABLED=0 as well, but the performance is worse.
$ CGO_ENABLED=0 go test -test.run=NONE -test.bench=. > old.benchcmp
$ CGO_ENABLED=1 go test -test.run=NONE -test.bench=. > new.benchcmp
$ benchcmp old.benchcmp new.benchcmp
benchmark old ns/op new ns/op delta
BenchmarkWordsDecode1e3 9735 5288 -45.68%
BenchmarkWordsDecode1e4 100229 55369 -44.76%
BenchmarkWordsDecode1e5 1037611 546420 -47.34%
BenchmarkWordsDecode1e6 9559352 5335307 -44.19%
BenchmarkWordsEncode1e3 16206 6629 -59.10%
BenchmarkWordsEncode1e4 140283 73161 -47.85%
BenchmarkWordsEncode1e5 1476657 781756 -47.06%
BenchmarkWordsEncode1e6 12702229 6997656 -44.91%
Benchmark_UFlat0 397307 221198 -44.33%
Benchmark_UFlat1 3890483 2008341 -48.38%
Benchmark_UFlat2 35810 15398 -57.00%
Benchmark_UFlat3 140850 74194 -47.32%
Benchmark_UFlat4 814575 426783 -47.61%
Benchmark_UFlat5 156995 81473 -48.10%
Benchmark_UFlat6 77645 43161 -44.41%
Benchmark_UFlat7 25415 13579 -46.57%
Benchmark_UFlat8 6372440 3412916 -46.44%
Benchmark_UFlat9 1453679 789956 -45.66%
Benchmark_UFlat10 1243146 660747 -46.85%
Benchmark_UFlat11 3903493 2146334 -45.02%
Benchmark_UFlat12 5106250 2696144 -47.20%
Benchmark_UFlat13 1641394 884969 -46.08%
Benchmark_UFlat14 262206 131174 -49.97%
Benchmark_UFlat15 32325 17047 -47.26%
Benchmark_UFlat16 366991 204877 -44.17%
Benchmark_UFlat17 1343988 770907 -42.64%
Benchmark_ZFlat0 579954 329812 -43.13%
Benchmark_ZFlat1 6564692 3504867 -46.61%
Benchmark_ZFlat2 902029 513700 -43.05%
Benchmark_ZFlat3 678722 384312 -43.38%
Benchmark_ZFlat4 1197389 654361 -45.35%
Benchmark_ZFlat5 262677 144939 -44.82%
Benchmark_ZFlat6 111249 60876 -45.28%
Benchmark_ZFlat7 39024 19420 -50.24%
Benchmark_ZFlat8 8046106 4387928 -45.47%
Benchmark_ZFlat9 2043167 1143139 -44.05%
Benchmark_ZFlat10 1781604 980528 -44.96%
Benchmark_ZFlat11 5478647 3078585 -43.81%
Benchmark_ZFlat12 7245995 3929863 -45.77%
Benchmark_ZFlat13 2432529 1371606 -43.61%
Benchmark_ZFlat14 420315 227494 -45.88%
Benchmark_ZFlat15 52378 26564 -49.28%
Benchmark_ZFlat16 567047 316196 -44.24%
Benchmark_ZFlat17 1630820 937310 -42.53%
benchmark old MB/s new MB/s speedup
BenchmarkWordsDecode1e3 102.71 189.08 1.84x
BenchmarkWordsDecode1e4 99.77 180.60 1.81x
BenchmarkWordsDecode1e5 96.38 183.01 1.90x
BenchmarkWordsDecode1e6 104.61 187.43 1.79x
BenchmarkWordsEncode1e3 61.70 150.85 2.44x
BenchmarkWordsEncode1e4 71.28 136.68 1.92x
BenchmarkWordsEncode1e5 67.72 127.92 1.89x
BenchmarkWordsEncode1e6 78.73 142.90 1.82x
Benchmark_UFlat0 257.73 462.93 1.80x
Benchmark_UFlat1 180.46 349.59 1.94x
Benchmark_UFlat2 3545.30 8244.61 2.33x
Benchmark_UFlat3 669.72 1271.39 1.90x
Benchmark_UFlat4 502.84 959.74 1.91x
Benchmark_UFlat5 156.71 301.98 1.93x
Benchmark_UFlat6 143.60 258.33 1.80x
Benchmark_UFlat7 146.41 274.01 1.87x
Benchmark_UFlat8 161.59 301.72 1.87x
Benchmark_UFlat9 104.62 192.53 1.84x
Benchmark_UFlat10 100.70 189.45 1.88x
Benchmark_UFlat11 109.33 198.83 1.82x
Benchmark_UFlat12 94.37 178.72 1.89x
Benchmark_UFlat13 312.67 579.93 1.85x
Benchmark_UFlat14 145.84 291.52 2.00x
Benchmark_UFlat15 130.77 247.95 1.90x
Benchmark_UFlat16 323.14 578.82 1.79x
Benchmark_UFlat17 137.14 239.09 1.74x
Benchmark_ZFlat0 176.57 310.48 1.76x
Benchmark_ZFlat1 106.95 200.32 1.87x
Benchmark_ZFlat2 140.75 247.14 1.76x
Benchmark_ZFlat3 138.98 245.45 1.77x
Benchmark_ZFlat4 342.08 625.95 1.83x
Benchmark_ZFlat5 93.66 169.75 1.81x
Benchmark_ZFlat6 100.23 183.16 1.83x
Benchmark_ZFlat7 95.35 191.60 2.01x
Benchmark_ZFlat8 127.98 234.68 1.83x
Benchmark_ZFlat9 74.44 133.04 1.79x
Benchmark_ZFlat10 70.26 127.66 1.82x
Benchmark_ZFlat11 77.89 138.62 1.78x
Benchmark_ZFlat12 66.50 122.62 1.84x
Benchmark_ZFlat13 210.98 374.17 1.77x
Benchmark_ZFlat14 90.98 168.09 1.85x
Benchmark_ZFlat15 80.70 159.12 1.97x
Benchmark_ZFlat16 209.13 375.04 1.79x
Benchmark_ZFlat17 113.02 196.65 1.74x
$
Build tags
If a constraint 'purego' appears in the build constraints [5] then a pure Go
version is built regardless of the $CGO_ENABLED value.
$ touch zappy.go ; go install -tags purego github.com/cznic/zappy # for example
Information sources
... referenced from the above documentation.
[1]: http://github.com/golang/snappy
[2]: http://code.google.com/p/snappy/
[3]: http://code.google.com/p/snappy/source/browse/trunk/format_description.txt
[4]: http://golang.org/pkg/encoding/binary/
[5]: http://golang.org/pkg/go/build/#hdr-Build_Constraints
*/
package zappy