pypto_pro.language.system.dcci#

产品支持情况#

  • Ascend 950PR/Ascend 950DT:支持

  • Atlas A3 训练系列产品/Atlas A3 推理系列产品:不支持

  • Atlas A2 训练系列产品/Atlas A2 推理系列产品:不支持

功能说明#

对指定地址对应的数据缓存执行清理并失效(Data Cache Clean and Invalidate,DCCI)。典型用途是在跨核或跨流水共享数据时,清除当前执行单元可能持有的旧缓存副本,使后续访问能够观察到已发布的数据。

dcci只处理缓存状态,不等价于流水同步、跨核事件或内存屏障。调用者仍须保证生产者写入已经完成,并使用与通信协议匹配的同步接口建立先后关系。

函数原型#

pypto_pro.language.system.dcci(
    target: Union[Tensor, Tile],
    offset: Optional[Union[int, Sequence[int], Expr]] = None,
    *,
    cache_line: CacheLine = pypto_pro.language.CacheLine.ENTIRE_DATA_CACHE,
    dst: DcciDst = pypto_pro.language.DcciDst.AUTO,
) -> None

参数说明#

参数

输入/输出

说明

target

输入

GM Tensor变量,或已分配在UB中的Tile。

offset

输入

可选,元素偏移,单位为target.dtype元素。GM Tensor支持各维偏移列表/元组,也支持整型常量或运行时整型标量表达式表示的线性偏移;列表/元组长度须与Tensor维数一致,框架按Tensor stride换算线性偏移。UB Tile仅支持整型常量或运行时整型标量表达式表示的线性偏移。缺省时为0,即使用目标起始地址;偏移不得使有效地址越出目标已分配范围。

cache_line

输入

可选,编译期pypto_pro.language.CacheLine枚举值,默认pypto_pro.language.CacheLine.ENTIRE_DATA_CACHE。缓存行为64字节;SINGLE_CACHE_LINE的地址无需由用户向下对齐,硬件操作包含该地址的缓存行。若数据跨越多个缓存行,须逐行调用或使用ENTIRE_DATA_CACHE。

dst

输入

可选,编译期pypto_pro.language.DcciDst枚举值,默认pypto_pro.language.DcciDst.AUTO。各枚举值的含义和适用目标参见DcciDst。

约束说明#

  • cache_line和dst必须在编译期确定,不能由运行时Scalar或Tensor动态选择。

  • SINGLE_CACHE_LINE只覆盖一个64字节缓存行。处理地址区间[addr, addr + bytes)时,调用次数至少为该区间覆盖的缓存行数,不能只对首地址调用一次。

  • ENTIRE_DATA_CACHE作用于整个数据缓存,offset不会缩小其作用范围;该模式开销大于单缓存行操作。

  • DCCI不是同步原语。生产者通过MTE3等流水写出数据后,必须先同步到S流水再执行DCCI或发布标志;消费者也必须先完成相应跨核等待,再执行缓存处理和数据读取。具体事件号和同步模式由上层通信协议决定。

  • 频繁对整个缓存执行DCCI会造成明显性能损失;已知共享数据范围时应优先按64字节缓存行处理。

返回值说明#

无。

调用示例#

单缓存行失效(GM Tensor)#

import os
import pypto_pro.language as pl
import torch

@pl.jit()
def dcci_gm_kernel(
    inp: pl.Tensor[[16, 16], pl.DT_FP32],
    out: pl.Tensor[[16, 16], pl.DT_FP32],
):
    # 对 inp 起始元素所在地址的64字节缓存行执行清理并失效
    pl.system.dcci(inp, [0, 0], cache_line=pl.CacheLine.SINGLE_CACHE_LINE)


if __name__ == "__main__":
    device = f"npu:{int(os.environ.get('TILE_FWK_DEVICE_ID', 0))}"
    torch.npu.set_device(device)

    inp = torch.ones([16, 16], device=device, dtype=torch.float32)
    out = torch.ones([16, 16], device=device, dtype=torch.float32)

    dcci_gm_kernel(inp, out)
    torch.npu.synchronize()

    # DCCI只处理缓存状态,不修改数据
    assert torch.allclose(out.cpu(), inp.cpu())
    print("dcci done")

全缓存失效#

# 对整个数据缓存执行DCCI,开销大于单缓存行操作,offset不会缩小其作用范围
pl.system.dcci(inp, cache_line=pl.CacheLine.ENTIRE_DATA_CACHE)

DCCI搭配同步使用#

对UB Tile执行DCCI时,须先用sync_src/sync_dst建立流水先后关系(DCCI不是同步原语):

@pl.jit(auto_mutex=True)
def dcci_ub_kernel(
    inp: pl.Tensor[[16, 16], pl.DT_FP32],
    out: pl.Tensor[[16, 16], pl.DT_FP32],
):
    tt = pl.TileType(shape=[16, 16], dtype=pl.DT_FP32, target_memory=pl.MemorySpace.Vec)
    t = pl.make_tile(tt, addr=0x0000)
    with pl.section_vector():
        pl.load(t, inp, [0, 0])
        # load(MTE2)完成后才能执行 dcci(S)
        pl.system.sync_src(set_pipe=pl.PipeType.MTE2, wait_pipe=pl.PipeType.S, event_id=0)
        pl.system.sync_dst(set_pipe=pl.PipeType.MTE2, wait_pipe=pl.PipeType.S, event_id=0)
        pl.system.dcci(t, cache_line=pl.CacheLine.SINGLE_CACHE_LINE)
        # dcci(S)完成后再 store(MTE3),否则store可能读到失效前的旧数据
        pl.system.sync_src(set_pipe=pl.PipeType.S, wait_pipe=pl.PipeType.MTE3, event_id=1)
        pl.system.sync_dst(set_pipe=pl.PipeType.S, wait_pipe=pl.PipeType.MTE3, event_id=1)
        pl.store(out, t, [0, 0])