---
title: 支持自动同步
description: "使用Ascend C编写算子时，通过设置毕昇编译器自动同步编译选项 “--cce-auto-sync”（kernel直调算子工程和自定义算子开发工程已默认开启，无需开发者设置）， 能够自动插入如下AI Core内部执行单元间的同步指令："
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/compiler/BishengCompiler/atlas_bisheng_10_0008.html
sourcePath: /source/zh/canncommercial/900/compiler/BishengCompiler/atlas_bisheng_10_0008.html
indexId: 23ce597c467f1c1341fd848b7567c6227a35531f05f55ee304e275c765d8c68581
---
# 支持自动同步

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

- MTE2与Scalar之间
- MTE3与Scalar之间
- Vector与Scalar之间
- Vector与Vector之间

Ascend C编程框架和编译器为开发者提供以下自动同步功能，详细内容请参考同步控制简介(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/ascendcopapi/atlasascendc_api_07_0179.html)《Ascend C算子开发(https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/900/programug/Ascendcopdevg/atlas_ascendc_map_10_0002.html)》。

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

#### 自动同步使用约束

使用自动同步功能需要满足以下约束：Kernel函数中调用的所有函数需要为inline函数；规范使用Ascend C编程模型。

- Kernel函数中调用的所有函数需要为inline函数
  下面的样例中，非inline函数不支持自动同步功能。

```
// 算子类的实现中Process函数
__aicore__ void Process()
{
CopyIn();
Compute();
CopyOut();
}
__aicore__ void CopyIn()
{
LocalTensor<int32_t> srcLocal = inQueueSrc.AllocTensor<int32_t>();
DataCopy(srcLocal, srcGlobal, 512);
inQueueSrc.EnQue(srcLocal);
}
__aicore__ void Compute()
{
LocalTensor<int32_t> srcLocal = inQueueSrc.DeQue<int32_t>();
LocalTensor<int32_t> dstLocal = outQueueDst.AllocTensor<int32_t>();
uint64_t mask = 64;
Copy(dstLocal, srcLocal, mask, 4, { 1, 1, 8, 8 });
outQueueDst.EnQue<int32_t>(dstLocal);
inQueueSrc.FreeTensor(srcLocal);
}
__aicore__ void CopyOut()
{
LocalTensor<int32_t> dstLocal = outQueueDst.DeQue<int32_t>();
DataCopy(dstGlobal, dstLocal, 512);
outQueueDst.FreeTensor(dstLocal);
}
```


  上述样例需要改写为如下形式才可以支持自动同步。

```
// 算子类的实现中Process函数
__aicore__ inline void Process()
{
CopyIn();
Compute();
CopyOut();
}
__aicore__ inline void CopyIn()
{
LocalTensor<int32_t> srcLocal = inQueueSrc.AllocTensor<int32_t>();
DataCopy(srcLocal, srcGlobal, 512);
inQueueSrc.EnQue(srcLocal);
}
__aicore__ inline void Compute()
{
LocalTensor<int32_t> srcLocal = inQueueSrc.DeQue<int32_t>();
LocalTensor<int32_t> dstLocal = outQueueDst.AllocTensor<int32_t>();
uint64_t mask = 64;
Copy(dstLocal, srcLocal, mask, 4, { 1, 1, 8, 8 });
outQueueDst.EnQue<int32_t>(dstLocal);
inQueueSrc.FreeTensor(srcLocal);
}
__aicore__ inline void CopyOut()
{
LocalTensor<int32_t> dstLocal = outQueueDst.DeQue<int32_t>();
DataCopy(dstGlobal, dstLocal, 512);
outQueueDst.FreeTensor(dstLocal);
}
```


- 规范使用  Ascend C编程模型(https://www.hiascend.comdocument/detail/zh/canncommercial/900/programug/Ascendcopdevg/atlas_ascendc_map_10_0004.html)

  下面的样例中，没有使用Ascend C编程模型（EnQue()、DeQue()、AllocTensor()、FreeTensor()接口），不支持自动同步。

```
// 不使用Ascend C编程模型
__aicore__ inline void CopyIn()
{
DataCopy(srcLocal, srcGlobal, 512);
}
__aicore__ inline void Compute()
{
for(int i = 0;i<dstDataSize; i++) {
dstLocal.SetValue(i,srcLocal.GetValue(i));
}
}
__aicore__ inline void CopyOut()
{
DataCopy(dstGlobal, dstLocal, 512);
}
private:
TPipe pipe;
LocalTensor<int32_t> srcLocal, dstLocal;
GlobalTensor<int32_t> srcGlobal, dstGlobal;
int dstDataSize = 512;
```


  需要改写为如下形式才可以支持自动同步。

```
// 合理按照编程范式写法使用EnQue()、DeQue()、AllocTensor()以及FreeTensor()等内存管理与同步控制API接口
__aicore__ inline void CopyIn()
{
LocalTensor<int32_t> srcLocal = inQueueSrc.AllocTensor<int32_t>();
DataCopy(srcLocal, srcGlobal, 512);
inQueueSrc.EnQue(srcLocal);
}
__aicore__ inline void Compute()
{
LocalTensor<int32_t> srcLocal = inQueueSrc.DeQue<int32_t>();
LocalTensor<int32_t> dstLocal = outQueueDst.AllocTensor<int32_t>();
for(int i = 0;i<dstDataSize; i++) {
dstLocal.SetValue(i,srcLocal.GetValue(i));
}
outQueueDst.EnQue<int32_t>(dstLocal);
inQueueSrc.FreeTensor(srcLocal);
}
__aicore__ inline void CopyOut()
{
LocalTensor<int32_t> dstLocal = outQueueDst.DeQue<int32_t>();
DataCopy(dstGlobal, dstLocal, 512);
outQueueDst.FreeTensor(dstLocal);
}
private:
TPipe pipe;
TQue<QuePosition::VECIN, 1> inQueueSrc;
TQue<QuePosition::VECOUT, 1> outQueueDst;
GlobalTensor<int32_t> srcGlobal, dstGlobal;
int dstDataSize = 512;
```


#### 自动同步debug日志功能

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

- 直接使用毕昇编译器的场景，可以直接在编译命令中添加该编译选项
- 使用Ascend C kernel直调算子工程，可以通过  ascendc_compile_options(https://www.hiascend.comdocument/detail/zh/canncommercial/900/programug/Ascendcopdevg/atlas_ascendc_10_0056.html#ZH-CN_TOPIC_0000002531522228__table481718169817)
添加该编译选项
- 使用Ascend C自定义算子开发工程，可以通过  add_ops_compile_options(https://www.hiascend.comdocument/detail/zh/canncommercial/900/programug/Ascendcopdevg/atlas_ascendc_10_0068.html#ZH-CN_TOPIC_0000002531522170__section7321165972311)
添加该编译选项

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