1 /*
2     RawSpeed - RAW file decoder.
3 
4     Copyright (C) 2017 Roman Lebedev
5 
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10 
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Lesser General Public License for more details.
15 
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 #include "decompressors/DeflateDecompressor.h" // for DeflateDecompressor
22 #include "bench/Common.h"                      // for areaToRectangle
23 #include "common/Common.h"                     // for isAligned
24 #include "common/Memory.h"                     // for alignedFree
25 #include "common/Point.h"                      // for iPoint2D
26 #include "common/RawImage.h"                   // for RawImage, RawImageData
27 #include "io/Buffer.h"                         // for Buffer, Buffer::size_...
28 #include "io/ByteStream.h"                     // for ByteStream
29 #include "io/Endianness.h"                     // for Endianness, Endiannes...
30 #include <benchmark/benchmark.h>               // for State, Benchmark, BEN...
31 #include <cassert>                             // for assert
32 #include <cstddef>                             // for size_t
33 #include <cstdint>                             // for uint8_t
34 #include <memory>                              // for operator!=, unique_ptr
35 #include <type_traits>                         // for integral_constant
36 #include <utility>                             // for move
37 #include <zlib.h>                              // for compressBound, compress
38 
39 #ifndef NDEBUG
40 #include <limits> // for numeric_limits
41 #endif
42 
43 using rawspeed::Buffer;
44 using rawspeed::DeflateDecompressor;
45 
46 template <size_t N> using BPS = std::integral_constant<size_t, N>;
47 template <int N> using Pf = std::integral_constant<int, N>;
48 
49 template <typename BPS>
50 static std::unique_ptr<uint8_t, decltype(&rawspeed::alignedFree)>
compressChunk(const rawspeed::RawImage & mRaw,uLong * bufSize)51 compressChunk(const rawspeed::RawImage& mRaw, uLong* bufSize) {
52   static_assert(BPS::value > 0, "bad bps");
53   static_assert(rawspeed::isAligned(BPS::value, 8), "not byte count");
54 
55   const uLong uncompressedLength = BPS::value * mRaw->dim.x * mRaw->dim.y / 8UL;
56   assert(uncompressedLength > 0);
57   assert(uncompressedLength <= std::numeric_limits<Buffer::size_type>::max());
58 
59   *bufSize = compressBound(uncompressedLength);
60   assert(*bufSize > 0);
61   assert(*bufSize <= std::numeric_limits<Buffer::size_type>::max());
62 
63   // will contain some random garbage
64   auto uBuf = Buffer::Create(uncompressedLength);
65   assert(uBuf != nullptr);
66 
67   auto cBuf = Buffer::Create(*bufSize);
68   assert(cBuf != nullptr);
69 
70   const int err = compress(cBuf.get(), bufSize, uBuf.get(), uncompressedLength);
71   if (err != Z_OK)
72     throw;
73 
74   assert(compressBound(uncompressedLength) >= *bufSize);
75 
76   return cBuf;
77 }
78 
79 template <typename BPS, typename Pf>
BM_DeflateDecompressor(benchmark::State & state)80 static inline void BM_DeflateDecompressor(benchmark::State& state) {
81   static_assert(BPS::value > 0, "bad bps");
82   static_assert(rawspeed::isAligned(BPS::value, 8), "not byte count");
83 
84   const auto dim = areaToRectangle(state.range(0));
85   auto mRaw = rawspeed::RawImage::create(dim, rawspeed::TYPE_FLOAT32, 1);
86 
87   uLong cBufSize;
88   auto cBuf = compressChunk<BPS>(mRaw, &cBufSize);
89   assert(cBuf != nullptr);
90   assert(cBufSize > 0);
91 
92   Buffer buf(std::move(cBuf), cBufSize);
93   assert(buf.getSize() == cBufSize);
94 
95   int predictor = 0;
96   switch (Pf::value) {
97   case 0:
98     predictor = 0;
99     break;
100   case 1:
101     predictor = 3;
102     break;
103   case 2:
104     predictor = 34894;
105     break;
106   case 4:
107     predictor = 34895;
108     break;
109   default:
110     __builtin_unreachable();
111     break;
112   }
113 
114   std::unique_ptr<unsigned char[]> uBuffer; // NOLINT
115 
116   const rawspeed::ByteStream bs(
117       rawspeed::DataBuffer(buf, rawspeed::Endianness::little));
118 
119   for (auto _ : state) {
120     DeflateDecompressor d(bs, mRaw, predictor, BPS::value);
121 
122     d.decode(&uBuffer, mRaw->dim, mRaw->dim, {0, 0});
123   }
124 
125   state.SetComplexityN(dim.area());
126   state.SetItemsProcessed(state.complexity_length_n() * state.iterations());
127   state.SetBytesProcessed(BPS::value * state.items_processed() / 8);
128 }
129 
CustomArgs(benchmark::internal::Benchmark * b)130 static inline void CustomArgs(benchmark::internal::Benchmark* b) {
131   b->RangeMultiplier(2);
132 // FIXME: appears to not like 1GPix+ buffers
133 #if 1
134   b->Arg(128 << 20);
135 #else
136   b->Range(1, 1023 << 20)->Complexity(benchmark::oN);
137 #endif
138   b->Unit(benchmark::kMillisecond);
139 }
140 
141 #define GEN_E(s, f)                                                            \
142   BENCHMARK_TEMPLATE(BM_DeflateDecompressor, BPS<s>, Pf<f>)->Apply(CustomArgs);
143 #define GEN_PFS(s) GEN_E(s, 0) GEN_E(s, 1) GEN_E(s, 2) GEN_E(s, 4)
144 #define GEN_PSS() GEN_PFS(16) GEN_PFS(24) GEN_PFS(32)
145 
146 GEN_PSS()
147 
148 BENCHMARK_MAIN();
149