FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
compressor.h
Go to the documentation of this file.
1
5#pragma once
6
7#include "backend/types.h"
8#include "advanced/dag.h"
10#include "pipeline/perf.h"
11#include "pipeline/config.h"
12#include "stage/stage.h"
13#include "stage/stage_factory.h"
14#include "mem/mempool.h"
15#include "fzm_format.h"
16
17#include <array>
18#include <memory>
19#include <stdexcept>
20#include <string>
21#include <unordered_map>
22#include <vector>
23
24namespace fz {
25
62enum class SpecializationPolicy { Off, Auto, Force };
63
67
70 std::string implementation;
71 std::vector<std::string> stages;
72 std::string execution_path;
73};
75
78 SpecializationPolicy policy = SpecializationPolicy::Off;
79 size_t legal_group_count = 0;
80 std::vector<SpecializationGroupInfo> installed_groups;
82 std::vector<SpecializationGroupInfo> installed_inverse_groups;
84 std::string fallback_reason;
85};
87
88class Pipeline {
89public:
95 explicit Pipeline(
96 size_t input_data_size = 0,
98 float pool_multiplier = 3.0f
99 );
100
108 explicit Pipeline(const std::string& config_path);
109
110 ~Pipeline();
111
112 // ── Configuration ─────────────────────────────────────────────────────────
113
115 void setMemoryStrategy(MemoryStrategy strategy);
116
118 void setSpecializationPolicy(SpecializationPolicy mode) { fusion_policy_ = mode; }
119 SpecializationPolicy getSpecializationPolicy() const { return fusion_policy_; }
121 size_t getSpecializedGroupCount() const { return dag_ ? dag_->getFusedGroupCount() : 0; }
123 const SpecializationInfo& getSpecializationInfo() const { return fusion_info_; }
124
126 void setFusionPolicy(SpecializationPolicy mode) { setSpecializationPolicy(mode); }
127 SpecializationPolicy getFusionPolicy() const { return getSpecializationPolicy(); }
128 size_t getFusedGroupCount() const { return getSpecializedGroupCount(); }
129 const SpecializationInfo& getFusionInfo() const { return fusion_info_; }
130
132 void setNumStreams(int num_streams);
133
140 void setDims(size_t x, size_t y = 1, size_t z = 1) { dims_ = {x, y, z}; }
141 void setDims(std::array<size_t, 3> dims) { dims_ = dims; }
142 std::array<size_t, 3> getDims() const { return dims_; }
143
144 // ── Builder API ───────────────────────────────────────────────────────────
145
150 template<typename StageT, typename... Args>
151 StageT* addStage(Args&&... args);
152
160 int connect(Stage* dependent, Stage* producer, const std::string& output_name = "output");
161
163 int connect(Stage* dependent, const std::vector<Stage*>& producers);
164
188 void bindExternalInput(Stage* stage);
189
195 void finalize();
196
202 void warmup(fz::stream_t stream = 0);
203
205 void setWarmupOnFinalize(bool enable) { warmup_on_finalize_ = enable; }
206 bool isWarmupOnFinalizeEnabled() const { return warmup_on_finalize_; }
207
214 void setPoolManagedDecompOutput(bool enable) { pool_managed_decomp_ = enable; }
215 bool isPoolManagedDecompOutput() const { return pool_managed_decomp_; }
216
249 void setPrimarySource(Stage* stage) { primary_source_stage_ = stage; }
250
264 size_t getMaxCompressedSize(size_t input_bytes) const;
265
285 size_t getLastUncompressedSize() const {
286 return original_input_size_ > 0 ? original_input_size_ : input_size_;
287 }
288
289 // ── Execution ─────────────────────────────────────────────────────────────
290
302 void compress(
303 const void* d_input,
304 size_t input_size,
305 void** d_output,
306 size_t* output_size,
307 fz::stream_t stream = 0
308 );
309
336 void compress(
337 const void* d_input,
338 size_t input_size,
339 void* d_output_buf,
340 size_t output_buf_capacity,
341 size_t* actual_output_size,
342 fz::stream_t stream = 0
343 );
344
359 void decompress(
360 const void* d_input,
361 size_t input_size,
362 void** d_output,
363 size_t* output_size,
364 fz::stream_t stream = 0
365 );
366
387 void decompress(
388 const void* d_input,
389 size_t input_size,
390 void* d_output_buf,
391 size_t output_buf_capacity,
392 size_t* actual_output_size,
393 fz::stream_t stream = 0
394 );
395
433 void decompressInto(
434 const void* d_input,
435 size_t input_size,
436 void* d_output_buf,
437 size_t output_buf_capacity,
438 size_t* actual_output_size,
439 fz::stream_t stream = 0
440 );
441
442 // ── Explicit-ownership execution API ──────────────────────────────────────
443 //
444 // Span-based wrappers over the pointer overloads above. Behavior is
445 // identical — these exist so ownership is visible in the signature instead
446 // of depending on `void**` vs `void*` and on setPoolManagedDecompOutput().
447 // Prefer these in new code; the pointer overloads remain supported.
448
454 BorrowedDeviceBuffer compress(ConstDeviceSpan input, fz::stream_t stream = 0);
455
461 size_t compressInto(ConstDeviceSpan input, DeviceSpan output, fz::stream_t stream = 0);
462
471 BorrowedDeviceBuffer decompressBorrowed(ConstDeviceSpan input, fz::stream_t stream = 0);
472
478 OwnedDeviceBuffer decompressOwned(ConstDeviceSpan input, fz::stream_t stream = 0);
479
485 size_t decompressInto(ConstDeviceSpan input, DeviceSpan output, fz::stream_t stream = 0);
486
493 size_t decompressIntoAsync(ConstDeviceSpan input, DeviceSpan output, fz::stream_t stream = 0);
494
519 void prepareInverse(size_t uncompressed_size);
520
522 void reset(fz::stream_t stream = 0);
523
524 // ── Profiling ─────────────────────────────────────────────────────────────
525
530 void enableProfiling(bool enable);
531 bool isProfilingEnabled() const { return profiling_enabled_; }
532
534 const PipelinePerfResult& getLastPerfResult() const { return last_perf_result_; }
535
537 CompressionDAG* getDAG() { return dag_.get(); }
538
540 size_t getPoolThreshold() const;
541
551 bool isMemPoolFallbackMode() const;
552
558 void enableBoundsCheck(bool enable) { dag_->enableBoundsCheck(enable); }
559 bool isBoundsCheckEnabled() const { return dag_->isBoundsCheckEnabled(); }
560
566 void setColoringEnabled(bool enable) {
567 coloring_enabled_ = enable; // survives a setMemoryStrategy() DAG swap
568 dag_->setColoringEnabled(enable);
569 }
570 bool isColoringEnabled() const { return dag_->isColoringEnabled(); }
571 size_t getColorRegionCount() const { return dag_->getColorRegionCount(); }
572
580 bool isColoringRequested() const { return coloring_enabled_; }
581
591 std::unordered_map<std::string, std::vector<std::string>> collectRunNotes() const {
592 std::unordered_map<std::string, std::vector<std::string>> notes;
593 for (const auto& s : stages_) {
594 if (!s) continue;
595 auto n = s->getRunNotes();
596 if (!n.empty()) notes.emplace(s->getName(), std::move(n));
597 }
598 return notes;
599 }
600
601 // ── CUDA Graph Capture (compression-only) ─────────────────────────────────
602
610 void enableGraphMode(bool enable);
611 bool isGraphModeEnabled() const { return graph_mode_enabled_; }
612
623 void captureGraph(fz::stream_t stream = 0);
624 bool isGraphCaptured() const { return graph_captured_; }
625
626 size_t getPeakMemoryUsage() const;
627 size_t getCurrentMemoryUsage() const;
628 void printPipeline() const;
629
630 // ── File Serialization ────────────────────────────────────────────────────
631
634 FZMHeaderCore core;
635 std::vector<FZMStageInfo> stages;
636 std::vector<FZMBufferEntry> buffers;
637 };
638
640 void writeToFile(const std::string& filename, fz::stream_t stream = 0);
641
643 static FZMFileHeader readHeader(const std::string& filename);
644
646 FZMFileHeader buildHeader() const;
647
648 // ── In-memory metadata header (decode without a prior compress) ────────────
649
664 std::vector<uint8_t> serializeHeaderToMemory() const;
665
685 void primeInverseFromHeader(const void* header_bytes, size_t header_size);
686
701 static void decompressFromFile(
702 const std::string& filename,
703 void** d_output,
704 size_t* output_size,
705 fz::stream_t stream = 0,
706 PipelinePerfResult* perf_out = nullptr,
707 size_t pool_override_bytes = 0
708 );
709
727 void decompressFromFileInstance(
728 const std::string& filename,
729 void** d_output,
730 size_t* output_size,
731 fz::stream_t stream = 0,
732 PipelinePerfResult* perf_out = nullptr
733 );
734
759 void decompressFromMemory(
760 const void* header_bytes,
761 size_t header_size,
762 const void* d_blob,
763 size_t blob_size,
764 void** d_output,
765 size_t* output_size,
766 fz::stream_t stream = 0
767 );
768
769 // ── Config File ───────────────────────────────────────────────────────────
770
784 void loadConfig(const std::string& path);
785
794 void saveConfig(const std::string& path) const;
795
796private:
797 // ── RAII buffer wrappers (private implementation detail) ─────────────────
798
799 // Pool-allocated persistent device buffer.
800 struct PoolBuffer {
801 void* ptr = nullptr;
802 size_t capacity = 0;
803 MemoryPool* pool = nullptr;
804
805 ~PoolBuffer() { free(0); }
806 PoolBuffer() = default;
807 PoolBuffer(const PoolBuffer&) = delete;
808 PoolBuffer& operator=(const PoolBuffer&) = delete;
809
810 void free(fz::stream_t s) {
811 if (ptr && pool) { pool->free(ptr, s); ptr = nullptr; capacity = 0; }
812 }
813 bool allocate(MemoryPool* p, size_t bytes, fz::stream_t s,
814 const char* tag, bool persistent = false) {
815 free(s);
816 pool = p;
817 ptr = pool->allocate(bytes, s, tag, persistent);
818 if (ptr) capacity = bytes;
819 return ptr != nullptr;
820 }
821 };
822
823 // cudaHostAlloc pinned host buffer — grows on demand, never shrinks.
824 struct PinnedBuffer {
825 void* ptr = nullptr;
826 size_t capacity = 0;
827
828 ~PinnedBuffer() { if (ptr) cudaFreeHost(ptr); }
829 PinnedBuffer() = default;
830 PinnedBuffer(const PinnedBuffer&) = delete;
831 PinnedBuffer& operator=(const PinnedBuffer&) = delete;
832
833 // Returns false on CUDA allocation failure.
834 bool ensureCapacity(size_t bytes) {
835 if (capacity >= bytes) return true;
836 if (ptr) { cudaFreeHost(ptr); ptr = nullptr; capacity = 0; }
837 if (cudaHostAlloc(&ptr, bytes, cudaHostAllocDefault) != cudaSuccess) return false;
838 capacity = bytes;
839 return true;
840 }
841 };
842
843 // cudaMalloc device buffer — grows on demand, never shrinks.
844 struct DeviceBuffer {
845 void* ptr = nullptr;
846 size_t capacity = 0;
847
848 ~DeviceBuffer() { if (ptr) cudaFree(ptr); }
849 DeviceBuffer() = default;
850 DeviceBuffer(const DeviceBuffer&) = delete;
851 DeviceBuffer& operator=(const DeviceBuffer&) = delete;
852
853 // Returns false on CUDA allocation failure.
854 bool ensureCapacity(size_t bytes) {
855 if (capacity >= bytes) return true;
856 if (ptr) { cudaFree(ptr); ptr = nullptr; capacity = 0; }
857 if (cudaMalloc(&ptr, bytes) != cudaSuccess) return false;
858 capacity = bytes;
859 return true;
860 }
861 };
862
863 // ── Internal helpers ──────────────────────────────────────────────────────
864
865 Stage* addRawStage(Stage* stage);
866
867 struct OutputBuffer {
868 void* d_ptr;
869 size_t actual_size;
870 size_t allocated_size;
871 std::string name;
872 int buffer_id;
873 };
874 std::vector<OutputBuffer> getOutputBuffers() const;
875
876 static void* loadCompressedData(
877 const std::string& filename,
878 const FZMFileHeader& header,
879 fz::stream_t stream = 0,
880 MemoryPool* pool = nullptr
881 );
882
883 void validate();
884 std::pair<std::vector<Stage*>, std::vector<Stage*>> identifyTopology();
885 void setupInputBuffers(const std::vector<Stage*>& sources);
886 int autoDetectUnconnectedOutputs();
887 void detectMultiOutputScenario(int pipeline_outputs);
888 void configureStreamsIfNeeded();
889
890 // finalize() sub-steps
891 void typeCheckConnections();
892 void computeInputAlignment();
895 void bindSemanticContracts();
899 void planAndInstallFusion();
900 void notifyStagesFinalizeHooks();
901 void refinePoolSize();
902 void setupGraphModeInput();
903 void preallocatePadBuffer();
904 void preallocateConcatBuffers();
905
906 // compress() helper: handles graph-mode copy or alignment padding.
907 // Returns the effective source pointer and padded source size.
908 std::pair<const void*, size_t> prepareInputSource(
909 const void* d_input, size_t input_size, fz::stream_t stream);
910
916 void propagateBufferSizes(bool force_from_current_inputs = false);
917
918 std::vector<Stage*> getSourceStages() const;
919 std::vector<Stage*> getSinkStages() const;
920
921 // ── Inverse DAG helpers ───────────────────────────────────────────────────
922
924 struct FwdStageDesc {
925 Stage* stage;
926 std::vector<int> output_buf_ids;
927 std::vector<int> input_buf_ids;
928 };
929
931 using PipelineOutputMap = std::unordered_map<int, std::pair<void*, size_t>>;
932
933 // decompress() helper: builds or reuses the inverse DAG cache.
934 void buildOrReuseInvCache(
935 const PipelineOutputMap& po_map,
936 Stage* src_stage,
937 size_t src_sz,
938 fz::stream_t stream);
939
948 std::vector<size_t> resolveDecompressSegmentSizes(
949 const void* d_input, size_t input_size, fz::stream_t stream) const;
950
957 PipelineOutputMap mapCompressedBufferPointers(
958 const void* d_input, const std::vector<size_t>& seg_sizes) const;
959
966 std::pair<Stage*, size_t> resolvePrimarySource() const;
967
975 void* allocateDecompressOutput(
976 size_t actual_size, void* caller_output, size_t caller_capacity,
977 fz::stream_t stream);
978
991 void decompressCore(
992 const void* d_input,
993 size_t input_size,
994 void* caller_output,
995 size_t caller_capacity,
996 bool synchronize,
997 void** d_output,
998 size_t* output_size,
999 fz::stream_t stream);
1000
1008 void buildStaticBufferMetadata();
1009
1015 std::vector<size_t> readConcatSegmentSizes(
1016 const void* d_blob, size_t n, fz::stream_t stream) const;
1017
1018 // decompressFromFile() helpers.
1020 static FZMFileHeader parseHeaderFromMemory(const void* data, size_t size);
1021 static size_t computeFilePoolSize(const FZMFileHeader& fh, size_t pool_override_bytes);
1022 static std::pair<std::vector<std::unique_ptr<Stage>>, std::vector<FwdStageDesc>>
1023 reconstructForwardTopology(const FZMFileHeader& fh);
1024 static std::unordered_map<Stage*, size_t> buildSourceSizesFromHeader(
1025 const FZMFileHeader& fh, const std::vector<FwdStageDesc>& fwd_topology);
1026
1032 static std::pair<std::unique_ptr<CompressionDAG>,
1033 std::unordered_map<Stage*, int>>
1034 buildInverseDAG(
1035 const std::vector<FwdStageDesc>& fwd_stages,
1036 const PipelineOutputMap& pipeline_outputs,
1037 MemoryPool* pool,
1038 MemoryStrategy strategy,
1039 const std::unordered_map<Stage*, size_t>& source_sizes,
1040 bool enable_profiling,
1041 bool enable_inverse_fusion = false
1042 );
1043
1044 // ── Concat helpers ────────────────────────────────────────────────────────
1045
1046 struct OutputBufferInfo {
1047 int buffer_id;
1048 void* d_ptr;
1049 size_t actual_size;
1050 std::string stage_name;
1051 std::string output_name;
1052 };
1053
1054 std::vector<OutputBufferInfo> collectOutputBuffers() const;
1055
1057 size_t calculateConcatSize(const std::vector<OutputBufferInfo>& outputs) const;
1058
1059 size_t writeConcatBuffer(
1060 const std::vector<OutputBufferInfo>& outputs,
1061 uint8_t* d_concat_bytes,
1062 fz::stream_t stream
1063 ) const;
1064
1065 void concatOutputs(void** d_output, size_t* output_size, fz::stream_t stream);
1066
1067 // ── Member variables ──────────────────────────────────────────────────────
1068
1069 std::unique_ptr<MemoryPool> mem_pool_;
1070 std::unique_ptr<CompressionDAG> dag_;
1071 MemoryStrategy strategy_;
1072
1073 std::vector<std::unique_ptr<Stage>> stages_;
1074 std::unordered_map<Stage*, DAGNode*> stage_to_node_;
1075
1076 struct ConnectionInfo {
1077 Stage* dependent;
1078 Stage* producer;
1079 std::string output_name;
1080 int output_index;
1081 };
1082 std::vector<ConnectionInfo> connections_;
1083
1084 int num_streams_;
1085 bool is_finalized_;
1086 bool warmup_on_finalize_;
1087 bool pool_managed_decomp_;
1088
1089 // is_compressed_: true after the first successful compress() (gates writeToFile).
1090 // was_compressed_: true between compress() and the next reset() (gates captureGraph).
1091 bool is_compressed_;
1092 bool was_compressed_;
1093
1094 bool profiling_enabled_;
1097 bool coloring_enabled_ = true;
1098 PipelinePerfResult last_perf_result_;
1099
1100 std::vector<DAGNode*> input_nodes_;
1101 // Explicit choice of which input_nodes_ entry decompress() returns, for
1102 // pipelines with more than one source stage. Null = default to
1103 // input_nodes_[0]. Set via setPrimarySource(); resolved to an index lazily
1104 // (source stages aren't wired into input_nodes_ until finalize()).
1105 Stage* primary_source_stage_ = nullptr;
1106 // (node, buffer_id) pairs registered by bindExternalInput(), captured
1107 // immediately (before any later connect() calls add more buffer ids to
1108 // the same node). setupInputBuffers() appends these to input_nodes_/
1109 // input_buffer_ids_ after its own auto-discovery pass, since it clears
1110 // both first and auto-discovery alone would miss any stage that also
1111 // has real dependencies (getSourceStages() requires dependencies.empty()).
1112 std::vector<std::pair<DAGNode*, int>> explicit_external_bindings_;
1113 std::vector<DAGNode*> output_nodes_;
1114 std::vector<int> input_buffer_ids_;
1115 std::vector<int> output_buffer_ids_;
1116
1117 PoolBuffer d_concat_buffer_;
1118 bool needs_concat_;
1119
1120 // Pool-persistent decompress output buffers (one per source stage).
1121 // Only used when pool_managed_decomp_ == true.
1122 std::vector<void*> d_decomp_outputs_;
1123
1124 // Pinned host buffer for concat header (one H2D copy instead of N).
1125 PinnedBuffer h_concat_header_;
1126 // Persistent pinned host + device descriptor buffers for the gather kernel.
1127 PinnedBuffer h_copy_descs_;
1128 DeviceBuffer d_copy_descs_;
1129
1130 size_t input_size_;
1131
1132 // Per-source input sizes from the most recent compress(), ordered to match
1133 // input_nodes_. Used by decompress() to size each inverse result buffer.
1134 std::vector<size_t> source_input_sizes_;
1135
1136 // Input alignment in bytes — LCM of all stage getRequiredInputAlignment() values.
1137 // compress() zero-pads to this boundary transparently.
1138 size_t input_alignment_bytes_;
1139 PoolBuffer d_pad_buf_;
1140
1141 // Original (pre-padding) input size. decompress() uses this to trim the
1142 // reported output back to what the caller provided. 0 when no padding.
1143 size_t original_input_size_;
1144
1145 size_t input_size_hint_;
1146 float pool_multiplier_;
1147
1148 // Dataset dimensions (x=fast, y, z). Pushed to each stage on addStage() and
1149 // again at finalize(). Default {0,1,1} = 1-D, infer x from input size.
1150 std::array<size_t, 3> dims_;
1151
1160 struct InvDAGCache {
1161 std::unique_ptr<CompressionDAG> inv_dag;
1162 std::unordered_map<Stage*, int> inv_result_map;
1163 std::unordered_map<int, int> fwd_to_inv_ext_buf;
1164 std::unordered_map<Stage*, size_t> source_sizes;
1165 };
1166 std::unique_ptr<InvDAGCache> inv_cache_;
1167
1168 struct BufferMetadata {
1169 int buffer_id;
1170 size_t actual_size;
1171 size_t allocated_size;
1172 std::string name;
1173 DAGNode* producer;
1174 int output_index;
1175 };
1176 std::vector<BufferMetadata> buffer_metadata_;
1177
1178 bool graph_mode_enabled_;
1179 bool graph_captured_;
1180 FusionPolicy fusion_policy_ = FusionPolicy::Off;
1181 FusionInfo fusion_info_;
1182
1183 // Fixed device input buffer whose address is baked into the captured graph.
1184 // compress() copies user input here before cudaGraphLaunch().
1185 PoolBuffer d_graph_input_;
1186 size_t d_graph_input_size_;
1187
1188 fz::graph_t captured_graph_;
1189 fz::graph_exec_t graph_exec_;
1190};
1191
1192// ── Template implementation ───────────────────────────────────────────────────
1193
1194template<typename StageT, typename... Args>
1195StageT* Pipeline::addStage(Args&&... args) {
1196 if (is_finalized_) {
1197 throw std::runtime_error("Cannot add stages after finalization");
1198 }
1199
1200 // if constexpr, not a runtime check: on an unsupported backend, StageT's
1201 // constructor may not exist in the build at all (its .cu translation
1202 // unit excluded — see Stage::isSupportedOnBackend()'s doc comment), so
1203 // every line below that references `new StageT()` must never be
1204 // instantiated at all, not merely never executed — hence the whole rest
1205 // of the function lives in the `if constexpr` branch rather than after
1206 // a standalone early-throw.
1207 if constexpr (!StageT::isSupportedOnBackend()) {
1208 throw std::runtime_error(
1209 "addStage(): this stage type is not supported on the current "
1210 "GPU backend (FZGMOD_BACKEND) this library was built for");
1211 } else {
1212 auto stage_ptr = std::make_unique<StageT>(std::forward<Args>(args)...);
1213 StageT* stage = stage_ptr.get();
1214
1215 stage->setDims(dims_);
1216
1217 DAGNode* node = dag_->addStage(stage, stage->getName());
1218 size_t num_outputs = stage->getNumOutputs();
1219 auto output_names = stage->getOutputNames();
1220
1221 // Pre-allocate all output slots as unconnected (size=1 placeholder).
1222 // connect() will promote any that get wired to downstream stages.
1223 for (size_t i = 0; i < num_outputs; i++) {
1224 std::string out_name = i < output_names.size() ? output_names[i] : std::to_string(i);
1225 dag_->addUnconnectedOutput(node, 1, i, stage->getName() + "." + out_name + "_unconnected");
1226 }
1227
1228 stage_to_node_[stage] = node;
1229 stages_.push_back(std::move(stage_ptr));
1230 return stage;
1231 }
1232}
1233
1234} // namespace fz
Definition device_buffer.h:54
Definition dag.h:101
Definition mempool.h:82
void free(void *ptr, fz::stream_t stream)
void * allocate(size_t size, fz::stream_t stream, const std::string &tag="", bool persistent=false)
Definition device_buffer.h:84
Definition stage.h:31
virtual void setDims(const std::array< size_t, 3 > &dims)
Definition stage.h:207
TOML-based pipeline configuration file support.
Compression DAG wiring, execution, and memory strategy types.
Backend-neutral device span and buffer value types.
FZM binary file format definitions — structs, enums, and helpers.
Stream-ordered CUDA memory pool for pipeline buffer management.
Definition dag.h:24
SpecializationPolicy
Pipeline Specialization policy.
Definition compressor.h:62
MemoryStrategy
Definition dag.h:32
@ MINIMAL
Allocate on-demand, free at last consumer. Lowest peak memory.
SpecializationInfo FusionInfo
Definition compressor.h:86
SpecializationPolicy FusionPolicy
Definition compressor.h:66
Pipeline and per-stage profiling result types.
Base class interface for all compression stages.
Backward-compatible shim.
Definition device_buffer.h:35
Definition device_buffer.h:24
Fixed-size FZM file header core (80 bytes).
Definition fzm_format.h:275
Definition perf.h:78
Definition compressor.h:633
One finalize-time specialization selected for execution (compress or inverse).
Definition compressor.h:69
std::vector< std::string > stages
the stages it replaced
Definition compressor.h:71
std::string execution_path
last runtime subpath; empty if not applicable
Definition compressor.h:72
std::string implementation
strategy impl name, e.g. "warp-register"
Definition compressor.h:70
Resolved specialization decision for diagnostics and benchmark provenance.
Definition compressor.h:77
std::string fallback_reason
policy_off, no_legal_group, or legacy no_profitable_implementation; empty on a hit.
Definition compressor.h:84
std::vector< SpecializationGroupInfo > installed_inverse_groups
Lazily populated after the first decompress builds its inverse DAG.
Definition compressor.h:82
Backend-neutral GPU type aliases.