FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
adaptive_lorenzo_stage.h
Go to the documentation of this file.
1#pragma once
2
8#include "stage/stage.h"
9#include "fzm_format.h"
10#include "backend/types.h"
11#include <algorithm>
12#include <array>
13#include <cstdint>
14#include <cstring>
15#include <stdexcept>
16#include <string>
17#include <type_traits>
18#include <unordered_map>
19#include <vector>
20
21namespace fz {
22
38static_assert(sizeof(AdaptiveLorenzoConfig) <= FZM_STAGE_CONFIG_SIZE,
39 "AdaptiveLorenzoConfig must fit in FZM_STAGE_CONFIG_SIZE");
40
94template<typename T>
96 static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
97 "AdaptiveLorenzoStage requires a signed integer type");
98public:
99 struct Config {
104 uint32_t coder_block_size = 32;
109 uint32_t blocks_per_tile = 8;
110 bool enable_order2 = true;
111 bool enable_centering = true;
112 Config() = default;
113 };
114
115 AdaptiveLorenzoStage() { validate(); }
116 explicit AdaptiveLorenzoStage(const Config& config) : config_(config) { validate(); }
117
118 void setInverse(bool inv) override { is_inverse_ = inv; }
119 bool isInverse() const override { return is_inverse_; }
120
121 uint32_t getTileSize() const {
122 return config_.coder_block_size * config_.blocks_per_tile;
123 }
124
126 fz::stream_t stream,
127 MemoryPool* pool,
128 const std::vector<void*>& inputs,
129 const std::vector<void*>& outputs,
130 const std::vector<size_t>& sizes
131 ) override;
132
133 std::string getName() const override { return "AdaptiveLorenzo"; }
134 size_t getNumInputs() const override { return is_inverse_ ? 3 : 1; }
135 size_t getNumOutputs() const override { return is_inverse_ ? 1 : 3; }
136
137 std::vector<std::string> getOutputNames() const override {
138 return {"output", "modes", "means"};
139 }
140
141 ~AdaptiveLorenzoStage() override { releaseScratch(); }
142
146 void postStreamSync(fz::stream_t stream) override;
147
150 bool isGraphCompatible() const override { return false; }
151
154 const std::vector<size_t>& input_sizes
155 ) const override;
156
157 std::vector<size_t> estimateOutputSizes(
158 const std::vector<size_t>& input_sizes
159 ) const override {
160 if (input_sizes.empty()) return {0, 0, 0};
161 if (is_inverse_) return {input_sizes[0]};
162 const size_t n = input_sizes[0] / sizeof(T);
163 const size_t tiles = numTiles(n);
164 // modes: 2 bits per tile. means: worst case one per tile — the real
165 // length is trimmed in postStreamSync() once the scan total is known.
166 return {input_sizes[0], (tiles + 3) / 4, tiles * sizeof(T)};
167 }
168
169 void saveState() override { saved_output_sizes_ = actual_output_sizes_; }
170 void restoreState() override {
171 if (!saved_output_sizes_.empty()) actual_output_sizes_ = saved_output_sizes_;
172 }
173
174 std::unordered_map<std::string, size_t>
175 getActualOutputSizesByName() const override {
176 auto names = getOutputNames();
177 std::unordered_map<std::string, size_t> r;
178 for (size_t i = 0; i < names.size() && i < actual_output_sizes_.size(); ++i)
179 r[names[i]] = actual_output_sizes_[i];
180 return r;
181 }
182
183 size_t getActualOutputSize(int index) const override {
184 return (index >= 0 && index < static_cast<int>(actual_output_sizes_.size()))
185 ? actual_output_sizes_[index] : 0;
186 }
187
188 uint16_t getStageTypeId() const override {
189 return static_cast<uint16_t>(StageType::ADAPTIVE_LORENZO);
190 }
191
192 uint8_t getOutputDataType(size_t output_index) const override {
193 // The mode map is a byte stream; the residuals and means are T.
194 return static_cast<uint8_t>(output_index == 1 ? DataType::UINT8
195 : getElementDataType());
196 }
197 uint8_t getInputDataType(size_t input_index) const override {
198 return static_cast<uint8_t>(input_index == 1 ? DataType::UINT8
199 : getElementDataType());
200 }
201
202 size_t serializeHeader(size_t /*output_index*/, uint8_t* buf, size_t max_size) const override {
203 if (max_size < sizeof(AdaptiveLorenzoConfig))
204 throw std::runtime_error("AdaptiveLorenzoStage: header buffer too small");
206 cfg.data_type = getElementDataType();
207 cfg.coder_block_size = static_cast<uint8_t>(config_.coder_block_size);
208 cfg.blocks_per_tile = static_cast<uint8_t>(config_.blocks_per_tile);
209 cfg.enable_order2 = config_.enable_order2 ? 1u : 0u;
210 cfg.enable_centering = config_.enable_centering ? 1u : 0u;
211 cfg.num_elements = static_cast<uint32_t>(num_elements_);
212 std::memcpy(buf, &cfg, sizeof(cfg));
213 return sizeof(cfg);
214 }
215
216 void deserializeHeader(const uint8_t* buf, size_t size) override {
217 if (size < sizeof(AdaptiveLorenzoConfig))
218 throw std::runtime_error("AdaptiveLorenzoStage: header too small");
220 std::memcpy(&cfg, buf, sizeof(cfg));
221 config_.coder_block_size = cfg.coder_block_size;
222 config_.blocks_per_tile = cfg.blocks_per_tile;
223 config_.enable_order2 = (cfg.enable_order2 != 0);
224 config_.enable_centering = (cfg.enable_centering != 0);
225 num_elements_ = cfg.num_elements;
226 validate();
227 }
228
229 size_t getMaxHeaderSize(size_t /*output_index*/) const override {
230 return sizeof(AdaptiveLorenzoConfig);
231 }
232
233private:
234 Config config_;
235 bool is_inverse_ = false;
236 size_t num_elements_ = 0;
237 std::vector<size_t> actual_output_sizes_{0, 0, 0};
238 std::vector<size_t> saved_output_sizes_;
239
240 // Persistent compaction scratch, grown when a larger input is seen. Held
241 // across calls so postStreamSync() can read the scan total after the fact.
242 uint8_t* d_modes_dense_ = nullptr;
243 T* d_means_dense_ = nullptr;
244 uint32_t* d_flags_ = nullptr;
245 uint32_t* d_offsets_ = nullptr;
246 size_t scratch_tiles_ = 0;
247 MemoryPool* scratch_pool_ = nullptr;
248 size_t pending_tiles_ = 0;
249
250 size_t ensureScratch(size_t num_tiles, MemoryPool* pool, fz::stream_t stream);
251 void releaseScratch();
252
253 size_t numTiles(size_t n) const {
254 const size_t t = getTileSize();
255 return (n + t - 1) / t;
256 }
257
258 void validate() const {
259 if (config_.coder_block_size != 32)
260 throw std::invalid_argument(
261 "AdaptiveLorenzoStage: coder_block_size must be 32 (the cost model "
262 "and the per-block warp reduction both assume a 32-element block)");
263 if (config_.blocks_per_tile < 1 || config_.blocks_per_tile > 32)
264 throw std::invalid_argument(
265 "AdaptiveLorenzoStage: blocks_per_tile must be in [1, 32] so the "
266 "tile fits one CUDA block, got "
267 + std::to_string(config_.blocks_per_tile));
268 }
269
270 static DataType getElementDataType() {
271 if (std::is_same<T, int8_t>::value) return DataType::INT8;
272 if (std::is_same<T, int16_t>::value) return DataType::INT16;
273 if (std::is_same<T, int32_t>::value) return DataType::INT32;
274 if (std::is_same<T, int64_t>::value) return DataType::INT64;
275 return DataType::INT32;
276 }
277};
278
279extern template class AdaptiveLorenzoStage<int16_t>;
280extern template class AdaptiveLorenzoStage<int32_t>;
281
283template<typename T>
285 const T* d_input, T* d_residuals, uint8_t* d_modes, T* d_means,
286 size_t n, uint32_t tile_size, bool enable_order2, bool enable_centering,
287 fz::stream_t stream);
288
290template<typename T>
292 const T* d_residuals, const uint8_t* d_modes, const T* d_means, T* d_output,
293 size_t n, uint32_t tile_size, fz::stream_t stream);
294
295} // namespace fz
Definition adaptive_lorenzo_stage.h:95
uint16_t getStageTypeId() const override
Definition adaptive_lorenzo_stage.h:188
uint8_t getInputDataType(size_t input_index) const override
Definition adaptive_lorenzo_stage.h:197
size_t estimateScratchBytes(const std::vector< size_t > &input_sizes) const override
Defined in the .cu — sizing the CUB scan temp needs a CUDA translation unit.
size_t serializeHeader(size_t, uint8_t *buf, size_t max_size) const override
Definition adaptive_lorenzo_stage.h:202
size_t getMaxHeaderSize(size_t) const override
Definition adaptive_lorenzo_stage.h:229
bool isGraphCompatible() const override
Definition adaptive_lorenzo_stage.h:150
std::unordered_map< std::string, size_t > getActualOutputSizesByName() const override
Definition adaptive_lorenzo_stage.h:175
void setInverse(bool inv) override
Definition adaptive_lorenzo_stage.h:118
void deserializeHeader(const uint8_t *buf, size_t size) override
Definition adaptive_lorenzo_stage.h:216
std::string getName() const override
Definition adaptive_lorenzo_stage.h:133
uint8_t getOutputDataType(size_t output_index) const override
Definition adaptive_lorenzo_stage.h:192
std::vector< std::string > getOutputNames() const override
Definition adaptive_lorenzo_stage.h:137
void execute(fz::stream_t stream, MemoryPool *pool, const std::vector< void * > &inputs, const std::vector< void * > &outputs, const std::vector< size_t > &sizes) override
size_t getActualOutputSize(int index) const override
Definition adaptive_lorenzo_stage.h:183
void postStreamSync(fz::stream_t stream) override
void saveState() override
Definition adaptive_lorenzo_stage.h:169
std::vector< size_t > estimateOutputSizes(const std::vector< size_t > &input_sizes) const override
Definition adaptive_lorenzo_stage.h:157
Definition mempool.h:82
Definition stage.h:30
FZM binary file format definitions — structs, enums, and helpers.
Definition algorithms.h:48
constexpr size_t FZM_STAGE_CONFIG_SIZE
Per-stage serialized config slot (bytes)
Definition fzm_format.h:65
@ ADAPTIVE_LORENZO
Per-tile adaptive multi-order Lorenzo + centering (FSZ prediction stage)
DataType
Element data type identifiers used in buffer and stage descriptors.
Definition fzm_format.h:117
void launchAdaptiveLorenzoForward(const T *d_input, T *d_residuals, uint8_t *d_modes, T *d_means, size_t n, uint32_t tile_size, bool enable_order2, bool enable_centering, fz::stream_t stream)
Forward: select the best variant per tile and emit its residuals.
void launchAdaptiveLorenzoInverse(const T *d_residuals, const uint8_t *d_modes, const T *d_means, T *d_output, size_t n, uint32_t tile_size, fz::stream_t stream)
Inverse: replay each tile's recorded variant.
Base class interface for all compression stages.
Serialized config stored in FZMBufferEntry.stage_config.
Definition adaptive_lorenzo_stage.h:24
uint8_t reserved[3]
Must be zero.
Definition adaptive_lorenzo_stage.h:30
uint8_t enable_order2
1 if LZ2 is a candidate variant.
Definition adaptive_lorenzo_stage.h:28
uint8_t blocks_per_tile
Coder blocks per adaptation tile.
Definition adaptive_lorenzo_stage.h:27
DataType data_type
Signed integer element type (1B).
Definition adaptive_lorenzo_stage.h:25
uint8_t coder_block_size
Downstream coder's block size (fixed at 32).
Definition adaptive_lorenzo_stage.h:26
uint8_t enable_centering
1 if centering is a candidate variant.
Definition adaptive_lorenzo_stage.h:29
uint32_t num_elements
Element count (for tile-count recovery).
Definition adaptive_lorenzo_stage.h:31
Backend-neutral GPU type aliases.