compress_test.go 20 KB

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