kernel_planning.bend checks
raw source on the hub · import stelliferous@0.0.2.0/kernel_planning.bend as Kernel_planning
Structural cost of the 4x8 pipeline. Only guarded dimensions enter here. Packing and GEMM run in each leaf; reordering and final gather are serial.
5 imports
import Base import ./kernel_cost.bend as Cost import ./kernel_window.bend as KernelWindow import ./math_activation.bend as Activations import ./kernel_pipeline.bend as Pipeline
Types
type Owners source · line 9 · raw
Data
Owners@input_capacity:U32 -> @bias_capacity:U32 -> Owners
type Geometry source · line 13 · raw
Data
Image and stencil extents that decide which input rows a fork copies.
Geometry@channels:U32 -> @height:U32 -> @width:U32 -> @kernel:U32 -> @stride:U32 -> @padding:U32 -> @output_width:U32 -> Geometry
type Work source · line 16 · raw
Data
Work@positions:U32 -> @inner:U32 -> @rows:U32 -> @owners:Owners -> @geometry:Geometry -> @activation:0x9be3b13bf249759bc81e1958bcd1a4c0/math_activation.Activation -> Work
type InputRows source · line 20 · raw
Data
The input rows a partition node holds and the capacity of their owner.
InputRows@first:U32 -> @rows:U32 -> @capacity:Nat -> InputRows
type ForkInput source · line 24 · raw
Data
Allocation and moved/initialized payload are distinct for a copied band.
ForkInput@bytes:Nat -> @transfer:Nat -> @left:InputRows -> ForkInput
type Movement source · line 29 · raw
Data
critical_ns is the span (the costliest root-to-leaf path) and work_ns the sum over every leaf and fork; together they bound time on a given worker count.
Movement@packed:Nat -> @leaves:Nat -> @copies:Nat -> @critical_ns:F32 -> @work_ns:F32 -> @minimum_leaf_ns:F32 -> Movement
type Plan source · line 32 · raw
Data
Plan@packed:Bool -> @split_depth:U32 -> @workspace_bytes:Nat -> @estimated_ns:F32 -> Plan
Definitions
def capacity_loop source · line 35 · raw
@remaining:Nat -> @+value:U32 -> @+capacity:Nat -> @zero:Bool -> Nat
def capacity source · line 43 · raw
@+elements:U32 -> Nat
def float_parts source · line 47 · raw
@parts:Pair(Nat, Nat) -> F32
def payload_float source · line 51 · raw
@bytes:Nat -> F32
def weight_bytes source · line 54 · raw
@work:Work -> Nat
def reorder_ns source · line 59 · raw
@+work:Work -> @config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> F32
The weight reorder writes complete eight-channel tiles, including zero lanes.
def fork_bytes source · line 65 · raw
@+work:Work -> @input:Nat -> Nat
Each fork clones the reordered weights and bias, and splits the input rows.
def clone_bytes source · line 69 · raw
@+window:InputRows -> Nat
def band_rows source · line 73 · raw
@+band:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_window.Band -> @+channels:U32 -> @+width:U32 -> InputRows
def band_bytes source · line 77 · raw
@+band:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_window.Band -> @+channels:U32 -> @+width:U32 -> Nat
def input_transfer source · line 83 · raw
@copy:Bool -> @band:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_window.Band -> @window:InputRows -> @channels:U32 -> @width:U32 -> Nat
copied initializes the new owner and copies every logical band value. Array.clone instead copies the complete allocation, without initialization.
def input_bytes source · line 92 · raw
@copy:Bool -> @+band:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_window.Band -> @+window:InputRows -> @+channels:U32 -> @+width:U32 -> Nat
As in the pipelines: a checked band over aligned rows is copied and the second half keeps the parent; otherwise the parent owner is cloned.
def left_rows source · line 97 · raw
@copy:Bool -> @+band:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_window.Band -> @+window:InputRows -> @+channels:U32 -> @+width:U32 -> InputRows
def fork_window source · line 102 · raw
@+offset:U32 -> @+half:U32 -> @+window:InputRows -> @+geometry:Geometry -> ForkInput
def fork_input source · line 110 · raw
@+offset:U32 -> @+half:U32 -> @+window:InputRows -> @+work:Work -> ForkInput
def forked_bytes source · line 114 · raw
@+fork:ForkInput -> Nat
def forked_transfer source · line 118 · raw
@+fork:ForkInput -> Nat
def forked_left source · line 122 · raw
@+fork:ForkInput -> InputRows
def root_rows source · line 126 · raw
@+work:Work -> InputRows
def activation_ns source · line 132 · raw
@+activation:0x9be3b13bf249759bc81e1958bcd1a4c0/math_activation.Activation -> @+config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> F32
The activation pass reads and writes each logical output in place; the identity skips the pass.
def leaf_cost source · line 135 · raw
@span:U32 -> @+count:U32 -> @work:Work -> @+config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> Movement
def merge source · line 151 · raw
@bytes:Nat -> @transfer:Nat -> @byte_ns:F32 -> @left:Movement -> @right:Movement -> Movement
def movement source · line 158 · raw
@depth:Nat -> @+offset:U32 -> @+span:U32 -> @+window:InputRows -> @+work:Work -> @+config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> Movement
def workspace source · line 170 · raw
@+depth:U32 -> @+work:Work -> @cost:Movement -> Nat
def scheduled source · line 181 · raw
@+workers:U32 -> @+span:F32 -> @+total:F32 -> F32
Estimate the partition on workers by (work - span) / workers + span, Graham's bound for greedy list scheduling. BendRT does not steal work: it deals forked tasks across rings that workers claim each turn, so this is an estimate, not a guarantee. One worker gives the total work, so a split only adds its copies; more workers shorten the span but pay copies.
def estimate source · line 184 · raw
@+depth:U32 -> @+work:Work -> @config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> @cost:Movement -> @+workers:U32 -> F32
def fits source · line 194 · raw
@budget:Maybe<&2, Nat> -> @bytes:Nat -> Bool
def choose source · line 199 · raw
@fits:Bool -> @depth:U32 -> @bytes:Nat -> @+time:F32 -> @best:Plan -> Plan
def candidate source · line 203 · raw
@+depth:U32 -> @+work:Work -> @+config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> @+budget:Maybe<&2, Nat> -> @+workers:U32 -> @+cost:Movement -> @best:Plan -> Plan
def candidates source · line 209 · raw
@remaining:Nat -> @allowed:Bool -> @+depth:U32 -> @+tasks:U32 -> @+ceiling:U32 -> @+workers:U32 -> @+span:U32 -> @+work:Work -> @+config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> @+budget:Maybe<&2, Nat> -> @best:Plan -> Plan
def select source · line 224 · raw
@+work:Work -> @workers:U32 -> @+budget:Maybe<&2, Nat> -> @+config:0x9be3b13bf249759bc81e1958bcd1a4c0/kernel_cost.Configuration -> Plan
workers is the runtime's pool size. As in XNNPACK, several workers take up to five tasks each, so idle workers pick up the remaining ones; one worker never splits. Every leaf keeps at least one block and one grain of work, and the scheduling bound must strictly improve.