ferrum_models/executor/vnext_executor/
composition.rs1use super::*;
6
7pub struct VNextRuntimeComposition<R: DeviceRuntime> {
8 pub(super) runtime: Arc<R>,
9 pub(super) registry: OperationRuntimeRegistry<R>,
10 weight_materializers: WeightMaterializerRegistry,
11 pub(super) catalog: CapabilityCatalog,
12}
13
14pub struct VNextCompiledModel<'a, R: DeviceRuntime> {
18 pub(super) composition: &'a VNextRuntimeComposition<R>,
19 pub(super) prepared: &'a PreparedProductionModel,
20 pub(super) info: ModelInfo,
21 pub(super) config: VNextExecutorConfig,
22 pub(super) compilation: ProgramPlanCompilation,
23 pub(super) language_io: VNextLanguageIoIds,
24 pub(super) checkpoint_selection: Option<VNextCheckpointSelection>,
25 pub(super) repetition_capacity: u64,
26 pub(super) executor_startup: StartupPhaseTimer,
27}
28
29impl<R: DeviceRuntime> VNextRuntimeComposition<R> {
30 pub fn new(
31 runtime: Arc<R>,
32 registry: OperationRuntimeRegistry<R>,
33 weight_materializers: WeightMaterializerRegistry,
34 catalog: CapabilityCatalog,
35 ) -> Self {
36 Self {
37 runtime,
38 registry,
39 weight_materializers,
40 catalog,
41 }
42 }
43
44 pub fn runtime(&self) -> &R {
45 self.runtime.as_ref()
46 }
47 pub fn catalog(&self) -> &CapabilityCatalog {
48 &self.catalog
49 }
50 pub fn weight_materializers(&self) -> &WeightMaterializerRegistry {
51 &self.weight_materializers
52 }
53
54 pub fn compile_model<'a>(
55 &'a self,
56 prepared: &'a PreparedProductionModel,
57 info: ModelInfo,
58 engine_config: &EngineConfig,
59 config: VNextExecutorConfig,
60 materializer_selection: WeightMaterializerSelection,
61 ) -> Result<VNextCompiledModel<'a, R>> {
62 if self.runtime.descriptor() != self.catalog.device() {
63 return Err(FerrumError::device(
64 "vNext static compilation catalog differs from the actual device runtime",
65 ));
66 }
67 let executor_startup = StartupPhaseTimer::start("executor_composition_total");
68 let checkpoint_selection = VNextCheckpointSelection::from_config(
69 engine_config.runtime.vnext_checkpoint_capture.as_ref(),
70 )?;
71 let family = prepared.family();
72 let language_io = VNextModelExecutor::<R>::resolve_language_io_ids(family.program())?;
73 let input_capacity = u64::try_from(config.maximum_model_tokens)
74 .map_err(|_| FerrumError::config("vNext model length exceeds u64"))?;
75 let vocabulary_size = u64::try_from(info.vocab_size)
76 .map_err(|_| FerrumError::config("vNext vocabulary exceeds u64"))?;
77 let repetition_capacity = input_capacity.min(vocabulary_size);
78 let tensor = |dimensions, element_type| ProgramTensorSpec {
79 dimensions,
80 element_type,
81 layout: ResolvedTensorLayout::Contiguous,
82 };
83 let mut options = ProgramPlanCompileOptions::new(BTreeMap::from([
84 (
85 language_io.token_input.clone(),
86 tensor(vec![input_capacity], ElementType::U32),
87 ),
88 (
89 language_io.token_mask_input.clone(),
90 tensor(vec![vocabulary_size], ElementType::U8),
91 ),
92 (
93 language_io.repetition_token_ids_input.clone(),
94 tensor(vec![repetition_capacity], ElementType::U32),
95 ),
96 (
97 language_io.repetition_offsets_input.clone(),
98 tensor(vec![2], ElementType::U32),
99 ),
100 (
101 language_io.repetition_penalty_input.clone(),
102 tensor(vec![1], ElementType::F32),
103 ),
104 ]))
105 .map_err(|error| FerrumError::model(format!("vNext compile input: {error}")))?;
106 config.plan_observation.apply(family, &mut options)?;
107 if let Some(selection) = &checkpoint_selection {
108 selection.retain_in(&mut options);
109 }
110 options.require_weight_materializer_selection(materializer_selection);
111 let compile_phase = StartupPhaseTimer::start("plan_compile");
112 let compilation = ProgramPlanCompiler::compile_with_weight_materializers(
113 family,
114 &self.catalog,
115 &config.runtime_policy,
116 &self.registry.planning(),
117 &self.weight_materializers,
118 &options,
119 )
120 .map_err(|error| FerrumError::model(format!("vNext plan compile: {error}")))?;
121 config
122 .plan_observation
123 .validate_compilation(family, &compilation)?;
124 compile_phase.finish();
125 Ok(VNextCompiledModel {
126 composition: self,
127 prepared,
128 info,
129 config,
130 compilation,
131 language_io,
132 checkpoint_selection,
133 repetition_capacity,
134 executor_startup,
135 })
136 }
137}
138
139impl<R: DeviceRuntime> VNextCompiledModel<'_, R> {
140 pub fn prepared(&self) -> &PreparedProductionModel {
141 self.prepared
142 }
143 pub fn compilation(&self) -> &ProgramPlanCompilation {
144 &self.compilation
145 }
146
147 pub fn startup_peak_bytes(&self, workload: ferrum_types::StartupWorkload) -> Result<u64> {
149 let (context, frontier, sequences, tokens) = match workload {
150 ferrum_types::StartupWorkload::Prefill {
151 context_tokens,
152 chunk_tokens,
153 } => (context_tokens, context_tokens, 1, chunk_tokens),
154 ferrum_types::StartupWorkload::Decode {
155 context_tokens,
156 active_sequences,
157 } => (context_tokens, 1, active_sequences, active_sequences),
158 };
159 let context = u64::try_from(context)
160 .map_err(|_| FerrumError::config("startup context exceeds u64"))?;
161 let frontier = u64::try_from(frontier)
162 .map_err(|_| FerrumError::config("startup sequence frontier exceeds u64"))?;
163 let sequences = u32::try_from(sequences)
164 .map_err(|_| FerrumError::config("startup sequence count exceeds u32"))?;
165 let tokens = u64::try_from(tokens)
166 .map_err(|_| FerrumError::config("startup token count exceeds u64"))?;
167 self.compilation
168 .executable()
169 .execution_plan()
170 .payload()
171 .memory()
172 .startup_workload_peak_bytes(context, frontier, sequences, tokens)
173 .map_err(|error| FerrumError::config(format!("compiled startup memory: {error}")))
174 }
175
176 pub fn set_startup_memory_plan(&mut self, plan: ferrum_types::StartupMemoryPlan) -> Result<()> {
179 let memory = self
180 .compilation
181 .executable()
182 .execution_plan()
183 .payload()
184 .memory();
185 if plan.selected.context_tokens != self.config.maximum_model_tokens
186 || plan.selected.max_sequences as u64 != u64::from(memory.maximum_active_sequences())
187 || plan.selected.max_batch_tokens as u64
188 != self.config.runtime_policy.maximum_scheduled_tokens()
189 || plan.request.usable_capacity_bytes != memory.usable_capacity_bytes()
190 || plan.context_peak_bytes > memory.usable_capacity_bytes()
191 || plan.decode_peak_bytes > memory.usable_capacity_bytes()
192 {
193 return Err(FerrumError::config(
194 "startup memory report differs from the retained compiled plan",
195 ));
196 }
197 self.config.startup_memory_plan = Some(plan);
198 Ok(())
199 }
200
201 pub fn initialize<F>(self, resolve_plan: F) -> Result<VNextModelExecutor<R>>
202 where
203 F: FnOnce(
204 &PreparedProductionModel,
205 &ResolvedRuntimePolicy,
206 &CapabilityCatalog,
207 &ProgramPlanCompilation,
208 ) -> Result<ResolvedModelPlan>,
209 {
210 VNextModelExecutor::from_compiled_model(self, resolve_plan)
211 }
212}