Skip to main content

MatmulTileScenario

Optimization scenarios · Implementation: mlsysim/engine/scenario_definitions/optimization.py.

Construct this scenario with keyword inputs. The fields below show the types and defaults declared by this class.

C = A B with A m x k and B k x n, computed one tile_m x tile_n output tile at a time, stepping through the reduction tile_k elements per step.

Operands are operand_bytes each and the accumulator accumulator_bytes. The on-chip store holds one A tile and one B tile (two of each when double buffered) and the accumulator tile. Traffic counts element moves between memory and the on-chip store: A is loaded once per output-tile column, B once per output-tile row, and C written once. The single-cell loop orders (no tile) count one held value per cell: the other operands stream once per MAC, and a partial sum that is not held is read and written once per MAC.

Notes

Equation: The calculation members below define macs, flops, tiles_m, tiles_n, tiles_k, output_tiles, tile_products, tile_product_flops, tile_product_bytes, tile_intensity, unblocked_intensity, compulsory_intensity, buffer_copies, a_tile_bytes, b_tile_bytes, accumulator_tile_bytes, operand_tile_bytes, live_bytes, fits, a_bytes, a_elements, b_elements, c_elements, a_moves, b_moves, tiled_moves, global_loads_per_mac, partial_sum_moves, a_stationary_moves, output_stationary_moves, b_stationary_moves, row_b_reads.

Assumptions: Dense multiplication uses two FLOPs per MAC and fixed-width operands/accumulators; full-tile work counts padded edges.

Excludes: Bank conflicts, cache effects, scheduling overhead, and precision-dependent arithmetic throughput.

References

Derivation: C = A B with A m x k and B k x n, computed one tile_m x tile_n output tile at a time, stepping through the reduction tile_k elements per step. Each member records the corresponding algebra or named physics function.

Examples

Evaluate the named configuration and display a modeled result.

>>> from mlsysim import Scenarios
>>> case = Scenarios.Matmul4096Fp16Tile128
>>> value = case.tile_intensity
>>> print(f"{value:.3g}")
64

Attributes

Name Description
a_bytes Full A-matrix storage in bytes at operand precision.
a_elements Number of elements in the M-by-K input matrix A.
a_moves A-element reads when A is reloaded for every output tile column.
a_stationary_moves Element transfers when each cell retains A while B and partial sums stream.
a_tile_bytes Live A-tile operand buffers in bytes, including double buffering if enabled.
accumulator_bytes
accumulator_tile_bytes Output-tile accumulator storage in bytes at accumulator precision.
b_elements Number of elements in the K-by-N input matrix B.
b_moves B-element reads when B is reloaded for every output tile row.
b_stationary_moves Element transfers when each cell retains B while A and partial sums stream.
b_tile_bytes Live B-tile operand buffers in bytes, including double buffering if enabled.
buffer_copies Operand buffer-copy count: two for double buffering, otherwise one.
c_elements Number of elements in the M-by-N output matrix C.
compulsory_intensity FLOP/byte if each A, B, and C element moves exactly once at operand precision.
double_buffered
flops Dense multiplication work in FLOPs, two operations per MAC.
global_loads_per_mac Operand loads per MAC for a full tile, reciprocal tile dimensions summed.
k
live_bytes Combined operand and accumulator bytes simultaneously resident.
m
macs Multiply-accumulate count for dense M-by-K times K-by-N multiplication.
n
operand_bytes
operand_tile_bytes Combined A and B operand-buffer bytes, excluding accumulators.
output_stationary_moves Element transfers when output sums remain local and both operands stream.
output_tiles Number of output tiles, tile rows times tile columns.
partial_sum_moves Partial-sum transfers if each MAC reads and writes its sum.
tile_intensity FLOP per operand byte loaded for a full tile, excluding output traffic.
tile_k
tile_m
tile_n
tile_product_bytes Operand bytes loaded for one full A-tile/B-tile product.
tile_product_flops FLOPs for one full tile product; edge padding is counted as full work.
tile_products Tile products required, one per output tile and reduction slice.
tiled_moves Total element transfers: tiled A and B reads plus one output write.
tiles_k Reduction tile count, rounding K up to a multiple of reduction width.
tiles_m Output tile-row count, rounding M up to a multiple of tile height.
tiles_n Output tile-column count, rounding N up to a multiple of tile width.
unblocked_intensity FLOP/byte when every MAC loads both operands without reuse.

Methods

Name Description
fits Whether live bytes fit the supplied capacity quantity; equality is feasible.
row_b_reads B-element reads after reuse along cells cells; integer division requires complete sharing groups.

fits

engine.scenario_types.MatmulTileScenario.fits(capacity)

Whether live bytes fit the supplied capacity quantity; equality is feasible.

Equation: bool(live_bytes <= capacity).

row_b_reads

engine.scenario_types.MatmulTileScenario.row_b_reads(cells)

B-element reads after reuse along cells cells; integer division requires complete sharing groups.

B reads when each B value passes along a row of cells cells holding A values.

Equation: macs // cells.

m

Type: int.

Declared default: required.

n

Type: int.

Declared default: required.

k

Type: int.

Declared default: required.

tile_m

Type: int.

Declared default: required.

tile_n

Type: int.

Declared default: required.

tile_k

Type: int.

Declared default: required.

operand_bytes

Type: Quantity.

Declared default: required.

accumulator_bytes

Type: Quantity.

Declared default: required.

double_buffered

Type: bool.

Declared default: False.

macs

engine.scenario_types.MatmulTileScenario.macs

Multiply-accumulate count for dense M-by-K times K-by-N multiplication.

Equation: m * n * k.

flops

engine.scenario_types.MatmulTileScenario.flops

Dense multiplication work in FLOPs, two operations per MAC.

Equation: Q_(2 * macs, 'flop').

tiles_m

engine.scenario_types.MatmulTileScenario.tiles_m

Output tile-row count, rounding M up to a multiple of tile height.

Equation: -(-m // tile_m).

tiles_n

engine.scenario_types.MatmulTileScenario.tiles_n

Output tile-column count, rounding N up to a multiple of tile width.

Equation: -(-n // tile_n).

tiles_k

engine.scenario_types.MatmulTileScenario.tiles_k

Reduction tile count, rounding K up to a multiple of reduction width.

Equation: -(-k // tile_k).

output_tiles

engine.scenario_types.MatmulTileScenario.output_tiles

Number of output tiles, tile rows times tile columns.

Equation: tiles_m * tiles_n.

tile_products

engine.scenario_types.MatmulTileScenario.tile_products

Tile products required, one per output tile and reduction slice.

A-tile-by-B-tile products: every output tile sums tiles_k of them.

Equation: output_tiles * tiles_k.

tile_product_flops

engine.scenario_types.MatmulTileScenario.tile_product_flops

FLOPs for one full tile product; edge padding is counted as full work.

Equation: Q_(2 * tile_m * tile_n * tile_k, 'flop').

tile_product_bytes

engine.scenario_types.MatmulTileScenario.tile_product_bytes

Operand bytes loaded for one full A-tile/B-tile product.

One A tile and one B tile loaded.

Equation: ((tile_m * tile_k + tile_k * tile_n) * operand_bytes).to('byte').

tile_intensity

engine.scenario_types.MatmulTileScenario.tile_intensity

FLOP per operand byte loaded for a full tile, excluding output traffic.

FLOP per operand byte loaded: (2 / b) T_M T_N / (T_M + T_N), independent of T_K.

Equation: (tile_product_flops / tile_product_bytes).to('flop/byte').magnitude.

unblocked_intensity

engine.scenario_types.MatmulTileScenario.unblocked_intensity

FLOP/byte when every MAC loads both operands without reuse.

No reuse: every MAC (2 FLOP) loads its two operands.

Equation: (Q_(2, 'flop') / (2 * operand_bytes)).to('flop/byte').magnitude.

compulsory_intensity

engine.scenario_types.MatmulTileScenario.compulsory_intensity

FLOP/byte if each A, B, and C element moves exactly once at operand precision.

Each of A, B, and C moved exactly once, all at operand_bytes.

Equation: (flops / moved).to('flop/byte').magnitude.

buffer_copies

engine.scenario_types.MatmulTileScenario.buffer_copies

Operand buffer-copy count: two for double buffering, otherwise one.

Equation: 2 if double_buffered else 1.

a_tile_bytes

engine.scenario_types.MatmulTileScenario.a_tile_bytes

Live A-tile operand buffers in bytes, including double buffering if enabled.

Equation: (buffer_copies * tile_m * tile_k * operand_bytes).to('byte').

b_tile_bytes

engine.scenario_types.MatmulTileScenario.b_tile_bytes

Live B-tile operand buffers in bytes, including double buffering if enabled.

Equation: (buffer_copies * tile_k * tile_n * operand_bytes).to('byte').

accumulator_tile_bytes

engine.scenario_types.MatmulTileScenario.accumulator_tile_bytes

Output-tile accumulator storage in bytes at accumulator precision.

Equation: (tile_m * tile_n * accumulator_bytes).to('byte').

operand_tile_bytes

engine.scenario_types.MatmulTileScenario.operand_tile_bytes

Combined A and B operand-buffer bytes, excluding accumulators.

The A and B buffers alone (what a GPU stages in shared memory).

Equation: a_tile_bytes + b_tile_bytes.

live_bytes

engine.scenario_types.MatmulTileScenario.live_bytes

Combined operand and accumulator bytes simultaneously resident.

Every buffer live at once: 2 T_M T_K + 2 T_K T_N + 4 T_M T_N bytes for FP16 operands, FP32 sums.

Equation: operand_tile_bytes + accumulator_tile_bytes.

a_bytes

engine.scenario_types.MatmulTileScenario.a_bytes

Full A-matrix storage in bytes at operand precision.

Equation: (m * k * operand_bytes).to('byte').

a_elements

engine.scenario_types.MatmulTileScenario.a_elements

Number of elements in the M-by-K input matrix A.

Equation: m * k.

b_elements

engine.scenario_types.MatmulTileScenario.b_elements

Number of elements in the K-by-N input matrix B.

Equation: k * n.

c_elements

engine.scenario_types.MatmulTileScenario.c_elements

Number of elements in the M-by-N output matrix C.

Equation: m * n.

a_moves

engine.scenario_types.MatmulTileScenario.a_moves

A-element reads when A is reloaded for every output tile column.

Equation: a_elements * tiles_n.

b_moves

engine.scenario_types.MatmulTileScenario.b_moves

B-element reads when B is reloaded for every output tile row.

Equation: b_elements * tiles_m.

tiled_moves

engine.scenario_types.MatmulTileScenario.tiled_moves

Total element transfers: tiled A and B reads plus one output write.

Element moves with the tiling: A per output-tile column, B per output-tile row, C once.

Equation: a_moves + b_moves + c_elements.

global_loads_per_mac

engine.scenario_types.MatmulTileScenario.global_loads_per_mac

Operand loads per MAC for a full tile, reciprocal tile dimensions summed.

Operand loads from memory per MAC inside a full tile: 1/T_N + 1/T_M.

Equation: 1 / tile_n + 1 / tile_m.

partial_sum_moves

engine.scenario_types.MatmulTileScenario.partial_sum_moves

Partial-sum transfers if each MAC reads and writes its sum.

A partial sum read and written once per MAC.

Equation: 2 * macs.

a_stationary_moves

engine.scenario_types.MatmulTileScenario.a_stationary_moves

Element transfers when each cell retains A while B and partial sums stream.

One cell holds an A value: A loaded once; B and the partial sums stream.

Equation: a_elements + macs + partial_sum_moves.

output_stationary_moves

engine.scenario_types.MatmulTileScenario.output_stationary_moves

Element transfers when output sums remain local and both operands stream.

One cell holds the running sum: A and B stream, C written once.

Equation: 2 * macs + c_elements.

b_stationary_moves

engine.scenario_types.MatmulTileScenario.b_stationary_moves

Element transfers when each cell retains B while A and partial sums stream.

One cell holds a B value: B loaded once; A and the partial sums stream.

Equation: b_elements + macs + partial_sum_moves.

Back to top