pypto_pro.language.make_tile_group#

产品支持情况#

  • Ascend 950PR&950DT系列产品:支持

  • Atlas A3系列产品:不支持

  • Atlas A2系列产品:不支持

功能说明#

一次性创建一组同规格且可轮转复用的Tile,为每块Tile绑定独立地址,并可选建立Tile与一个或多个mutex ID的对应关系。解析器会将TileGroup展开成多个pypto_pro.language.make_tile操作;启用auto_mutex后,框架根据该元数据为涉及这些Tile的后续操作自动插入mutex同步。

缓冲深度由depth或非空mutex_ids的长度确定:

  • 1-buffer(depth为1,或mutex_ids长度为1):仅包含一块Tile,可使用current()或group[0]访问,不产生实际的轮转效果。

  • 2-buffer(double-buffer/ping-pong):两块Tile交替使用。

  • 3-buffer、4-buffer或N-buffer:多块Tile循环轮转,适用于通过加深流水隐藏搬运延迟的场景。

与多次调用pypto_pro.language.make_tile相比,make_tile_group统一管理地址排布、轮转位置和mutex元数据,无需手动维护Tile下标与同步关系。TileGroup本身不在运行时执行加锁或解锁;启用auto_mutex后,其mutex映射在编译期用于生成同步操作。

下图以UB中的双缓冲为例,展示单个基地址如何展开成两个连续Tile槽位,以及地址、mutex和轮转访问之间的对应关系。

make_tile_group双缓冲地址与轮转关系

函数原型#

pypto_pro.language.make_tile_group(
    *,
    type: TileType,
    addrs: Union[int, List[int]],
    mutex_ids: Optional[Sequence[Union[int, Sequence[int]]]] = None,
    depth: Optional[int] = None,
    fwd_ids: Optional[Sequence[int]] = None,
    bwd_ids: Optional[Sequence[int]] = None,
) -> TileGroup

参数说明#

参数

输入/输出

说明

type

输入

Tile类型描述,pypto_pro.language.TileType类型。

addrs

输入

Tile地址,int或List[int]类型,必须非负并在编译期确定,且满足对应Buffer的地址对齐要求。传入单个基地址时,第i块Tile的地址为base + i × slot_size,其中slot_size为单块Tile占用的字节数;传入地址列表时,列表长度必须等于mutex_ids的长度或depth的值,并按顺序为每块Tile指定地址。地址列表可用于非连续地址排布。

mutex_ids

输入

mutex ID配置,Sequence[int或Sequence[int]]类型,可选,也可传入None或空列表。mutex ID的取值范围为[0, 31]。每块Tile对应的mutex ID数量必须一致,同一块Tile的多个mutex ID不得重复,不同Tile之间可以使用相同的mutex ID。

depth

输入

TileGroup深度,int类型,可选,必须为正的编译期整数。mutex_ids为None或空列表时必须指定depth;未指定depth且mutex_ids非空时,由mutex_ids的长度确定;同时指定时,两者必须相等。

fwd_ids

输入

仅用于自动CV并行流水,表示核间正向同步的event id,Sequence[int]类型,可选。未开启自动流水时忽略。

bwd_ids

输入

仅用于自动CV并行流水,表示核间反向同步的event id,Sequence[int]类型,可选。未开启自动流水时忽略。

约束说明#

  • 使用group[i]访问Tile时,i支持编译期整数或运行时整数表达式,例如g[i]、g[(i + 1) % 2]。索引值应位于[0, num_tile)范围内;num_tile为mutex_ids非空时的列表长度,否则为depth。

  • 配置非空mutex_ids且启用auto_mutex时,框架根据Tile与mutex的映射插入同步;未启用auto_mutex时,调用方必须自行保证Tile的访问时序。

返回值说明#

返回TileGroup对象,支持以下访问方式:

访问方式

说明

group.next()

推进轮转位置并返回下一块Tile;连续调用时按照TileGroup大小循环选择Tile。

group.current()

不推进轮转位置,返回当前Tile。

group.previous()

不推进轮转位置,返回当前Tile的前一块Tile。

group[i]

返回下标为i的Tile,i支持编译期整数或运行时整数表达式;该操作不读取或改变轮转位置。

TileGroup还可直接传给pypto_pro.language.set_validshape,批量设置组内所有Tile的valid_shape。

调用示例#

2-buffer(double-buffer / ping-pong)#

import pypto_pro.language as pl

TILE = 128
MM_M, MM_K, MM_N = 256, 128, 256


@pl.jit(auto_mutex=True)
def tile_group_matmul_kernel(
    a: pl.Tensor[[MM_M, MM_K], pl.DT_FP16],
    b: pl.Tensor[[MM_K, MM_N], pl.DT_FP16],
    c: pl.Tensor[[MM_M, MM_N], pl.DT_FP32],
):
    # L1 双缓冲(next() 轮转)
    a_l1_db = pl.make_tile_group(
        type=pl.TileType(shape=[TILE, MM_K], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Mat),
        addrs=0x00000, mutex_ids=[0, 1])
    b_l1_db = pl.make_tile_group(
        type=pl.TileType(shape=[MM_K, TILE], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Mat),
        addrs=0x10000, mutex_ids=[2, 3])
    # L0A Buffer、L0B Buffer和L0C Buffer均使用单Tile组(current())
    a_left = pl.make_tile_group(
        type=pl.TileType(shape=[TILE, MM_K], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Left),
        addrs=0x0000, mutex_ids=[4])
    b_right = pl.make_tile_group(
        type=pl.TileType(shape=[MM_K, TILE], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Right),
        addrs=0x0000, mutex_ids=[5])
    acc = pl.make_tile_group(
        type=pl.TileType(shape=[TILE, TILE], dtype=pl.DT_FP32, target_memory=pl.MemorySpace.Acc),
        addrs=0x0000, mutex_ids=[6])

    with pl.section_cube():
        for i in pl.range(0, MM_M, TILE):
            for j in pl.range(0, MM_N, TILE):
                cur_a = a_l1_db.next()      # 双缓冲轮转
                cur_b = b_l1_db.next()
                al = a_left.current()       # 单Tile组
                br = b_right.current()
                ac = acc.current()
                pl.load(cur_a, a, [i, 0])
                pl.load(cur_b, b, [0, j])
                pl.move(al, cur_a)
                pl.move(br, cur_b)
                pl.matmul(ac, al, br)
                pl.store(c, ac, [i, j])

在L1 Buffer中创建4-buffer#

import pypto_pro.language as pl

TILE = 128
MM_M, MM_K, MM_N = 256, 128, 256


@pl.jit(auto_mutex=True)
def tile_group_4buf_matmul_kernel(
    a: pl.Tensor[[MM_M, MM_K], pl.DT_FP16],
    b: pl.Tensor[[MM_K, MM_N], pl.DT_FP16],
    c: pl.Tensor[[MM_M, MM_N], pl.DT_FP32],
):
    a_l1 = pl.make_tile_group(
        type=pl.TileType(shape=[TILE, MM_K], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Mat),
        addrs=0x00000, mutex_ids=[0, 1, 2, 3])
    b_l1 = pl.make_tile_group(
        type=pl.TileType(shape=[MM_K, TILE], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Mat),
        addrs=0x20000, mutex_ids=[4, 5, 6, 7])
    a_left = pl.make_tile_group(
        type=pl.TileType(shape=[TILE, MM_K], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Left),
        addrs=0x0000, mutex_ids=[8])
    b_right = pl.make_tile_group(
        type=pl.TileType(shape=[MM_K, TILE], dtype=pl.DT_FP16, target_memory=pl.MemorySpace.Right),
        addrs=0x0000, mutex_ids=[9])
    acc = pl.make_tile_group(
        type=pl.TileType(shape=[TILE, TILE], dtype=pl.DT_FP32, target_memory=pl.MemorySpace.Acc),
        addrs=0x0000, mutex_ids=[10])

    with pl.section_cube():
        for i in pl.range(0, MM_M, TILE):
            for j in pl.range(0, MM_N, TILE):
                cur_a = a_l1.next()
                cur_b = b_l1.next()
                al = a_left.current()
                br = b_right.current()
                ac = acc.current()
                pl.load(cur_a, a, [i, 0])
                pl.load(cur_b, b, [0, j])
                pl.move(al, cur_a)
                pl.move(br, cur_b)
                pl.matmul(ac, al, br)
                pl.store(c, ac, [i, j])

使用地址列表创建非连续Buffer#

# 两块 Tile 分别落在 0x0 和 0x10000
tt = pl.TileType(shape=[64, 64], dtype=pl.DT_FP32, target_memory=pl.MemorySpace.Vec)
buf = pl.make_tile_group(type=tt, addrs=[0x0, 0x10000], mutex_ids=[0, 1])