昇腾社区首页
中文
注册

支持自动同步

使用Ascend C编写算子时,通过设置毕昇编译器自动同步编译选项 “--cce-auto-sync”(kernel直调算子工程和自定义算子开发工程已默认开启,无需开发者设置), 能够自动插入如下AI Core内部执行单元间的同步指令:

  • MTE2与Scalar之间
  • MTE3与Scalar之间
  • Vector与Scalar之间
  • Vector与Vector之间

Ascend C编程框架和编译器为开发者提供以下自动同步功能,详细内容请参考同步控制简介

  • 单流水同步:PIPE_V由编译器自动完成同步插入, PIPE_MTE2/PIPE_MTE3在搬运地址有重叠的情况下需要开发者插入同步。
  • 多流水同步:PIPE_V、PIPE_MTE2、PIPE_MTE3、PIPE_S之间的多流水同步,都是双向的,如下图所示,黄色线条表示的同步由编译器自动完成同步插入,剩余的同步由Ascend C框架完成。

自动同步编译选项能够正确插入同步强依赖于LocalTensor间依赖关系,特别做如下说明。

临时LocalTensor直接逻辑依赖(赋值、引用、指针操作)支持自动同步。非直接逻辑依赖(利用容器传递,手动tensor成员赋值,函数传值等)不支持自动同步,需要开发者手动改为支持场景。

下面以vector间PIPE_V的插入举例,其中Vector_OP指任意的vector指令:

  • 直接逻辑依赖场景
    • LocalTensor初始化通过赋值方式
      // 定义dstLocal1
      LocalTensor<T> dstLocal1;
      Vector_OP(dstLocal1, params); 
      // 赋值定义dstLocal2
      LocalTensor<T> dstLocal2 = dstLocal1; 
      // 自动插入PIPE_V
      Vector_OP(dstLocal2, params);
    • LocalTensor初始化通过切片赋值方式
      // 定义dstLocal1
      LocalTensor<T> dstLocal1;
      Vector_OP(dstLocal1, params); 
      // 切片赋值定义dstLocal2
      LocalTensor<T> dstLocal2 = dstLocal1[512]; 
      // 自动插入PIPE_V
      Vector_OP(dstLocal2, params); 
    • LocalTensor初始化通过引用方式
      // 定义dstLocal1
      LocalTensor<T> dstLocal1;
      Vector_OP(dstLocal1, params); 
      // 引用定义dstLocal2
      LocalTensor<T> &dstLocal2 = dstLocal1; 
      // 自动插入PIPE_V
      Vector_OP(dstLocal2, params); 
    • LocalTensor初始化通过指针方式
      // 定义dstLocal1
      LocalTensor<T> dstLocal1;
      Vector_OP(dstLocal1, params); 
      // 指针定义dstLocal2
      LocalTensor<T> *dstLocal2 = &dstLocal1; 
      // 自动插入PIPE_V
      Vector_OP(*dstLocal2, params); 
  • 非直接逻辑依赖场景
    • LocalTensor初始化通过容器Que方式
      // 定义dstLocal1
      LocalTensor<T> dstLocal1;
      Vector_OP(dstLocal1, params);
      inQueueSrc.EnQue(dstLocal1); 
      // 容器Que定义dstLocal2
      LocalTensor<T> dstLocal2 = inQueueSrc.DeQue<T>(); 
      // 无法获取依赖,需手动改为支持场景
      Vector_OP(dstLocal2, params);
    • LocalTensor初始化通过其内存成员的接口方式
      // 定义dstLocal1
      LocalTensor<T> dstLocal1;
      Vector_OP(dstLocal1, params);
      // LocalTensor操作内存成员接口定义dstLocal2内存地址
      dstLocal2.SetAddrWithOffset(dstLocal1, offset);
      // 无法获取依赖,需手动改为支持场景
      Vector_OP(dstLocal2, params);
    • 函数接口场景:
      LocalTensor<T> dstLocal1;
      Vector_OP(dstLocal1, params);
      
      __aicore__ void Foo (dstLocal1) { 
      // 无法获取依赖,需手动改为支持场景
         Vector_OP(dstLocal1, params);
      }

    毕昇编译器提供“--cce-auto-sync-log=<file>”编译选项可以输出同步插入信息到<file>文件中,帮助开发者显式地识别编译器在算子文件中插入的同步指令信息。需debug模式(添加-g编译选项)编译算子,用于获取算子代码文件行号。

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

    如下的代码文件sync_log_test.h:

    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);
    }

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

    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日志功能后,输出日志如下:

    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表示紧接着当前行前面插入的同步指令。