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