检测内核调用符方式的Ascend C算子
操作步骤
内存检测示例说明
- 在步骤1之前,需要在Add 算子中构造一个非法读写的场景,将DataCopy内存拷贝长度从TILE_LENGTH 改为2 * TILE_LENGTH ,此时最后一次拷贝会发生内存读写越界。
__aicore__ inline void CopyOut(int32_t progress) { // deque output tensor from VECOUT queue LocalTensor<half> zLocal = outQueueZ.DeQue<half>(); // copy progress_th tile from local tensor to global tensor // 构建非法读写场景 DataCopy(zGm[progress * TILE_LENGTH], zLocal, 2 * TILE_LENGTH); // free output tensor for reuse outQueueZ.FreeTensor(zLocal); }
- 根据检测工具输出的报告,可以发现在add_custom.cpp的63行对GM存在 256 字节的非法读操作,与我们构造的异常场景对应。
$ mssanitizer --tool=memcheck --leak-check=yes ./add_custom_npu [mssanitizer] logging to file: ./mssanitizer_20240124182331_37743.log ====== ERROR: illegal read of size 256 ====== at 0x124080022f00 on GM ====== in block 7 ====== code in add_custom.cpp:63
竞争检测示例说明
- 在步骤1之前,需要在Add 算子中构造一个流水间竞争的场景,将CopyOut函数中的数据搬出逻辑直接写在Compute函数末尾,并注释zLocal的入队操作,此时会在zLocal内存上存在竞争。
__aicore__ inline void Compute(int32_t progress) { LocalTensor<half> xLocal = inQueueX.DeQue<half>(); LocalTensor<half> yLocal = inQueueY.DeQue<half>(); LocalTensor<half> zLocal = outQueueZ.AllocTensor<half>(); Add(zLocal, xLocal, yLocal, TILE_LENGTH); // outQueueZ.EnQue<half>(zLocal); inQueueX.FreeTensor(xLocal); inQueueY.FreeTensor(yLocal); // 计算完成后不通过 queue 保证同步,构造竞争异常场景 DataCopy(zGm[progress * TILE_LENGTH], zLocal, TILE_LENGTH); outQueueZ.FreeTensor(zLocal); } ... __aicore__ inline void Process() { int32_t loopCount = TILE_NUM * BUFFER_NUM; for (int32_t i = 0; i < loopCount; i++) { CopyIn(i); Compute(i); // 不使用 CopyOut 函数,直接在 Compute 函数中做搬出 // CopyOut(i); } }
- 根据检测工具输出的报告,可以发现在add_custom.cpp的58行和63行,PIPE_V和PIPE_MTE3流水在UB上存在先读后写竞争,符合我们构造的异常场景。
$ mssanitizer --tool=racecheck ./add_npu ====== ERROR: Potential RAW hazard detected at UB : ====== PIPE_V Write at RAW()+0x400 in add_custom.cpp:58 ====== PIPE_MTE3 Read at RAW()+0x400 in add_custom.cpp:63
父主题: 使用示例