17 KiB
Scheduling implementation notes
The scheduling overview maps ownership and summarizes costs/complexity. Normative graph, pipeline, synchronization, and target contracts are linked there; the details below describe current implementation choices.
Publication, order, and local materialization
Deferred transfer planning allocates one host slot for repeated full-fragment requirements with the same physical producer, payload type, and source slot. One immutable producer result identifies one logical inference generation. Scalar source projections retain separate publications until their exact geometry has a common representation in both analyses.
Boundary planning moves a shared publication's notifications to its earliest existing send boundary. The first notification stores the payload before READY; later notifications emit READY only. Each reader retains its load and READY count. FREE planning includes every physical reader before the first overwrite of the shared slot. Existing unique writer-reader releases, register allocation, capacity-driven FREE-group merging, and restart barriers remain in force.
Host-slot allocation and shared-boundary planning take expected linear time and space in the number of physical consumer transfers. Structured send runs retain compact per-lane store flags. They do not duplicate payload shaping for notification-only readers.
materializeScheduledCompute records
graph IDs for publication identity, not execution order. Class lanes retain
graph encounter order independently of physical core IDs, preserving regular
source-lane mappings. Within each core, instances sort by verified scheduler
slots. Only consecutive compatible instances form homogeneous runs; class-lane
ordering must not reorder a core's work.
insertLocalFragment replaces a complete singleton insertion with a leading
unit-dimension reshape view only when:
- source and destination have static shapes;
- destination rank is source rank + 1, with leading dimension 1 and remaining dimensions exactly equal to the source shape;
- element type and encoding match;
- offset/size/stride lists all match destination rank; and
- every offset is statically zero, every size is the full corresponding destination dimension, and every stride is statically one.
This includes scalar sources. Other insertions retain tensor.insert_slice
semantics rather than being converted into views.
Receive forwarding belongs to
PimBufferizationPass.cpp,
after copy lowering and contiguity normalization. It requires a private
allocation and single-use receive/copy chain in the same block, zero source and
receive offsets, and equal sizes. The receive can sink to the copy target past
memory-effect-free operations and memref.load (including lane lookup loads).
Writes, synchronization, and other effectful operations are barriers. Forwarding
does not establish synchronization policy.
Transfer accounting and transpose costs
ComputeGraph.cpp uses the same cached publication map for
dependency extraction and projected transfer volume. Physical slots map back
to graph lanes; graph-range overlap is not a byte estimate. Blueprint edges
belong to this shared graph for both scheduling strategies.
Exact projections charge selected physical fragments individually, including each fragment's byte, endpoint-memory, and packet rounding. Conservative batch dependencies charge a producer chunk as one aggregate: scale element count by chunk lanes, multiply by effective bitwidth, then round to bytes once before memory-access/flit rounding. Dividing an already rounded whole-result byte count would lose sub-byte payloads. These two granularities are deliberate. Spatial can analyze sub-byte storage; PIM communication lowering requires byte-sized elements. Blueprint assembly charges per fragment. A full fragment receive directly into assembly storage omits duplicate endpoint-memory edge cost; later copy elimination can leave this estimate conservative.
CopyAccessPlan shares ordered contiguous-run geometry between projection
costing and PIM copy normalization. Its inputs are a logical copy shape and
proven source and destination strides, in elements. The immutable result keeps
outer dimensions, run count, run length, and relative offsets compact. Building
the plan takes linear time and space in rank, independent of loop trip counts.
It creates no IR and does not prove aliasing, storage ownership, or copy legality.
PIM bufferization still owns those decisions and the mapping to byte accesses.
The plan alone does not describe a complete scheduled memory-request stream.
Construction rejects an unrepresentable maximum relative element offset,
including the last element of each run. Callers still check byte scaling and
base-address addition.
Projection costing uses checked row-major strides. Unsupported flattened
offsets or strides produce at most one warning per graph cost query. The query
uses one separately rounded request per element as a conservative service bound.
It does not reject otherwise valid Spatial IR. Target lowering retains its own
address and layout legality checks. Unsupported estimates and malformed IR are
different conditions.
The PIM adapter's planComputeInputMaterialization reads scheduled Spatial
regions without changing them. It returns Unused, ForwardConstant,
ForwardFunctionInput, or CopyAtEntry. Function-input normalization forwards
host inputs into compute bodies before entry-copy materialization.
Single-core lowering forwards used arithmetic constants. Batch lowering copies
remaining inputs at body entry, including constants. Lowering and costing
consume the same decisions. The query has constant time and space per
input and does not expand lanes or loops. Abstract target work extraction uses
the same query. Subsequent canonicalization can remove uses.
getReusableOutputTensor shares read-only destination selection with vector
lowering. It identifies a tensor operand or requires fresh storage. It does not
prove a physical alias, assign an address, or replace one-shot bufferization.
The result is valid only for the current SSA graph. Changes to uses, operation
order, loop yields, or operands require recomputation. Lowering consumes this
decision immediately; it does not cache values across rewrites. Current PIM
bufferization consumes the explicit destination ties introduced by target
lowering. Output-copy forwarding also consumes the resulting allocation,
subview, copy, and dominance facts. An early destination choice alone cannot
describe those physical aliases or the final storage lifetimes.
Logical storage identity and physical address equality are different facts.
Local-memory planning can assign the same address to distinct allocations whose
lifetimes do not overlap. Scalar register setup therefore needs placement and
instruction-order information in addition to logical alias relationships.
Abstract cost estimates need not reconstruct these addresses.
This input plan does not count physical constant loads. A forwarded host
constant can need a new local buffer at each use. Bufferization, host folding,
alias analysis, and memory normalization determine the resulting requests.
isZeroBitPatternSplat shares constant-content classification between graph
accounting and code generation. PIM replaces eligible positive-zero and integer-zero
loads with local fills. Negative floating zero retains its distinct bit pattern.
Constant content is candidate-independent; input placement and buffer reuse
depend on the realized candidate. Production uses these shared decisions when
extracting Spatial execution events for the queue estimate.
Execution transpose costs share getTransposeRun with lowering: round memory
reads/writes per run and add vector execution when source stride is not one.
The Pimsim vector unit
charges vector payload bytes, not the full strided address footprint. The
compiler model follows that accounting; instruction setup/issue and contention
remain approximations, not extra inferred memory traffic.
Priorities, placement, and recovery limits
PipelineScheduling.cpp caches a per-template
adjustment between physical execution cost and nominal volume priority, scaling
it by chunk lanes. The original partitioning and packing candidate uses nominal
priorities; transposes count as bulk moves there. The memory-aware candidate
uses execution estimates for partitioning, retaining the existing core-budget
and packing heuristics. Final
selection evaluates bounded alternatives after physical placement, retaining
the original candidate when the combined resource estimates worsen. PEFT,
final schedule evaluation, and reported per-core demand use physical estimates.
These quantities must not be substituted for measured simulator periods.
Placement compares maximum per-core serial compute plus incident same-stage transfer demand, then completion/span and compute load. Each participating core is charged incident transfer demand as a placement proxy; those charges are not summed twice into elapsed time. Within 1% demand difference, span breaks the tie. Ordered packing plus dependency-tail priority biases cuts away from long dependent groups; it is not a throughput prediction. Measured simulator periods remain authoritative, including when a proxy improves.
Core budgets come from stage allocation and bounded capacity recovery. Failed packing budgets are not lower bounds. PEFT reservations prefer weight reuse when distinct weights exceed half the fleet's one-copy resident capacity; otherwise they favor communication/load. The reuse-first constructor supplies feasibility recovery without replacing a successful reservation, and can concentrate work. No exact combinatorial solver proves infeasibility after heuristic failure.
ResidentWeightPacking.hpp adds at most 17
constructions after initial failure: one reverse traversal, then up to 16
single-choice replays sharing 65,536 candidate checks. Scratch buffers are reused;
an extra O(T) failed-assignment snapshot is created only after both initial
orders fail. Weight indexing still has O(R W) worst-case equality work; partition
DP and latency insertion-gap searches remain superlinear as listed in the
scheduling overview. Cached PEFT center distances avoid a topology scan per task/candidate;
projection and priority analyses share/cache work rather than revisiting every
template body per chunk. Ready-transfer signature searches remain another
potential compile-time hotspot.
Spatial execution costs
SchedulingTarget::estimateRealizedScheduleCost is a read-only query on realized Spatial IR.
The PIM adapter extracts compact ordered execution events without constructing PIM operations.
It uses physical core assignments, communication, input-materialization decisions, and shared copy geometry.
No physical buffer addresses are required.
The shared engine models controller arbitration, source FIFOs, synchronization, and repeated generations.
Both arbitration policies are sensitivity checks, not guaranteed bounds.
The engine returns typed intervals and recurrence evidence before diagnostic serialization.
The target adapter adds static lowering support. Spatial owns the selection policy margin.
JSON fields are report output and do not control availability or eligibility.
Typed evaluation completes before reporting. Serialization never runs queue analysis.
Only optional diagnostics construct fingerprints, traces, and per-core resource reports.
Normal compilation extracts costs for multiple candidates and lowers only the selected schedule.
A single candidate bypasses the cost query entirely.
Candidate summaries distinguish available timing, static lowering support, and proved modeled recurrence.
Unknown support remains explicit. All candidates must satisfy these checks before comparison.
Unsupported identifies a known static violation, including invalid or repeated physical-core assignments.
Unknown identifies missing evidence or an unmodeled form, rather than a proven backend rejection.
Supported covers checked static forms and does not prove final allocation success.
A finite interval alone does not establish eligibility.
Preflight does not repeat bufferization or allocation. The backend owns final legality and signed 32-bit local-memory address validation. Resource failures marked by that owner permit an explicit retry from the original checkpoint. Unclassified failures stop compilation. Every attempted schedule and cause appears in the selection report.
Complete-state recurrence
Queue analysis checks translated states at one fixed core's body entry. Snapshots contain completion counts relative to core entry, ready-input counts, and busy state for every event. Run-length encoding keeps these records compact. Snapshots also contain pending events in arbitration order, remaining FIFO tokens, controller availability, and the tie policy. One pending firing per event makes node IDs sufficient to resolve simultaneous-event ties. The graph and target parameters remain fixed within each query. Time offsets use checked unsigned differences. Equal states require equal positive generation progress on every core. This proves recurrence for the deterministic abstract model, not physical execution-time accuracy. Reporting counters and analysis budgets are not hardware state.
Token initialization distances and graph edges remain immutable within a query. Consumption clears a drained queue and resets its head immediately. Drained and never-populated queues therefore have the same readiness state. Consumed prefixes, capacities, and compaction indices cannot affect future timing or FIFO contents. An idle controller's past completion cannot delay future arrivals. These normalizations require causal, monotonic transitions, which the proof checks.
Proof construction uses at most 256 generations and 16 MiB of snapshot storage.
Each checkpoint scans events, dependencies, and remaining tokens, then orders a copy of the pending frontier.
Exact comparisons use bounded history; hashes only filter comparisons.
Unproved recurrence remains explicit and cannot guide multi-candidate selection.
When recurrence is proved, its interval is authoritative for that arbitration policy and its report.
Proof-mode reports retain interval-window results under legacy_interval_window.
Normal costing stops once recurrence is proved. Detailed diagnostics can continue to collect interval-window evidence.
A legacy event or generation limit cannot override a later complete-state proof.
Budget limits, lack of ready events, and unproved recurrence remain separate evidence.
Internal diagnostic queries can cap interval-window work without reducing the recurrence proof budget.
The standalone instruction diagnostic keeps its interval-window behavior when recurrence is not requested.
Approximation and diagnostics
Scalar setup, copy forwarding, local reuse, and host-slice folding can change request readiness.
These effects remain prediction limitations. Physical address reuse itself adds no execution work.
Direct returns use the same return-operand test as lowering and preserve output multiplicity.
Captured weights used by vector operations require host loads.
Publication-only slices of compact results use CopyAccessPlan runs without an intermediate copy.
Matrix writeback requires complete aligned array groups.
Partial output groups, encoded layouts, unavailable geometry, and indirect output collection produce unavailable costs.
--pim-periodic-diagnostics adds resource summaries and ordered-request fingerprints.
Normal compilation creates no fingerprints, detailed traces, or sensitivity runs.
Optional local-copy sensitivity removes modeled copy work without changing generated code.
It does not describe a legal transformed program or an interval bound.
The standalone instruction diagnostic remains available for offline timing validation.
Checked arithmetic rejects unrepresentable sizes, loop bounds, repeated work, and service durations.
Work-only repeats remain compact. Immutable summaries are cached within a query.
Ordered memory and communication occurrences expand within the event budget.
For P compact records, R expanded events, and D dependencies, construction costs O(P+R+D) time.
With B processed events and T token propagations, queue evaluation costs O(B log R+T) time.
Storage costs O(P+R+G D) for bounded generation count G, plus bounded recurrence history.
Reports separate extraction, expansion, and queue-analysis times.
Fingerprints compare memory and blocking-operation order, without addresses or work between requests.
Equal fingerprints therefore do not prove equal request readiness or timing.