1use std::ops::Range;
2
3use super::super::{
4 AllocationLifetime, BatchWorkShape, BufferDescriptor, BufferUsage, DeviceBufferRetention,
5 DeviceRuntime, DynamicResourceDemand, DynamicResourceShape, LeasedBufferView,
6 LogicalBackingBufferView, LogicalBackingSegmentBinding, NodeWorkContract, ResourceId,
7 ResourceTransactionIdentity, VNextError,
8};
9use super::foundation::invalid_operation;
10use super::{DynamicStorageView, ResolvedStorageComponent, ResolvedValueBinding};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub(super) enum ValueBindingPhysicalCoverage {
14 CanonicalComponent,
15 RuntimeTokenView,
16}
17
18pub(super) fn validate_value_binding_physical_coverage(
19 work: &NodeWorkContract,
20 binding: &ResolvedValueBinding,
21 component: &ResolvedStorageComponent,
22 descriptor: &BufferDescriptor,
23 dynamic_demand: Option<&DynamicResourceDemand>,
24 value_alignment_bytes: u64,
25) -> Result<ValueBindingPhysicalCoverage, VNextError> {
26 let required_end = component
27 .offset_bytes()
28 .checked_add(component.length_bytes())
29 .ok_or_else(|| invalid_operation("bound component range overflows u64"))?;
30 if descriptor.usage != binding.usage()
31 || descriptor.element_type != component.element_type()
32 || descriptor.alignment_bytes < value_alignment_bytes
33 || descriptor.alignment_bytes % value_alignment_bytes != 0
34 || component.offset_bytes() % value_alignment_bytes != 0
35 {
36 return Err(invalid_operation(format!(
37 "resource `{}` differs from its value binding",
38 component.resource_id()
39 )));
40 }
41
42 let Some(projection) = work.token_projection(binding.role(), binding.ordinal()) else {
43 if required_end > descriptor.size_bytes {
44 return Err(invalid_operation(format!(
45 "resource `{}` differs from its value binding",
46 component.resource_id()
47 )));
48 }
49 return Ok(ValueBindingPhysicalCoverage::CanonicalComponent);
50 };
51
52 let axis = usize::try_from(projection.axis())
53 .map_err(|_| invalid_operation("token projection axis exceeds usize"))?;
54 let canonical_extent = projection.canonical_extent();
55 let bytes_per_token = component
56 .length_bytes()
57 .checked_div(canonical_extent)
58 .filter(|bytes| *bytes > 0)
59 .ok_or_else(|| invalid_operation("token projection has zero canonical extent"))?;
60 let demand_matches = matches!(
61 dynamic_demand,
62 Some(DynamicResourceDemand::Tokens {
63 bytes_per_token: planned_bytes_per_token,
64 ..
65 }) if *planned_bytes_per_token == bytes_per_token
66 );
67 if binding.usage() != BufferUsage::Activations
68 || component.offset_bytes() != 0
69 || component.length_bytes() % canonical_extent != 0
70 || usize::try_from(projection.rank()).ok() != Some(binding.tensor().dimensions().len())
71 || binding.tensor().dimensions().get(axis) != Some(&canonical_extent)
72 || !demand_matches
73 || descriptor.size_bytes < bytes_per_token
74 {
75 return Err(invalid_operation(format!(
76 "resource `{}` differs from its token-projected value binding",
77 component.resource_id()
78 )));
79 }
80
81 Ok(ValueBindingPhysicalCoverage::RuntimeTokenView)
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85enum StepParticipantRangeCoordinates {
86 SourceToken,
87 ParticipantLocal,
88}
89
90pub(crate) fn translate_step_participant_upload_range(
93 demand: &DynamicResourceDemand,
94 work_shape: &BatchWorkShape,
95 participant_index: usize,
96 semantic_range: Range<u64>,
97) -> Result<Range<u64>, VNextError> {
98 translate_step_participant_range(
99 demand,
100 work_shape,
101 participant_index,
102 semantic_range,
103 StepParticipantRangeCoordinates::SourceToken,
104 )
105}
106
107pub(crate) fn translate_step_participant_readback_range(
109 demand: &DynamicResourceDemand,
110 work_shape: &BatchWorkShape,
111 participant_index: usize,
112 semantic_range: Range<u64>,
113) -> Result<Range<u64>, VNextError> {
114 translate_step_participant_range(
115 demand,
116 work_shape,
117 participant_index,
118 semantic_range,
119 StepParticipantRangeCoordinates::ParticipantLocal,
120 )
121}
122
123pub(crate) fn packed_step_token_range_to_participant_local_readback(
127 demand: &DynamicResourceDemand,
128 work_shape: &BatchWorkShape,
129 participant_index: usize,
130 packed_range: Range<u64>,
131) -> Result<Range<u64>, VNextError> {
132 if packed_range.start >= packed_range.end {
133 return Err(invalid_operation(
134 "packed participant token readback range is empty",
135 ));
136 }
137 let token_range = work_shape
138 .participant_token_ranges()
139 .get(participant_index)
140 .ok_or_else(|| invalid_operation("packed participant token readback is out of range"))?;
141 let DynamicResourceDemand::Tokens {
142 bytes_per_token,
143 maximum_tokens,
144 } = demand
145 else {
146 return Err(invalid_operation(
147 "packed participant token readback requires token demand",
148 ));
149 };
150 if work_shape.immediate_tokens() > *maximum_tokens {
151 return Err(invalid_operation(
152 "packed participant token readback exceeds its planned ceiling",
153 ));
154 }
155 let participant_start = token_range
156 .immediate_token_range()
157 .start
158 .checked_mul(*bytes_per_token)
159 .ok_or_else(|| invalid_operation("packed participant token offset overflows u64"))?;
160 let participant_end = token_range
161 .immediate_token_range()
162 .end
163 .checked_mul(*bytes_per_token)
164 .ok_or_else(|| invalid_operation("packed participant token range overflows u64"))?;
165 if packed_range.start < participant_start || packed_range.end > participant_end {
166 return Err(invalid_operation(
167 "packed participant token readback is outside its immediate span",
168 ));
169 }
170 Ok(packed_range.start - participant_start..packed_range.end - participant_start)
171}
172
173fn translate_step_participant_range(
174 demand: &DynamicResourceDemand,
175 work_shape: &BatchWorkShape,
176 participant_index: usize,
177 semantic_range: Range<u64>,
178 coordinates: StepParticipantRangeCoordinates,
179) -> Result<Range<u64>, VNextError> {
180 if semantic_range.start >= semantic_range.end {
181 return Err(invalid_operation(
182 "participant resource projection has an empty semantic range",
183 ));
184 }
185 if participant_index >= work_shape.participant_token_ranges().len() {
186 return Err(invalid_operation(
187 "participant resource projection is out of range",
188 ));
189 }
190 match demand {
191 DynamicResourceDemand::ActualSequences {
192 bytes_per_sequence,
193 maximum_sequences,
194 } => {
195 if work_shape.immediate_sequences() > *maximum_sequences
196 || semantic_range.end > *bytes_per_sequence
197 {
198 return Err(invalid_operation(
199 "participant fixed resource projection exceeds its planned stride",
200 ));
201 }
202 let base = bytes_per_sequence
203 .checked_mul(u64::try_from(participant_index).map_err(|_| {
204 invalid_operation("participant resource projection exceeds u64")
205 })?)
206 .ok_or_else(|| {
207 invalid_operation("participant fixed resource projection overflows u64")
208 })?;
209 let translated_start = base
210 .checked_add(semantic_range.start)
211 .ok_or_else(|| invalid_operation("participant fixed range overflows u64"))?;
212 let translated_end = base
213 .checked_add(semantic_range.end)
214 .ok_or_else(|| invalid_operation("participant fixed range overflows u64"))?;
215 Ok(translated_start..translated_end)
216 }
217 DynamicResourceDemand::Tokens {
218 bytes_per_token,
219 maximum_tokens,
220 } => {
221 if work_shape.immediate_tokens() > *maximum_tokens {
222 return Err(invalid_operation(
223 "participant token resource projection exceeds its planned ceiling",
224 ));
225 }
226 let token_range = &work_shape.participant_token_ranges()[participant_index];
227 let source = token_range.source_token_range();
228 let packed = token_range.immediate_token_range();
229 let source_start = source
230 .start
231 .checked_mul(*bytes_per_token)
232 .ok_or_else(|| invalid_operation("source token byte offset overflows u64"))?;
233 let source_end = source
234 .end
235 .checked_mul(*bytes_per_token)
236 .ok_or_else(|| invalid_operation("source token byte range overflows u64"))?;
237 let packed_start = packed
238 .start
239 .checked_mul(*bytes_per_token)
240 .ok_or_else(|| invalid_operation("packed token byte offset overflows u64"))?;
241 let relative_range = match coordinates {
242 StepParticipantRangeCoordinates::SourceToken => {
243 if semantic_range.start < source_start || semantic_range.end > source_end {
244 return Err(invalid_operation(
245 "participant token resource projection is outside its source span",
246 ));
247 }
248 semantic_range.start - source_start..semantic_range.end - source_start
249 }
250 StepParticipantRangeCoordinates::ParticipantLocal => {
251 let span_bytes = source_end - source_start;
252 if semantic_range.end > span_bytes {
253 return Err(invalid_operation(
254 "participant token readback exceeds its immediate span",
255 ));
256 }
257 semantic_range
258 }
259 };
260 let translated_start = packed_start
261 .checked_add(relative_range.start)
262 .ok_or_else(|| invalid_operation("packed token projection overflows u64"))?;
263 let translated_end = translated_start
264 .checked_add(relative_range.end - relative_range.start)
265 .ok_or_else(|| invalid_operation("packed token range overflows u64"))?;
266 Ok(translated_start..translated_end)
267 }
268 _ => Ok(semantic_range),
272 }
273}
274
275#[derive(Debug, Clone, Copy, PartialEq, Eq)]
276pub enum OperationBufferStorageKind {
277 StaticContiguous,
278 DynamicContiguous,
279 DynamicPaged,
280}
281
282enum OperationBufferSource<'a, B> {
283 Static {
284 view: LeasedBufferView<'a, B>,
285 retention: DeviceBufferRetention,
286 },
287 Backing(LogicalBackingBufferView<'a, B>),
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
291enum OperationBufferCoverage {
292 Exact,
293 BackingWindow {
296 offset_bytes: u64,
297 },
298}
299
300enum OperationRegionSource<'a, B> {
301 Contiguous {
302 buffer: &'a B,
303 physical_base_offset_bytes: u64,
304 retention: DeviceBufferRetention,
305 },
306 Paged {
307 bindings: &'a [LogicalBackingSegmentBinding<B>],
308 logical_origin_bytes: u64,
309 },
310}
311
312pub struct OperationBufferRegions<'a, B> {
315 storage_kind: OperationBufferStorageKind,
316 logical_offset_bytes: u64,
317 logical_length_bytes: u64,
318 source: OperationRegionSource<'a, B>,
319}
320
321impl<'a, B> OperationBufferRegions<'a, B> {
322 pub const fn storage_kind(&self) -> OperationBufferStorageKind {
323 self.storage_kind
324 }
325
326 pub const fn logical_offset_bytes(&self) -> u64 {
327 self.logical_offset_bytes
328 }
329
330 pub const fn logical_length_bytes(&self) -> u64 {
331 self.logical_length_bytes
332 }
333
334 pub fn iter(&self) -> OperationBufferRegionIter<'a, B> {
335 let logical_end_bytes = self
336 .logical_offset_bytes
337 .checked_add(self.logical_length_bytes)
338 .expect("validated operation logical range does not overflow");
339 match &self.source {
340 OperationRegionSource::Contiguous {
341 buffer,
342 physical_base_offset_bytes,
343 retention,
344 } => OperationBufferRegionIter {
345 state: OperationBufferRegionIterState::Contiguous(Some(OperationPhysicalRegion {
346 buffer: *buffer,
347 logical_offset_bytes: self.logical_offset_bytes,
348 physical_offset_bytes: physical_base_offset_bytes
349 .checked_add(self.logical_offset_bytes)
350 .expect("validated contiguous physical range does not overflow"),
351 length_bytes: self.logical_length_bytes,
352 retention: retention.clone(),
353 })),
354 },
355 OperationRegionSource::Paged {
356 bindings,
357 logical_origin_bytes,
358 } => OperationBufferRegionIter {
359 state: OperationBufferRegionIterState::Paged {
360 bindings: *bindings,
361 logical_origin_bytes: *logical_origin_bytes,
362 requested_start_bytes: logical_origin_bytes
363 .checked_add(self.logical_offset_bytes)
364 .expect("validated paged window start does not overflow"),
365 requested_end_bytes: logical_origin_bytes
366 .checked_add(logical_end_bytes)
367 .expect("validated paged window end does not overflow"),
368 next_segment: 0,
369 next_segment_logical_offset_bytes: 0,
370 },
371 },
372 }
373 }
374}
375
376pub struct OperationPhysicalRegion<'a, B> {
379 buffer: &'a B,
380 logical_offset_bytes: u64,
381 physical_offset_bytes: u64,
382 length_bytes: u64,
383 retention: DeviceBufferRetention,
384}
385
386impl<'a, B> OperationPhysicalRegion<'a, B> {
387 pub const fn logical_offset_bytes(&self) -> u64 {
388 self.logical_offset_bytes
389 }
390
391 pub const fn length_bytes(&self) -> u64 {
392 self.length_bytes
393 }
394
395 pub fn buffer_and_physical_range(
396 &self,
397 ) -> (&'a B, std::ops::Range<u64>, DeviceBufferRetention) {
398 (
399 self.buffer,
400 self.physical_offset_bytes
401 ..self
402 .physical_offset_bytes
403 .checked_add(self.length_bytes)
404 .expect("validated physical region does not overflow"),
405 self.retention.clone(),
406 )
407 }
408}
409
410pub struct OperationBufferRegionIter<'a, B> {
411 state: OperationBufferRegionIterState<'a, B>,
412}
413
414enum OperationBufferRegionIterState<'a, B> {
415 Contiguous(Option<OperationPhysicalRegion<'a, B>>),
416 Paged {
417 bindings: &'a [LogicalBackingSegmentBinding<B>],
418 logical_origin_bytes: u64,
419 requested_start_bytes: u64,
420 requested_end_bytes: u64,
421 next_segment: usize,
422 next_segment_logical_offset_bytes: u64,
423 },
424}
425
426impl<'a, B> Iterator for OperationBufferRegionIter<'a, B> {
427 type Item = OperationPhysicalRegion<'a, B>;
428
429 fn next(&mut self) -> Option<Self::Item> {
430 match &mut self.state {
431 OperationBufferRegionIterState::Contiguous(region) => region.take(),
432 OperationBufferRegionIterState::Paged {
433 bindings,
434 logical_origin_bytes,
435 requested_start_bytes,
436 requested_end_bytes,
437 next_segment,
438 next_segment_logical_offset_bytes,
439 } => {
440 while let Some(binding) = bindings.get(*next_segment) {
441 *next_segment += 1;
442 let (segment_logical_end, region) = translate_paged_segment(
443 binding.buffer(),
444 binding.retention(),
445 binding.segment().offset_bytes(),
446 binding.segment().length_bytes(),
447 *next_segment_logical_offset_bytes,
448 *requested_start_bytes,
449 *requested_end_bytes,
450 );
451 *next_segment_logical_offset_bytes = segment_logical_end;
452 if let Some(mut region) = region {
453 region.logical_offset_bytes = region
454 .logical_offset_bytes
455 .checked_sub(*logical_origin_bytes)
456 .expect("paged region is inside its validated backing window");
457 return Some(region);
458 }
459 }
460 None
461 }
462 }
463 }
464}
465
466fn translate_paged_segment<'a, B>(
467 buffer: &'a B,
468 retention: DeviceBufferRetention,
469 physical_offset_bytes: u64,
470 length_bytes: u64,
471 logical_start_bytes: u64,
472 requested_start_bytes: u64,
473 requested_end_bytes: u64,
474) -> (u64, Option<OperationPhysicalRegion<'a, B>>) {
475 let logical_end_bytes = logical_start_bytes
476 .checked_add(length_bytes)
477 .expect("validated backing segments do not overflow");
478 let translated_start = logical_start_bytes.max(requested_start_bytes);
479 let translated_end = logical_end_bytes.min(requested_end_bytes);
480 let region = (translated_start < translated_end).then(|| OperationPhysicalRegion {
481 buffer,
482 logical_offset_bytes: translated_start,
483 physical_offset_bytes: physical_offset_bytes
484 .checked_add(translated_start - logical_start_bytes)
485 .expect("validated paged physical range does not overflow"),
486 length_bytes: translated_end - translated_start,
487 retention,
488 });
489 (logical_end_bytes, region)
490}
491
492const fn operation_storage_kind(view: DynamicStorageView) -> OperationBufferStorageKind {
493 match view {
494 DynamicStorageView::Contiguous => OperationBufferStorageKind::DynamicContiguous,
495 DynamicStorageView::PagedRegions { .. } => OperationBufferStorageKind::DynamicPaged,
496 }
497}
498
499fn validate_dynamic_binding_layout(
500 storage_kind: OperationBufferStorageKind,
501 logical_size_bytes: u64,
502 mut binding_lengths: impl ExactSizeIterator<Item = u64>,
503 coverage: OperationBufferCoverage,
504) -> Result<(), VNextError> {
505 let binding_count = binding_lengths.len();
506 if storage_kind == OperationBufferStorageKind::StaticContiguous {
507 return Err(invalid_operation(
508 "dynamic backing cannot claim static storage kind",
509 ));
510 }
511 if binding_count == 0 {
512 return Err(invalid_operation(
513 "dynamic backing has no physical segment binding",
514 ));
515 }
516 if storage_kind == OperationBufferStorageKind::DynamicContiguous && binding_count != 1 {
517 return Err(invalid_operation(
518 "contiguous dynamic storage requires one physical segment binding",
519 ));
520 }
521 let covered = binding_lengths.try_fold(0_u64, |total, length_bytes| {
522 total
523 .checked_add(length_bytes)
524 .ok_or_else(|| invalid_operation("backing segment coverage overflows u64"))
525 })?;
526 let window_offset = match coverage {
527 OperationBufferCoverage::Exact => 0,
528 OperationBufferCoverage::BackingWindow { offset_bytes } => offset_bytes,
529 };
530 let required_end = window_offset
531 .checked_add(logical_size_bytes)
532 .ok_or_else(|| invalid_operation("operation backing window overflows u64"))?;
533 if covered < required_end
534 || (coverage == OperationBufferCoverage::Exact && covered != logical_size_bytes)
535 {
536 return Err(invalid_operation(
537 "dynamic backing segments do not cover the operation's exact logical view",
538 ));
539 }
540 Ok(())
541}
542
543pub(super) fn sequence_execution_shape(
544 committed: DynamicResourceShape,
545 source_end_tokens: u64,
546) -> Result<DynamicResourceShape, VNextError> {
547 if committed.sequences() != 1
548 || source_end_tokens == 0
549 || source_end_tokens > committed.tokens()
550 {
551 return Err(invalid_operation(
552 "sequence operation frontier is empty or exceeds committed backing",
553 ));
554 }
555 Ok(DynamicResourceShape::from_validated(
556 1,
557 source_end_tokens,
558 committed.pages(),
559 ))
560}
561
562pub struct OperationBufferView<'a, B> {
563 descriptor: BufferDescriptor,
564 source: OperationBufferSource<'a, B>,
565 coverage: OperationBufferCoverage,
566 allocation_lifetime: AllocationLifetime,
567 packed_batch_coordinates: bool,
568}
569
570impl<'a, B> OperationBufferView<'a, B> {
571 pub(super) fn from_static(
572 view: LeasedBufferView<'a, B>,
573 retention: DeviceBufferRetention,
574 ) -> Self {
575 Self {
576 descriptor: view.committed_descriptor().clone(),
577 source: OperationBufferSource::Static { view, retention },
578 coverage: OperationBufferCoverage::Exact,
579 allocation_lifetime: AllocationLifetime::Plan,
580 packed_batch_coordinates: false,
581 }
582 }
583
584 pub(super) fn from_backing_exact(
585 descriptor: BufferDescriptor,
586 backing: LogicalBackingBufferView<'a, B>,
587 allocation_lifetime: AllocationLifetime,
588 ) -> Self {
589 Self::from_backing(
590 descriptor,
591 backing,
592 OperationBufferCoverage::Exact,
593 allocation_lifetime,
594 )
595 }
596
597 pub(super) fn from_backing_prefix(
598 descriptor: BufferDescriptor,
599 backing: LogicalBackingBufferView<'a, B>,
600 allocation_lifetime: AllocationLifetime,
601 ) -> Self {
602 Self::from_backing(
603 descriptor,
604 backing,
605 OperationBufferCoverage::BackingWindow { offset_bytes: 0 },
606 allocation_lifetime,
607 )
608 }
609
610 pub(super) fn from_backing_window(
611 descriptor: BufferDescriptor,
612 backing: LogicalBackingBufferView<'a, B>,
613 offset_bytes: u64,
614 allocation_lifetime: AllocationLifetime,
615 ) -> Self {
616 Self::from_backing(
617 descriptor,
618 backing,
619 OperationBufferCoverage::BackingWindow { offset_bytes },
620 allocation_lifetime,
621 )
622 }
623
624 fn from_backing(
625 descriptor: BufferDescriptor,
626 backing: LogicalBackingBufferView<'a, B>,
627 coverage: OperationBufferCoverage,
628 allocation_lifetime: AllocationLifetime,
629 ) -> Self {
630 Self {
631 descriptor,
632 source: OperationBufferSource::Backing(backing),
633 coverage,
634 allocation_lifetime,
635 packed_batch_coordinates: false,
636 }
637 }
638
639 pub(super) fn with_packed_batch_coordinates(mut self, packed: bool) -> Self {
640 self.packed_batch_coordinates = packed;
641 self
642 }
643
644 pub(super) fn validate_runtime<R>(
645 &self,
646 runtime: &R,
647 expected_static_identity: Option<&ResourceTransactionIdentity>,
648 ) -> Result<(), VNextError>
649 where
650 R: DeviceRuntime<Buffer = B>,
651 {
652 match &self.source {
653 OperationBufferSource::Static { view, .. } => {
654 let actual = runtime.buffer_descriptor(view.buffer());
655 if Some(view.identity()) != expected_static_identity
656 || &actual != view.committed_descriptor()
657 || view.generation() == 0
658 {
659 return Err(invalid_operation(format!(
660 "runtime descriptor differs from committed static resource `{}`",
661 self.resource_id()
662 )));
663 }
664 }
665 OperationBufferSource::Backing(backing_view) => {
666 let bindings = backing_view.segment_bindings();
667 if bindings.is_empty()
668 || bindings.len() != backing_view.committed_evidence_segments().count()
669 || bindings
670 .iter()
671 .zip(backing_view.committed_evidence_segments())
672 .any(|(binding, evidence)| {
673 let actual = runtime.buffer_descriptor(binding.buffer());
674 binding.segment() != evidence
675 || binding.chunk() != evidence.chunk()
676 || &actual != binding.descriptor()
677 || binding
678 .segment()
679 .offset_bytes()
680 .checked_add(binding.segment().length_bytes())
681 .is_none_or(|end| end > binding.descriptor().size_bytes)
682 })
683 {
684 return Err(invalid_operation(format!(
685 "runtime descriptor differs from a committed backing chunk for `{}`",
686 self.resource_id()
687 )));
688 }
689 }
690 }
691 Ok(())
692 }
693
694 pub fn resource_id(&self) -> &ResourceId {
695 &self.descriptor.resource_id
696 }
697
698 pub fn descriptor(&self) -> &BufferDescriptor {
699 &self.descriptor
700 }
701
702 pub const fn allocation_lifetime(&self) -> AllocationLifetime {
703 self.allocation_lifetime
704 }
705
706 pub const fn uses_packed_batch_coordinates(&self) -> bool {
707 self.packed_batch_coordinates
708 }
709
710 pub fn storage_kind(&self) -> OperationBufferStorageKind {
711 match &self.source {
712 OperationBufferSource::Static { .. } => OperationBufferStorageKind::StaticContiguous,
713 OperationBufferSource::Backing(view) => {
714 operation_storage_kind(view.storage_profile().view())
715 }
716 }
717 }
718
719 pub fn translate(
720 &self,
721 logical_offset_bytes: u64,
722 logical_length_bytes: u64,
723 ) -> Result<OperationBufferRegions<'_, B>, VNextError> {
724 let logical_end_bytes = logical_offset_bytes
725 .checked_add(logical_length_bytes)
726 .ok_or_else(|| invalid_operation("operation logical buffer range overflows u64"))?;
727 if logical_length_bytes == 0 || logical_end_bytes > self.descriptor.size_bytes {
728 return Err(invalid_operation(
729 "operation logical buffer range is empty or outside its resource",
730 ));
731 }
732 match &self.source {
733 OperationBufferSource::Static { view, retention } => Ok(OperationBufferRegions {
734 storage_kind: OperationBufferStorageKind::StaticContiguous,
735 logical_offset_bytes,
736 logical_length_bytes,
737 source: OperationRegionSource::Contiguous {
738 buffer: view.buffer(),
739 physical_base_offset_bytes: 0,
740 retention: retention.clone(),
741 },
742 }),
743 OperationBufferSource::Backing(view) => {
744 let bindings = view.segment_bindings();
745 if bindings.len() != view.committed_evidence_segments().count()
746 || bindings.iter().zip(view.committed_evidence_segments()).any(
747 |(binding, segment)| {
748 binding.segment() != segment || binding.chunk() != segment.chunk()
749 },
750 )
751 {
752 return Err(invalid_operation(
753 "dynamic backing bindings differ from committed segment evidence",
754 ));
755 }
756 let storage_kind = operation_storage_kind(view.storage_profile().view());
757 let backing_window_offset = match self.coverage {
758 OperationBufferCoverage::Exact => 0,
759 OperationBufferCoverage::BackingWindow { offset_bytes } => offset_bytes,
760 };
761 validate_dynamic_binding_layout(
762 storage_kind,
763 self.descriptor.size_bytes,
764 bindings
765 .iter()
766 .map(|binding| binding.segment().length_bytes()),
767 self.coverage,
768 )?;
769 let source = match storage_kind {
770 OperationBufferStorageKind::DynamicContiguous => {
771 let binding = &bindings[0];
772 OperationRegionSource::Contiguous {
773 buffer: binding.buffer(),
774 physical_base_offset_bytes: binding
775 .segment()
776 .offset_bytes()
777 .checked_add(backing_window_offset)
778 .ok_or_else(|| {
779 invalid_operation(
780 "participant backing physical offset overflows u64",
781 )
782 })?,
783 retention: binding.retention(),
784 }
785 }
786 OperationBufferStorageKind::DynamicPaged => OperationRegionSource::Paged {
787 bindings,
788 logical_origin_bytes: backing_window_offset,
789 },
790 OperationBufferStorageKind::StaticContiguous => unreachable!(
791 "dynamic storage kind was validated before region construction"
792 ),
793 };
794 Ok(OperationBufferRegions {
795 storage_kind,
796 logical_offset_bytes,
797 logical_length_bytes,
798 source,
799 })
800 }
801 }
802 }
803}
804
805#[cfg(test)]
806mod operation_buffer_region_tests {
807 use super::{
808 packed_step_token_range_to_participant_local_readback, sequence_execution_shape,
809 translate_paged_segment, translate_step_participant_readback_range,
810 translate_step_participant_upload_range, validate_dynamic_binding_layout,
811 validate_value_binding_physical_coverage, OperationBufferCoverage, OperationBufferRegions,
812 OperationBufferStorageKind, OperationRegionSource, ValueBindingPhysicalCoverage,
813 };
814 use crate::vnext::{
815 AliasPolicy, BatchWorkShape, BufferDescriptor, BufferUsage, DeviceBufferRetention,
816 DynamicResourceDemand, DynamicResourceShape, ElementType, NodeWorkContract, ProgramValueId,
817 ResolvedTensorLayout, ResolvedTensorSpec, ResolvedValueBinding, ResolvedValueRole,
818 ResolvedValueStorage, ResourceId, TensorAccess, TokenSpanWork,
819 };
820 use std::sync::atomic::Ordering;
821 use std::sync::Arc;
822
823 #[test]
824 fn token_projection_validates_runtime_view_instead_of_canonical_extent() {
825 let resource_id = ResourceId::new("resource.activation.token-ids").unwrap();
826 let binding = ResolvedValueBinding::new(
827 ProgramValueId::new("value.input.token-ids").unwrap(),
828 ResolvedValueRole::Input,
829 0,
830 ResolvedTensorSpec::new(
831 vec![128],
832 ElementType::U32,
833 ResolvedTensorLayout::Contiguous,
834 )
835 .unwrap(),
836 TensorAccess::Read,
837 AliasPolicy::NoAlias,
838 BufferUsage::Activations,
839 None,
840 ResolvedValueStorage::single(resource_id.clone(), 0, 512, ElementType::U32).unwrap(),
841 )
842 .unwrap();
843 let work: NodeWorkContract = serde_json::from_value(serde_json::json!({
844 "tokens": {
845 "source": {
846 "value_id": "value.input.token-ids",
847 "role": "input",
848 "ordinal": 0,
849 "axis": 0,
850 "rank": 1,
851 "canonical_extent": 128
852 },
853 "projections": [{
854 "value_id": "value.input.token-ids",
855 "role": "input",
856 "ordinal": 0,
857 "axis": 0,
858 "rank": 1,
859 "canonical_extent": 128
860 }]
861 }
862 }))
863 .unwrap();
864 let descriptor = BufferDescriptor {
865 resource_id,
866 size_bytes: 160,
867 alignment_bytes: 16,
868 usage: BufferUsage::Activations,
869 element_type: ElementType::U32,
870 };
871 let component = &binding.storage().components()[0];
872 let demand = DynamicResourceDemand::tokens(4, 128).unwrap();
873
874 assert_eq!(
875 validate_value_binding_physical_coverage(
876 &work,
877 &binding,
878 component,
879 &descriptor,
880 Some(&demand),
881 16,
882 )
883 .unwrap(),
884 ValueBindingPhysicalCoverage::RuntimeTokenView
885 );
886 assert!(validate_value_binding_physical_coverage(
887 &NodeWorkContract::Fixed,
888 &binding,
889 component,
890 &descriptor,
891 Some(&demand),
892 16,
893 )
894 .is_err());
895 assert!(validate_value_binding_physical_coverage(
896 &work,
897 &binding,
898 component,
899 &descriptor,
900 Some(&DynamicResourceDemand::tokens(8, 128).unwrap()),
901 16,
902 )
903 .is_err());
904 }
905
906 #[test]
907 fn paged_translation_uses_each_chunks_exact_buffer() {
908 struct MockBinding<'a> {
909 buffer: &'a u8,
910 physical_offset_bytes: u64,
911 length_bytes: u64,
912 }
913
914 let first_buffer = 7_u8;
915 let second_buffer = 11_u8;
916 let bindings = [
917 MockBinding {
918 buffer: &first_buffer,
919 physical_offset_bytes: 64,
920 length_bytes: 8,
921 },
922 MockBinding {
923 buffer: &second_buffer,
924 physical_offset_bytes: 200,
925 length_bytes: 12,
926 },
927 ];
928 let mut next_logical_offset = 0;
929 let translated = bindings
930 .iter()
931 .filter_map(|binding| {
932 let (logical_end, region) = translate_paged_segment(
933 binding.buffer,
934 DeviceBufferRetention::plan(Arc::new(())),
935 binding.physical_offset_bytes,
936 binding.length_bytes,
937 next_logical_offset,
938 6,
939 16,
940 );
941 next_logical_offset = logical_end;
942 region
943 })
944 .collect::<Vec<_>>();
945
946 assert_eq!(translated.len(), 2);
947 let (first, first_physical, _first_retention) = translated[0].buffer_and_physical_range();
948 assert!(std::ptr::eq(first, &first_buffer));
949 assert_eq!(translated[0].logical_offset_bytes(), 6);
950 assert_eq!(first_physical, 70..72);
951 let (second, second_physical, _second_retention) =
952 translated[1].buffer_and_physical_range();
953 assert!(std::ptr::eq(second, &second_buffer));
954 assert_eq!(translated[1].logical_offset_bytes(), 8);
955 assert_eq!(second_physical, 200..208);
956 }
957
958 #[test]
959 fn contiguous_layout_rejects_cross_chunk_bindings() {
960 let first_buffer = 7_u8;
961 let second_buffer = 11_u8;
962 let bindings = [(&first_buffer, 8_u64), (&second_buffer, 12_u64)];
963
964 let error = validate_dynamic_binding_layout(
965 OperationBufferStorageKind::DynamicContiguous,
966 20,
967 bindings.iter().map(|(_, length_bytes)| *length_bytes),
968 OperationBufferCoverage::Exact,
969 )
970 .unwrap_err();
971
972 assert!(error
973 .to_string()
974 .contains("contiguous dynamic storage requires one physical segment binding"));
975 }
976
977 #[test]
978 fn operation_prefix_view_retains_wider_backing_coverage() {
979 validate_dynamic_binding_layout(
980 OperationBufferStorageKind::DynamicPaged,
981 64,
982 [64_u64, 64].into_iter(),
983 OperationBufferCoverage::BackingWindow { offset_bytes: 0 },
984 )
985 .unwrap();
986 validate_dynamic_binding_layout(
987 OperationBufferStorageKind::DynamicContiguous,
988 64,
989 [128_u64].into_iter(),
990 OperationBufferCoverage::BackingWindow { offset_bytes: 0 },
991 )
992 .unwrap();
993
994 assert!(validate_dynamic_binding_layout(
995 OperationBufferStorageKind::DynamicPaged,
996 64,
997 [64_u64, 64].into_iter(),
998 OperationBufferCoverage::Exact,
999 )
1000 .is_err());
1001 assert!(validate_dynamic_binding_layout(
1002 OperationBufferStorageKind::DynamicPaged,
1003 128,
1004 [64_u64].into_iter(),
1005 OperationBufferCoverage::BackingWindow { offset_bytes: 0 },
1006 )
1007 .is_err());
1008 }
1009
1010 #[test]
1011 fn participant_step_projection_keeps_upload_and_readback_coordinate_spaces_distinct() {
1012 let first_tokens = vec![1_u32; 20];
1013 let second_tokens = vec![2_u32; 9];
1014 let work = BatchWorkShape::test_only(vec![
1015 TokenSpanWork::from_token_ids(&first_tokens, 17..18).unwrap(),
1016 TokenSpanWork::from_token_ids(&second_tokens, 7..9).unwrap(),
1017 ])
1018 .unwrap();
1019 let tokens = DynamicResourceDemand::tokens(4, 32).unwrap();
1020
1021 assert_eq!(
1022 translate_step_participant_upload_range(&tokens, &work, 0, 68..72).unwrap(),
1023 0..4
1024 );
1025 assert_eq!(
1026 translate_step_participant_upload_range(&tokens, &work, 1, 28..36).unwrap(),
1027 4..12
1028 );
1029 assert_eq!(
1030 translate_step_participant_readback_range(&tokens, &work, 1, 0..8).unwrap(),
1031 4..12
1032 );
1033 assert_eq!(
1034 packed_step_token_range_to_participant_local_readback(&tokens, &work, 1, 4..12)
1035 .unwrap(),
1036 0..8
1037 );
1038 assert!(translate_step_participant_readback_range(&tokens, &work, 1, 28..36).is_err());
1039 assert!(
1040 packed_step_token_range_to_participant_local_readback(&tokens, &work, 1, 28..36)
1041 .is_err()
1042 );
1043 }
1044
1045 #[test]
1046 fn fixed_participant_step_projection_uses_disjoint_aligned_strides() {
1047 let tokens = [1_u32];
1048 let work = BatchWorkShape::test_only(vec![
1049 TokenSpanWork::from_token_ids(&tokens, 0..1).unwrap(),
1050 TokenSpanWork::from_token_ids(&tokens, 0..1).unwrap(),
1051 ])
1052 .unwrap();
1053 let fixed = DynamicResourceDemand::actual_sequences(16, 4).unwrap();
1054
1055 assert_eq!(
1056 translate_step_participant_upload_range(&fixed, &work, 0, 0..4).unwrap(),
1057 0..4
1058 );
1059 assert_eq!(
1060 translate_step_participant_upload_range(&fixed, &work, 1, 0..4).unwrap(),
1061 16..20
1062 );
1063 assert_eq!(
1064 translate_step_participant_readback_range(&fixed, &work, 1, 0..4).unwrap(),
1065 16..20
1066 );
1067 assert!(translate_step_participant_upload_range(&fixed, &work, 1, 0..17).is_err());
1068 assert_eq!(
1069 translate_step_participant_upload_range(
1070 &DynamicResourceDemand::fixed(16).unwrap(),
1071 &work,
1072 1,
1073 0..4,
1074 )
1075 .unwrap(),
1076 0..4
1077 );
1078 }
1079
1080 #[test]
1081 fn sequence_execution_shape_uses_the_executed_source_frontier() {
1082 let committed = DynamicResourceShape::from_validated(1, 8, 3);
1083 let projected = sequence_execution_shape(committed, 4).unwrap();
1084
1085 assert_eq!(projected.sequences(), 1);
1086 assert_eq!(projected.tokens(), 4);
1087 assert_eq!(projected.pages(), 3);
1088 assert!(sequence_execution_shape(committed, 0).is_err());
1089 assert!(sequence_execution_shape(committed, 9).is_err());
1090 assert!(
1091 sequence_execution_shape(DynamicResourceShape::from_validated(2, 8, 3), 4).is_err()
1092 );
1093 }
1094
1095 #[test]
1096 fn contiguous_translation_applies_physical_base_offset() {
1097 let buffer = 9_u8;
1098 let regions = OperationBufferRegions {
1099 storage_kind: OperationBufferStorageKind::DynamicContiguous,
1100 logical_offset_bytes: 16,
1101 logical_length_bytes: 32,
1102 source: OperationRegionSource::Contiguous {
1103 buffer: &buffer,
1104 physical_base_offset_bytes: 4096,
1105 retention: DeviceBufferRetention::plan(Arc::new(())),
1106 },
1107 };
1108
1109 let translated = regions.iter().collect::<Vec<_>>();
1110 assert_eq!(translated.len(), 1);
1111 let (actual, physical, _retention) = translated[0].buffer_and_physical_range();
1112 assert_eq!(*actual, buffer);
1113 assert_eq!(translated[0].logical_offset_bytes(), 16);
1114 assert_eq!(physical, 4112..4144);
1115 }
1116
1117 #[test]
1118 fn physical_region_retains_opaque_owner_after_translation_source_drops() {
1119 struct DropOwner(Arc<std::sync::atomic::AtomicBool>);
1120
1121 impl Drop for DropOwner {
1122 fn drop(&mut self) {
1123 self.0.store(true, Ordering::Release);
1124 }
1125 }
1126
1127 let buffer = 9_u8;
1128 let dropped = Arc::new(std::sync::atomic::AtomicBool::new(false));
1129 let owner = Arc::new(DropOwner(Arc::clone(&dropped)));
1130 let regions = OperationBufferRegions {
1131 storage_kind: OperationBufferStorageKind::DynamicContiguous,
1132 logical_offset_bytes: 0,
1133 logical_length_bytes: 8,
1134 source: OperationRegionSource::Contiguous {
1135 buffer: &buffer,
1136 physical_base_offset_bytes: 64,
1137 retention: DeviceBufferRetention::plan(Arc::clone(&owner)),
1138 },
1139 };
1140 drop(owner);
1141
1142 let translated = regions.iter().collect::<Vec<_>>();
1143 drop(regions);
1144 assert!(!dropped.load(Ordering::Acquire));
1145 let (_, physical, retention) = translated[0].buffer_and_physical_range();
1146 assert_eq!(physical, 64..72);
1147 drop(translated);
1148 assert!(!dropped.load(Ordering::Acquire));
1149
1150 drop(retention);
1151 assert!(dropped.load(Ordering::Acquire));
1152 }
1153}