This document is relevant for: Trn2, Trn3
nki.language.blocks#
- nki.language.blocks(source: nki.language.NkiTensor | nki.language.NkiTileGrid | nki.language.NkiBlockGrid, *, tile_shape: Optional[tuple[int, ...]] = None, block_shape: tuple[int, ...]) NkiBlockGrid[source]#
Create a block view over a tensor where each block contains multiple tiles.
blocks()adds a second level of grouping above the tile grid. A block is a rectangular group of tiles intended as a coarser transfer or reuse grain, whiletile_shaperemains the compute grain presented tonisa.*operations. When one native access pattern can represent the complete block,block.dataallows it to participate in one aggregate operation.block_shapeis expressed in tile counts. For a4 x 4tile grid,block_shape=(2, 2)creates a2 x 2block grid:block grid: 2 x 2 +-------------------+-------------------+ | tile (0,0) (0,1) | tile (0,2) (0,3) | | tile (1,0) (1,1) | tile (1,2) (1,3) | +-------------------+-------------------+ | tile (2,0) (2,1) | tile (2,2) (2,3) | | tile (3,0) (3,1) | tile (3,2) (3,3) | +-------------------+-------------------+
Blocks are logical views over the source. Creating, regrouping, slicing, or indexing a block grid allocates no storage, copies no data, and emits no instruction.
Note
Indexing preserves
NkiBlockGrid. Callnki.language.tiles()on a selected block to expose its interior tile coordinates, then useNkiGrid.datawhen an instruction requires one native tensor operand.A block containing nonuniform boundary tiles may need to be split into uniform tile regions first.
- Parameters:
source – A direct
NkiTensor,NkiTileGrid, orNkiBlockGridwhose storage and selected addresses are shared by the returned view.tile_shape – The nominal source-element shape of one compute tile. Required for an
NkiTensor; optional for an existing grid.block_shape – The positive tile counts grouped along each block dimension. It must be a tuple with the same rank as the effective
tile_shape.
- Returns:
An
NkiBlockGridover the same storage. Itsshapecounts blocks, whiletile_shapeandblock_shapepreserve both levels of the hierarchy. Partial boundary blocks and tiles are retained at their exact logical extents; aggregatedataaccess still requires one exact native access pattern.- Raises:
TypeError – if
sourceis unsupported,tile_shapeis omitted for anNkiTensor, or a shape is not a tuple of exact Python integers.ValueError – if a shape entry is nonpositive,
block_shapeandtile_shapehave different ranks, the source cannot be tiled, or retiling or grouping cannot preserve the selected addresses.
Examples:
import nki import nki.isa as nisa import nki.language as nl @nki.jit def scale_by_block(src): dst = nl.ndarray( src.shape, dtype=src.dtype, buffer=nl.shared_hbm ) src_blocks = nl.blocks( src, tile_shape=(128, 256), block_shape=(2, 2), ) dst_blocks = nl.blocks( dst, tile_shape=(128, 256), block_shape=(2, 2), ) for i in range(src_blocks.shape[0]): for j in range(src_blocks.shape[1]): src_block = src_blocks[i, j] dst_block = dst_blocks[i, j] block = nl.blocks( nl.ndarray( src_block.element_shape, dtype=src.dtype, buffer=nl.sbuf, ), tile_shape=src_block.tile_shape, block_shape=src_block.block_shape, ) # copy entire block in single instruction nisa.dma_copy(dst=block.data, src=src_block.data) # demote to tile-grid to access individual tiles block_tiles = nl.tiles(block) for k in range(block_tiles.shape[0]): for p in range(block_tiles.shape[1]): tile = block_tiles[k, p].data nisa.tensor_scalar( dst=tile, data=tile, op0=nl.multiply, operand0=2.0, ) nisa.dma_copy( dst=dst_block.data, src=block.data, ) return dst
Source kinds.
The source can be
NkiTensororNkiTileGridorNkiBlockGrid.source tile_shape behavior ------------------ ----------------- ------------------------------ NkiTensor required tile, then group NkiTileGrid omitted group existing tiles NkiTileGrid supplied retile, then group NkiBlockGrid omitted remove old groups, regroup NkiBlockGrid supplied remove groups, retile, regroup
Remainder blocks.
Tile counts are ceiling-divided from the source extent, and block counts are ceiling-divided from the tile counts. A final block can therefore contain fewer tiles, and its final tile can contain fewer source elements. Both levels are clamped to the exact source extent.
See also
nki.language.tiles(): Create a tile grid or expose block tiles.NkiBlockGrid: Block-grid metadata and indexing behavior.
This document is relevant for: Trn2, Trn3