use crate::graph::partition::ExecutionPartition;
use crate::graph::ports::{CopyPolicy, EdgeContract, MediaCaps};
use crate::graph::signal::SignalSpec;
use crate::graph::spec::{EdgeId, InputPortRef, NodeId, OutputPortRef};
pub const FRAME_BYTES_MONO_48K: usize = 960 * 4; pub const EDGE_RING_CAPACITY_FRAMES: usize = 8; pub const EDGE_RECEIVER_MAX_IN_FLIGHT_FRAMES: usize = 1;
pub const MAX_EDGE_RING_CAPACITY_FRAMES: usize =
crate::frame::POOL_MAX_SLOTS - EDGE_RECEIVER_MAX_IN_FLIGHT_FRAMES;
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum PlanError {
#[error("input port '{port}' on node {node} has multiplicity One but receives multiple edges")]
FanInOnSinglePort { node: u32, port: String },
#[error("output port '{port}' on node {node} uses MoveExclusive in a fan-out group")]
MoveExclusiveFanOut { node: u32, port: String },
#[error("compiled edge {edge:?} is missing its negotiated contract")]
MissingEdgeContract { edge: EdgeId },
#[error("compiled edge {edge:?} is missing its declared output signal")]
MissingOutputSignal { edge: EdgeId },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EdgeMetricId(pub u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EdgeBufferPlan {
pub edge: EdgeId,
pub capacity_frames: usize,
pub bytes_per_frame: usize,
pub copy_policy: CopyPolicy,
}
impl EdgeBufferPlan {
pub fn total_bytes(&self) -> usize {
self.capacity_frames * self.bytes_per_frame
}
pub fn branch_copy_pool_capacity_frames(&self) -> usize {
if self.copy_policy == CopyPolicy::CopyToBranchPool {
self.capacity_frames
.saturating_add(EDGE_RECEIVER_MAX_IN_FLIGHT_FRAMES)
} else {
0
}
}
pub fn branch_copy_pool_bytes(&self) -> usize {
self.branch_copy_pool_capacity_frames()
.saturating_mul(self.bytes_per_frame)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MemoryPlan {
pub realtime_pool_bytes: usize,
pub branch_copy_pool_bytes: usize,
pub edge_buffers: Vec<EdgeBufferPlan>,
}
impl MemoryPlan {
pub fn edge_buffer(&self, edge: EdgeId) -> Option<&EdgeBufferPlan> {
self.edge_buffers.iter().find(|plan| plan.edge == edge)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PartitionGroup {
pub execution: ExecutionPartition,
pub nodes: Vec<NodeId>, }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FanOutGroup {
pub from: OutputPortRef,
pub targets: Vec<EdgeId>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FanInGroup {
pub into: InputPortRef,
pub sources: Vec<EdgeId>, }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypedEdgePlan {
pub edge: EdgeId,
pub from: OutputPortRef,
pub to: InputPortRef,
pub signal: SignalSpec,
pub media: MediaCaps,
pub contract: EdgeContract,
pub capacity_signals: usize,
pub metric_id: EdgeMetricId,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SourceOutputPlan {
pub from: OutputPortRef,
pub signal: SignalSpec,
pub media: MediaCaps,
pub branch_edges: Vec<EdgeId>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuntimePlan {
pub node_order: Vec<NodeId>,
pub partitions: Vec<PartitionGroup>,
pub memory_plan: MemoryPlan,
pub edge_metrics: Vec<(EdgeId, EdgeMetricId)>,
pub fan_out: Vec<FanOutGroup>,
pub fan_in: Vec<FanInGroup>,
pub typed_edges: Vec<TypedEdgePlan>,
pub source_outputs: Vec<SourceOutputPlan>,
pub edge_count: usize,
}
impl RuntimePlan {
#[cfg(any(test, feature = "internal-testing"))]
pub fn node_count(&self) -> usize {
self.node_order.len()
}
#[cfg(any(test, feature = "internal-testing"))]
pub fn partition(&self, ep: ExecutionPartition) -> Option<&PartitionGroup> {
self.partitions.iter().find(|group| group.execution == ep)
}
#[cfg(any(test, feature = "internal-testing"))]
pub fn metric_id(&self, edge: EdgeId) -> Option<EdgeMetricId> {
self.edge_metrics
.iter()
.find(|(id, _)| *id == edge)
.map(|(_, metric)| *metric)
}
pub fn typed_edge(&self, edge: EdgeId) -> Option<&TypedEdgePlan> {
self.typed_edges.iter().find(|plan| plan.edge == edge)
}
}