pl.system¶
同步、cache 与跨核原语。它们是产生副作用的语句而非产值算子 —— 多数没有返回值。
System operations for PyPTO Language DSL.
Sync/barrier ops are straight pass-through (no Tensor/Tile args). tpush ops wrap the IR-level functions, unwrapping Tile to Expr. tpop ops accept optional shape/dtype kwargs to create typed results.
AUTO = -1
module-attribute
¶
KernelType
¶
Bases: Enum
Which generated kernel an op belongs to.
A mixed InCore function is expanded into an AIC kernel and an AIV kernel.
This says which of the two a cross-core sync op lands in; MIX means both
take part, which only a barrier can ask for.
Two neighbouring enums mean different things:
FunctionType.AIC/.AIVclassify a function, and this classifies an op inside one. A function already declaredFunctionType.AIVneeds noKernelTypeon its ops -- there is only one kernel to land in.ir.CoreTypelabels one physical core in the SoC inventory, which is whatBackend::GetCoreCountcounts. That is hardware; this is not, andMIXhas noCoreTypecounterpart at all.
Members carry no wire value: each op spells the same kernel differently in
its IR attr (system.syncall writes "aic_only" where
system.sync_set writes "aic"), so the lowering tables are explicit.
SyncAllMode
¶
sync_src(*, set_pipe, wait_pipe, event_id, span=None)
¶
Send a synchronization signal (Set Flag).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
set_pipe
|
PipeType
|
Pipe that sets the flag |
required |
wait_pipe
|
PipeType
|
Pipe that will wait on the flag |
required |
event_id
|
int
|
Event identifier |
required |
span
|
Span | None
|
Optional source span for debugging (auto-captured if not provided) |
None
|
Returns:
| Type | Description |
|---|---|
Call
|
Call expression for system.sync_src |
sync_dst(*, set_pipe, wait_pipe, event_id, span=None)
¶
Wait for a synchronization signal (Wait Flag).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
set_pipe
|
PipeType
|
Pipe that sets the flag |
required |
wait_pipe
|
PipeType
|
Pipe that waits on the flag |
required |
event_id
|
int
|
Event identifier |
required |
span
|
Span | None
|
Optional source span for debugging (auto-captured if not provided) |
None
|
Returns:
| Type | Description |
|---|---|
Call
|
Call expression for system.sync_dst |
sync_set(event_id, *, pipe, ffts_mode=None, core_type=None, span=None)
¶
Set a Cube/Vector cross-core event using a static or dynamic event id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_id
|
IntLike
|
Event to signal. An int in the user-available range 0-13, or a
dynamic |
required |
pipe
|
PipeType
|
Pipe the event is raised on. The matching |
required |
ffts_mode
|
int | None
|
Optional FFTS mode, 0, 1 or 2. Accepted by |
None
|
core_type
|
KernelType | None
|
|
None
|
span
|
Span | None
|
Optional source span |
None
|
sync_wait(event_id, *, pipe, core_type=None, span=None)
¶
Wait for a Cube/Vector cross-core event using a static or dynamic event id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_id
|
IntLike
|
Event to wait on -- the one a matching |
required |
pipe
|
PipeType
|
Pipe the event is awaited on; must match the |
required |
core_type
|
KernelType | None
|
|
None
|
span
|
Span | None
|
Optional source span |
None
|
set_ffts(workspace, *, span=None)
¶
Declare the A3 FFTS setup operand for explicit cross-core synchronization.
bar_v(*, span=None)
¶
Vector unit barrier.
bar_m(*, span=None)
¶
Matrix unit barrier.
bar_all(*, span=None)
¶
Global barrier synchronization.
fence(*, span=None)
¶
Memory barrier over global memory.
Lowers to pto.fence.barrier_all #pto.fence_scope<gm>.
cacheinvalid(tensor=None, shapes=None, offsets=None, *, span=None)
¶
Invalidate one addressed cache line, or the whole GM address space.
Two forms selected by arity:
- No arguments: invalidate the entire GM address space; lowers to
pto.cmo.cacheinvalid all #pto.address_space<gm>. (tensor, shapes, offsets): locate a tensor sub-region and invalidate only the cache line containing that view's base address; lowers topto.partition_view+pto.cmo.cacheinvalid %payload_view single_cache_line : !pto.partition_tensor_view<...>for every region size, a single element included.shapesdoes not make the operation walk every cache line in the region.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tensor
|
Tensor | None
|
Target tensor whose view base addresses the cache line; omit for whole-GM. |
None
|
shapes
|
Sequence[int | Scalar] | None
|
Per-dimension region sizes; length must equal the tensor rank. |
None
|
offsets
|
Sequence[int | Scalar] | None
|
Per-dimension start offsets; length must equal the tensor rank. |
None
|
span
|
Span | None
|
Optional source span for debugging (auto-captured if not provided). |
None
|
syncall(*, core_type=KernelType.MIX, mode=SyncAllMode.HARD, gm_workspace=None, used_cores=None, span=None)
¶
Cross-core all-participant barrier (pto::SYNCALL).
Two modes:
mode=pl.SyncAllMode.HARD(default): FFTS barrier with no operands. Requires the enclosingpl.spmdlaunch to fill all physical cores ofcore_type(a partial launch deadlocks on device — error 507018). The compiler rejects a partial-occupancy hard launch at compile time (HardSyncallOccupancyverifier, issue #1935). Seepypto.ir.op.system_ops.syncall.mode=pl.SyncAllMode.SOFT: GM-polling barrier that works at partial occupancy. Each participant updates a shared counter in an exclusive 64-byte GM cache line and polls until all participants arrive. Supported for every participant set.
Both modes synchronize arrival only. They do not wait for preceding data
instructions or publish/invalidate business-data cache lines. For a
cross-core GM handoff that may span multiple cache lines, conservatively
call whole-GM pl.system.cacheinvalid() and pl.system.fence() before
the barrier, then call pl.system.cacheinvalid() again on the consumer
before it reads. The tensor-region overload covers only the cache line
containing the view's base address.
Soft-mode arguments:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
core_type
|
KernelType
|
Participant set, a |
MIX
|
mode
|
SyncAllMode
|
A |
HARD
|
gm_workspace
|
Tensor | None
|
Soft mode only. A shared, zero-initialized GM |
None
|
used_cores
|
IntLike | None
|
Soft mode only. Required participant count as a Python int
in the INT32 range or an |
None
|
span
|
Span | None
|
Optional source span for debugging (auto-captured if not provided). |
None
|
Returns:
| Type | Description |
|---|---|
Call
|
Call expression for system.syncall. |
tpush_to_aiv(tile, *, split, lane_stride=None, id=None, span=None)
¶
Push tile data from AIC to AIV via cross-core pipe.
The Vector side receives it with tpop_from_aic and releases the
slot with tfree_to_aic; split and id must match across all
three.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
Tile to send. Its Cube-side buffer stays live until the consumer frees the slot. |
required |
split
|
int
|
pto-isa split code (0=none, 1/2=up-down/left-right, 3/4=the same axes over an odd extent). Selects the axis along which the two AIV lanes divide the tile, and how their extents relate; 0 sends it whole. |
required |
lane_stride
|
int | None
|
Partition stride carried when a ragged boundary was balanced across the two AIV lanes; omit for the default box partition. |
None
|
id
|
int | None
|
Optional frontend pipe id. Omit to use PTOAS default id 0. |
None
|
span
|
Span | None
|
Optional source span |
None
|
tpush_to_aic(tile, *, split, id=None, span=None)
¶
Push tile data from AIV to AIC via cross-core pipe.
The Cube side receives it with tpop_from_aiv and releases the
slot with tfree_to_aiv; split and id must match across all
three.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
Tile to send. Its Vector-side buffer stays live until the consumer frees the slot. |
required |
split
|
int
|
Split mode (0=none, 1=up-down, 2=left-right). Selects the axis along which the two AIV lanes divide the tile; 0 sends it whole. |
required |
id
|
int | None
|
Optional frontend pipe id. Omit to use PTOAS default id 0. |
None
|
span
|
Span | None
|
Optional source span |
None
|
tpop_from_aic(*, shape=None, dtype=None, split=0, lane_stride=None, id=None, span=None)
¶
Pop tile data from AIC cross-core pipe into AIV.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
list[int] | None
|
Shape of the tile to receive |
None
|
dtype
|
DataType | None
|
Data type of the tile to receive |
None
|
split
|
int
|
pto-isa split code (0=none, 1/2=up-down/left-right, 3/4=the same axes over an odd extent) |
0
|
lane_stride
|
int | None
|
Partition stride carried when a ragged boundary was balanced across the two AIV lanes; omit for the box partition |
None
|
id
|
int | None
|
Optional frontend pipe id. Omit to use PTOAS default id 0. |
None
|
span
|
Span | None
|
Optional source span |
None
|
tpop_from_aiv(*, shape=None, dtype=None, split=0, id=None, span=None)
¶
Pop tile data from AIV cross-core pipe into AIC.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
list[int] | None
|
Shape of the tile to receive |
None
|
dtype
|
DataType | None
|
Data type of the tile to receive |
None
|
split
|
int
|
Split mode (0=none, 1=up-down, 2=left-right) |
0
|
id
|
int | None
|
Optional frontend pipe id. Omit to use PTOAS default id 0. |
None
|
span
|
Span | None
|
Optional source span |
None
|
aic_initialize_pipe(c2v_consumer_buf=0, v2c_consumer_buf=0, *, dir_mask, slot_size, slot_num=None, local_slot_num=None, id=None, span=None)
¶
Initialize cross-core pipe on AIC side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
c2v_consumer_buf
|
PipeBufOperand
|
C2V consumer buffer base (Expr, int, or DSL |
0
|
v2c_consumer_buf
|
PipeBufOperand
|
V2C consumer buffer base (Expr, int, or DSL |
0
|
dir_mask
|
int
|
Direction mask for pipe |
required |
slot_size
|
int
|
Size of each pipe slot |
required |
slot_num
|
int | None
|
Optional ring-buffer slot count. Omit to let PTOAS pick its default (8 unidirectional, 4 per direction bidirectional). |
None
|
local_slot_num
|
int | None
|
Optional local slot count (a2/a3 only, must be
|
None
|
id
|
int | None
|
Optional frontend pipe id. Omit to use PTOAS default id 0. |
None
|
span
|
Span | None
|
Optional source span |
None
|
aiv_initialize_pipe(c2v_consumer_buf=0, v2c_consumer_buf=0, *, dir_mask, slot_size, slot_num=None, local_slot_num=None, id=None, span=None)
¶
Initialize cross-core pipe on AIV side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
c2v_consumer_buf
|
PipeBufOperand
|
C2V consumer buffer base (Expr, int, or DSL |
0
|
v2c_consumer_buf
|
PipeBufOperand
|
V2C consumer buffer base (Expr, int, or DSL |
0
|
dir_mask
|
int
|
Direction mask for pipe |
required |
slot_size
|
int
|
Size of each pipe slot |
required |
slot_num
|
int | None
|
Optional ring-buffer slot count. Omit to let PTOAS pick its default (8 unidirectional, 4 per direction bidirectional). |
None
|
local_slot_num
|
int | None
|
Optional local slot count (a2/a3 only, must be
|
None
|
id
|
int | None
|
Optional frontend pipe id. Omit to use PTOAS default id 0. |
None
|
span
|
Span | None
|
Optional source span |
None
|
reserve_buffer(*, name, size, base=AUTO, span=None)
¶
Reserve a named buffer for cross-core communication.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Buffer name for cross-core reference. |
required |
size
|
int
|
Buffer size in bytes. |
required |
base
|
int
|
Base address in local SRAM. Use AUTO (-1) to let the compiler pick a non-conflicting address, or an explicit integer for manual kernels. |
AUTO
|
span
|
Span | None
|
Optional source span. |
None
|
Returns:
| Type | Description |
|---|---|
Scalar
|
|
import_peer_buffer(*, name, peer_func, span=None)
¶
Import a buffer from a peer function in the same group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Buffer name to import (must match peer's reserve_buffer name). |
required |
peer_func
|
str
|
Name of the peer function that owns the buffer. |
required |
span
|
Span | None
|
Optional source span. |
None
|
Returns:
| Type | Description |
|---|---|
Scalar
|
|
tfree_to_aic(tile, span=None, *, split=None, id=None)
¶
Release ring buffer slot back to AIC producer.
Call this once the tile from tpop_from_aic has been consumed.
Until it runs, the slot stays occupied and the producer blocks once the ring fills.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
The tile returned by the matching |
required |
span
|
Span | None
|
Optional source span |
None
|
split
|
int | None
|
Leave |
None
|
id
|
int | None
|
Optional frontend pipe id, inherited from the originating |
None
|
tfree_to_aiv(tile, span=None, *, split=None, id=None)
¶
Release ring buffer slot back to AIV producer.
Call this once the tile from tpop_from_aiv has been consumed.
Until it runs, the slot stays occupied and the producer blocks once the ring fills.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tile
|
Tile
|
The tile returned by the matching |
required |
span
|
Span | None
|
Optional source span |
None
|
split
|
int | None
|
Leave |
None
|
id
|
int | None
|
Optional frontend pipe id, inherited from the originating |
None
|
task_invalid(*, span=None)
¶
Sentinel pl.Scalar[pl.TASK_ID] for the "no producer" TaskId.
DSL surface of the IR-level system.task_invalid op. The printer emits
pl.system.task_invalid() for auto-scope TaskId placeholders so dumps
are valid Python; user code in pl.manual_scope normally writes None
and the parser lowers it to this op.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span
|
Span | None
|
Optional source span. |
None
|
Returns:
| Type | Description |
|---|---|
Scalar
|
|
task_dummy(*, deps)
¶
Dependency-only dummy TaskId barrier.
This is a parser construct: pl.system.task_dummy(deps=[...]) is
intercepted syntactically and lowered to system.task_dummy with manual
dep edges. The body exists so the public DSL name resolves for static
checkers and imports.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
deps
|
Sequence[Scalar | Array | None]
|
TaskIds the barrier waits on -- each a |
required |
Returns:
| Type | Description |
|---|---|
Scalar
|
A |
Scalar
|
it instead of listing all of |
available_cluster_count(*, span=None)
¶
This run's MIX cluster (= AIC) count, as reported by the runtime.
Use it as the core_num of a mixed (AIC+AIV) or cube-only
pl.spmd launch instead of a literal: the count belongs to the device
the run lands on, so a baked-in literal under- or over-fills the launch on
any device with a different usable cluster count. A hard
pl.system.syncall needs full occupancy to complete, so this is the only
launch width that keeps it deadlock-free across devices.
Codegen lowers it to the orchestration helper rt_available_cluster_count().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span
|
Span | None
|
Optional source span. |
None
|
Returns:
| Type | Description |
|---|---|
Scalar
|
|
Example
with pl.spmd(pl.system.available_cluster_count(), sync_start=True): ... out = self.mixed_kernel(a, b, out)
Pass the call directly as core_num as shown. Binding it to a name first
(n = pl.system.available_cluster_count()) also compiles, but the launch
width then reaches the outlined Spmd wrapper as a reference to a variable in
the caller, which the IR printer cannot re-parse.
available_aiv_count(*, span=None)
¶
This run's standalone AIV core count, as reported by the runtime.
The AIV counterpart of available_cluster_count — the
core_num of a vector-only pl.spmd launch. A mixed launch sizes itself on
available_cluster_count (one block per cluster), not on
this.
Codegen lowers it to the orchestration helper rt_available_aiv_count().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span
|
Span | None
|
Optional source span. |
None
|
Returns:
| Type | Description |
|---|---|
Scalar
|
|
Example
with pl.spmd(pl.system.available_aiv_count(), sync_start=True): ... out = self.aiv_kernel(a, b, out)