ExSystolic.Clock (ex_systolic v0.2.0)

Copy Markdown View Source

The clock drives systolic array execution tick by tick.

The clock is the orchestrator: it delegates to the selected backend's tick sequence in strict order, for as many ticks as requested.

Backend selection

By default, the interpreted (single-process) backend is used. You can select the partitioned (tile-based parallel) backend via the :backend option:

# Interpreted (default)
Clock.run(array, ticks: 10)

# Partitioned
Clock.run(array, ticks: 10, backend: :partitioned, tile_rows: 4, tile_cols: 4)

Both backends produce identical results for the same inputs.

Determinism

Because the interpreted backend is purely functional and the partitioned backend uses BSP barriers (no interleaving between compute and communication), running Clock.run(array, ticks: n) always produces the same result for the same inputs, regardless of backend choice.

API

  • run/2 -- execute N ticks
  • step/1 -- execute exactly one tick (interpreted only)

Summary

Functions

Runs the array for the given number of ticks.

Executes a single tick of the array using the interpreted backend.

Functions

run(array, opts)

Runs the array for the given number of ticks.

Returns the final array state, which includes the updated PEs, links, tick counter, and trace.

Options

  • :ticks -- number of ticks (required)
  • :backend -- :interpreted (default) or :partitioned
  • :tile_rows -- rows per tile (partitioned only)
  • :tile_cols -- cols per tile (partitioned only)

Examples

iex> alias ExSystolic.{Array, Clock, PE.MAC}
iex> array = Array.new(rows: 1, cols: 1) |> Array.fill(MAC) |> Array.connect(:west_to_east) |> Array.connect(:north_to_south)
iex> array = Array.input(array, :west, [{{0,0}, [3, 2]}])
iex> array = Array.input(array, :north, [{{0,0}, [4, 5]}])
iex> result = Clock.run(array, ticks: 2)
iex> result.tick
2

step(array)

Executes a single tick of the array using the interpreted backend.

Follows the strict order:

  1. INJECT external input streams into boundary link buffers
  2. READ all link buffers
  3. EXECUTE all PEs
  4. COLLECT outputs
  5. WRITE outputs into link buffers
  6. RECORD trace

Examples

iex> alias ExSystolic.{Array, Clock, PE.MAC}
iex> array = Array.new(rows: 1, cols: 1) |> Array.fill(MAC) |> Array.connect(:west_to_east) |> Array.connect(:north_to_south)
iex> array = Array.input(array, :west, [{{0,0}, [3]}])
iex> array = Array.input(array, :north, [{{0,0}, [4]}])
iex> result = Clock.step(array)
iex> result.tick
1