Skip to content

关键特性说明

自动同步概述

自动同步功能可减少开发者手动插入同步的工作量,自动同步特性需要了解以下要点:

  • 自动插入同步的范围是SIMD-API的核内同步(包含单流水同步和多流水同步)
  • 部分接口间的同步由硬件保证,无需手动或者自动插入同步,具体内容请参考硬件保证的同步
  • TPipe-TQue框架编程范式和开启cce-auto-sync编译选项都能自动插入同步(后者由毕昇编译器自动插入),两种方式不互斥、各自插入的同步类型不同,可同时生效。
  • TPipe-TQue框架编程范式和开启cce-auto-sync编译选项自动插入同步的前提是必须满足各自的使用约束。

自动同步决策树

如图1所示,开发者可以按照图中流程判断一对接口之间是否需要手动插入同步,自动同步的支持情况见表1表2表3

Ascend C提供了三层梯度化SIMD编程接口,下面列出了各类接口管理同步的具体情况:

基于Tensor的CPP编程操作的Tensor可以分为基础Tensor和扩展Tensor,两种Tensor的具体含义和区别请参考Tensor内存抽象

两种方式的使用约束和支持的同步类型分别在后续章节展开:TPipe-TQue框架范式自动同步开启cce-auto-sync编译选项自动同步

图1 自动同步决策树

硬件保证的同步

  • 针对Ascend 950PR/Ascend 950DT,PIPE_V与PIPE_V间的单流水同步由硬件保证。

TPipe-TQue框架编程范式自动同步

使用约束

TPipe-TQue框架编程范式的自动同步功能需满足以下前提条件方可生效:

  • 使用TPipe-TQue框架编程范式。
  • 正确使用EnQue/DeQue、AllocTensor/FreeTensor接口才能保证其自动同步功能正常运作,本条约束对应反例2

支持的同步类型

  • 单流水同步

    TPipe-TQue框架编程范式不支持插入单流水同步。

  • 多流水同步

    在TPipe-TQue框架编程范式下,框架能够自动插入部分多流水同步,以解决写后读(WAR,Write‑After‑Read)和读后写(RAW,Read‑After‑Write)两类数据依赖,具体原理参考TPipe-TQue框架数据依赖与同步机制

    NPU架构2201为例,该硬件架构下AIV和AIC中不同流水线的自动同步支持情况分别如表1表2所示。

    表1 在TPipe-TQue框架编程范式下,AIV中不同流水线的同步情况

    源流水\目的流水PIPE_SPIPE_VPIPE_MTE2PIPE_MTE3
    PIPE_S----
    PIPE_V--支持支持
    PIPE_MTE2-支持-支持
    PIPE_MTE3-支持支持-

    表2 在TPipe-TQue框架编程范式下,AIC中不同流水线的同步情况

    源流水\目的流水PIPE_SPIPE_MPIPE_MTE1PIPE_MTE2PIPE_MTE3PIPE_FIX
    PIPE_S------
    PIPE_M--支持支持-支持
    PIPE_MTE1-支持-支持支持支持
    PIPE_MTE2-支持支持-支持-
    PIPE_MTE3--支持支持--
    PIPE_FIX-支持支持---

反例

以下反例展示了因未满足使用约束而无法自动插入同步的典型场景。

  • 反例1:未使用TPipe-TQue框架编程范式。例如,将基于TPipe-TQue框架编程范式的Add向量加法的样例改写为基于静态Tensor编程范式时,静态Tensor编程范式无法自动插入MTE2_V,并最终导致样例执行失败。

    C++
    AscendC::LocalMemAllocator<AscendC::Hardware::UB> ubAllocator;
    AscendC::LocalTensor<float> xLocal = ubAllocator.Alloc<float, blockLength>();
    AscendC::LocalTensor<float> yLocal = ubAllocator.Alloc<float, blockLength>();
    AscendC::LocalTensor<float> zLocal = ubAllocator.Alloc<float, blockLength>();
    
    AscendC::DataCopy(xLocal, xGm, blockLength);
    AscendC::DataCopy(yLocal, yGm, blockLength);
    
    AscendC::Add(zLocal, xLocal, yLocal, blockLength);
    
  • 反例2:未正确使用EnQue/DeQue、AllocTensor/FreeTensor接口(由TPipe-TQue框架编程范式提供)。例如,在基于TPipe-TQue框架编程范式的Add向量加法的样例中,如果缺失了xLocal = inQueueX.DeQue<float>()会导致TPipe-TQue框架编程范式无法自动插入MTE2_V,并最终导致样例执行失败。

    C++
    // 使用DataCopy将输入从GM搬运到UB,并通过EnQue将LocalTensor入队,供后续计算阶段DeQue取用。
    AscendC::LocalTensor<float> xLocal = inQueueX.AllocTensor<float>();
    AscendC::LocalTensor<float> yLocal = inQueueY.AllocTensor<float>();
    AscendC::DataCopy(xLocal, xGm, blockLength);
    AscendC::DataCopy(yLocal, yGm, blockLength);
    inQueueX.EnQue(xLocal);
    inQueueY.EnQue(yLocal);
    
    // DeQue取出输入张量,在UB内执行Add,并将结果EnQue到输出队列,供后续写回GM。
    // xLocal未从inQueueX中执行DeQue操作,导致TPipe-TQue框架编程范式无法自动插入MTE2_V。
    yLocal = inQueueY.DeQue<float>();
    AscendC::LocalTensor<float> zLocal = outQueueZ.AllocTensor<float>();
    AscendC::Add(zLocal, xLocal, yLocal, blockLength);
    

开启cce-auto-sync编译选项自动同步(毕昇编译器自动插入)

使用约束

开启cce-auto-sync编译选项的自动同步功能需满足以下前提条件方可生效:

支持的同步类型

  • 单流水同步

    • 针对NPU架构2201,PIPE_V之间由毕昇编译器自动完成同步插入。
    • PIPE_MTE2/PIPE_MTE3在搬运地址有重叠的情况下需要开发者插入同步(具体示例请参考PipeBarrier约束说明)。
  • 多流水同步

    • Vector计算单元中,毕昇编译器支持自动插入PIPE_V与PIPE_S、PIPE_MTE2与PIPE_S、PIPE_MTE3与PIPE_S之间的多流水同步(双向)。
    • Cube计算单元中,毕昇编译器不支持自动插入任何类型的同步。

NPU架构2201为例,该硬件架构下AIV中不同流水线的自动同步支持情况如表3所示。

表3 开启cce-auto-sync编译选项,AIV中不同流水线的同步情况

源流水\目的流水PIPE_SPIPE_VPIPE_MTE2PIPE_MTE3
PIPE_S-支持支持支持
PIPE_V支持支持--
PIPE_MTE2支持---
PIPE_MTE3支持---

反例

以下反例展示了因未满足使用约束而无法自动插入同步的典型场景。

基于指针的C语言编程的Add样例中,操作x_local的第0个元素时直接通过指针访问。此时,毕昇编译器无法在PIPE_MTE2(asc_copy_gm2ub)与PIPE_S之间自动插入同步。

C++
__gm__ float* x_gm = x + block_idx * block_length;
__gm__ float* y_gm = y + block_idx * block_length;
__gm__ float* z_gm = z + block_idx * block_length;

__ubuf__ float x_local[block_length];
__ubuf__ float y_local[block_length];
__ubuf__ float z_local[block_length];


asc_copy_gm2ub(x_local, x_gm, block_length * sizeof(float));
asc_copy_gm2ub(y_local, y_gm, block_length * sizeof(float));

x_local[0] = 1.0f;

asc_sync();

asc_add(z_local, x_local, y_local, block_length);
asc_sync();

asc_copy_ub2gm(z_gm, z_local, block_length * sizeof(float));
asc_sync();

自动同步日志功能

开发者在使用自动同步功能时,往往不确定TPipe-TQue框架编程范式或毕昇编译器是否已插入同步指令、插入了哪些类型的同步、以及插入的具体位置。为了帮助开发者验证自动同步的插入情况,本节介绍两种查看自动同步信息的方式:NPU仿真模式的指令日志功能和毕昇编译器的自动同步日志功能。

NPU仿真模式指令日志

TPipe-TQue框架编程范式插入的同步并没有单独的日志功能,但是开启NPU仿真模式后(设置编译选项DCMAKE_ASC_RUN_MODE=sim,参考编译运行),可以通过指令日志同时查看TPipe-TQue框架编程范式和毕昇编译器自动插入的同步指令信息。

基于TPipe-TQue框架编程范式的Add向量加法的样例中,开启NPU仿真模式后,在build目录下查看vector核0的指令日志(core0.veccore0.instr_log.dump)片段如下:

Text
[info] [00002009] (PC: 0x10d0d378) MTE2     : (Binary: 0x40a210bc) SET_FLAG  PIPE:MTE2, TRIGGER PIPE:VEC, FLAG ID:0, 
[info] [00002009] (PC: 0x10d0d380) MTE2     : (Binary: 0x40a210b4) SET_FLAG  PIPE:MTE2, TRIGGER PIPE:VEC, FLAG ID:1, 
[info] [00002009] (PC: 0x10d0d32c) MTE2     : (Binary: 0x711cb788) MOV_OUT_TO_UB  Src:OUT, Dst:UB, XD:X14=0x2000, XN:X11=0x11321800, XM:X15=0x1000010,  id: 4
[info] [00002010] (PC: 0x10d0d5ac) SCALAR   : (Binary: 0x04c02010) ST_XD_XN_IMM  dtype:B64, XD:X0=0x1, XN:X2=0x1c7ae8, IMM:0x10, 
[info] [00002010] (PC: 0x10d0d3ac) VEC      : (Binary: 0x40c210ac) WAIT_FLAG  PIPE:MTE2, TRIGGER PIPE:VEC, FLAG ID:0, 
[info] [00002011] (PC: 0x10d0d5b4) SCALAR   : (Binary: 0x0406b003) ST_XD_XN_IMM  dtype:B8, XD:X3=0, XN:X11=0x1c7b90, IMM:0x3, 
[info] [00002011] (PC: 0x10d0d3e4) VEC      : (Binary: 0x40c210a8) WAIT_FLAG  PIPE:MTE2, TRIGGER PIPE:VEC, FLAG ID:1, 
[info] [00002012] (PC: 0x10d0d5bc) SCALAR   : (Binary: 0x0e001500) STI_XN_XM  dtype:B8, XN:X1=0x1c7b90, XM:X10=0, #POST:0, #IMM_TYPE:ZERO, 
[info] [00002028] (PC: 0x10d0d5e0) SCALAR   : (Binary: 0x0f35e5a1) STI_XN_IMM  dtype:B8, XN:X30=0x1c8270, IMM:0xd2d, #POST:0, #IMM_TYPE:ONE, 
[info] [00002028] (PC: 0x10d0d484) VEC      : (Binary: 0x80400008) MOVEMASK  XN:X2=0x800, Pos:0, Id:295
[info] [00002028] (PC: 0x10d0d494) VEC      : (Binary: 0x40e00400) BAR  PIPE:VEC
[info] [00002045] (PC: 0x10d0d498) VEC      : (Binary: 0x804000bc) MOVEMASK  XN:X15=0, Pos:1, Id:300
[info] [00002118] (PC: 0x10d0d4b8) VEC      : (Binary: 0x85c4c6bc) VADD  XD:X2=0x4000, XN:X12=0, XM:X13=0x2000, XT:X15=0x100080808010101, Dtype:F32, Id:308

以上日志片段大致与Add向量加法样例的如下代码片段对应,日志中MOV_OUT_TO_UB对应DataCopy(源地址GM、目的地址UB)、SET_FLAG对应SetFlagWAIT_FLAG对应WaitFlagVADD对应Add,从日志第2009行、第2010行和第2011行可以看到,TPipe-TQue框架编程范式在PIPE_MTE2和PIPE_V之间自动插入了SetFlagWaitFlag指令。

C++
AscendC::LocalTensor<float> xLocal = inQueueX.AllocTensor<float>();
AscendC::LocalTensor<float> yLocal = inQueueY.AllocTensor<float>();
AscendC::DataCopy(xLocal, xGm, blockLength);
AscendC::DataCopy(yLocal, yGm, blockLength);
inQueueX.EnQue(xLocal);
inQueueY.EnQue(yLocal);

// DeQue取出输入张量,在UB内执行Add,并将结果EnQue到输出队列,供后续写回GM。
xLocal = inQueueX.DeQue<float>();
yLocal = inQueueY.DeQue<float>();
AscendC::LocalTensor<float> zLocal = outQueueZ.AllocTensor<float>();
AscendC::Add(zLocal, xLocal, yLocal, blockLength);

毕昇编译器自动同步日志

毕昇编译器提供--cce-auto-sync-log=<file>编译选项可以输出同步插入信息到<file>文件中,帮助开发者显式地识别毕昇编译器在算子文件中插入的同步指令信息。

注意

获取毕昇编译器自动同步日志,还需要设置-g编译选项,用于获取算子代码文件行号。

根据开发场景不同,添加该编译选项的方式如下:

  • 直接使用毕昇编译器的场景,可以直接在编译命令中添加该编译选项。
  • 使用Ascend C kernel直调算子工程,可以通过ascendc_compile_options添加该编译选项。
  • 使用Ascend C自定义算子开发工程,可以通过add_ops_compile_options添加该编译选项。

如下的代码文件sync_log_test.h:

C++
LocalTensor<T> dstLocal;
T ave_tmp = 0;
Vector_OP1(dstLocal, params); 
ave_tmp = dstLocal.GetValue(0);
Vector_OP2(dstLocal, params); 
for (int i = 0; i < ave_tmp; ++i) {
    dstLocal.SetValue(i,0);
}

开启自动同步后,同步指令的插入位置如下:

C++
LocalTensor<T> dstLocal;
T ave_tmp = 0;
Vector_OP1(dstLocal, params); 
SetFlag<HardEvent::V_S>(EVENT_ID0);
WaitFlag<HardEvent::V_S>(EVENT_ID0);
ave_tmp = dstLocal.GetValue(0);
PipeBarrier<PIPE_V>();
SetFlag<HardEvent::S_V>(EVENT_ID0);
WaitFlag<HardEvent::S_V>(EVENT_ID0);
Vector_OP2(dstLocal, params); 
SetFlag<HardEvent::V_S>(EVENT_ID0);
WaitFlag<HardEvent::V_S>(EVENT_ID0);
for (int i = 0; i < ave_tmp; ++i) {
    dstLocal.SetValue(i,0);
}

开启自动同步debug日志功能后,输出日志如下:

Text
The BiSheng Auto Sync log of sync_log_test :  
Position: absolute-path/sync_log_test.h:4 : line before insert sync : SetFlag<HardEvent::V_S>(EVENT_ID0);
Position: absolute-path/sync_log_test.h:4 : line before insert sync : WaitFlag<HardEvent::V_S>(EVENT_ID0);
Position: absolute-path/sync_log_test.h:5 : line before insert sync : PipeBarrier<PIPE_V>();
Position: absolute-path/sync_log_test.h:5 : line before insert sync : SetFlag<HardEvent::S_V>(EVENT_ID0);
Position: absolute-path/sync_log_test.h:5 : line before insert sync : WaitFlag<HardEvent::S_V>(EVENT_ID0);
Position: absolute-path/sync_log_test.h:6 : line before insert sync : SetFlag<HardEvent::V_S>(EVENT_ID0);
Position: absolute-path/sync_log_test.h:6 : line before insert sync : WaitFlag<HardEvent::V_S>(EVENT_ID0);

其中,line before表示紧接着当前行前面插入的同步指令。

免责声明:本站内容由 asc-devkit 仓 master 分支自动编译生成,属于持续开发版本,可能存在缺陷,仅供预览与参考。如需稳定及商用资料,请查阅官方 昇腾社区