SuperAPI AI Directory

external-cannbot-ops-ascendc-precision-debug

Coding & development

View repository

Updated 10-15 17:19

About this skill

Ascend C operator precision debugging

Core concepts

Precision debugging = understand + analyze + locate + fix

  1. Understand data type limits: FP16 has about 3-4 significant digits, FP32 about 6-7.
  2. Identify numerical stability issues: large numbers swallowing small numbers, catastrophic cancellation.
  3. Master a scientific debugging method: from minimal reproduction to root cause analysis.

When to use

Applicable: precision verification failure (rtol/atol not met), output all 0 or random values, FP16 worse than FP32, large errors in specific numerical ranges, pipeline synchronization issues, DataCopy alignment issues.


Debugging prerequisites ⭐⭐⭐

Before debuggingmustcomplete the following three steps

1. Fix a minimal reproducible case

Item Description Example
Shape tensor shape {8, 16}
Dtype data type float16
fixed values specific values [1.0, 2.0, -0.5, ...]

Selection principles: prefer simple → prefer 32-byte alignment → prefer FP32 → cover boundary values

💡 Recommended practice: during debugging, it is recommended to validate on at least two dtypes (such as FP16 and FP32) withthe same shape + the same data. If one dtype passes and the other fails, you can quickly narrow the scope according to the corresponding diagnostic mode below.

2. Search asc-devkit ⭐

Do not modify code based on intuition

Search order:

  1. Search asc-devkit/examples/ to find similar operators.
  2. Check the asc-devkit/docs/api/context/ API documentation.
  3. Compare the official implementation with the current implementation.

3. Clean up caches and temporary files

rm -rf build input output
mkdir -p build/input build/output

Quick decision tree

[前置检查] 已固定用例?已检索API?已清理缓存?
    │
    └─ 否 → 先完成前置步骤
    └─ 是 → 继续
        │
        ├─ [第0步] ⭐ 代码修改后输出完全不变?
        │   ├─ 是 → 清理 build/ 和 kernel_cache 后重试
        │   └─ 否 → 继续
        │
        ├─ [第0.5步] ⭐ 多 dtype 交叉验证
        │   ├─ FP32通过但FP16/BF16失败 → 精度不足,见下方诊断模式
        │   ├─ BF16通过但FP16/FP32失败 → API fallback 路径差异 或 精度阈值差异,见下方诊断模式
        │   └─ 全部通过/全部失败 → 继续
        │
        ├─ [第一步] 排查数据搬运 ⭐⭐⭐
        │   ├─ 输出是否全为 0 或随机错误?
        │   │   ├─ 是 → 检查流水线同步(EnQue / DeQue)⭐⭐⭐
        │   │   │       └─ DataCopy 后直接计算?→ 添加 EnQue/DeQue
        │   │   │       └─ 临时验证:加 PipeBarrier,若正确则确认同步问题
        │   │   ├─ 检查 DataCopy 是否 32 字节对齐
        │   │   │       └─ 非对齐 → 改用 DataCopyPad
        │   │   └─ 检查是否使用 GlobalTensor.SetValue
        │   │           └─ 是 → 改用 LocalTensor.SetValue + DataCopyPad 搬出到 GM
        │   └─ 验证:用 "CopyIn → CopyOut" 测试搬运
        │
        ├─ [第二步] 对比分析
        │   └─ 对比官方示例与当前实现 → 发现差异
        │
        └─ [第三步] 诊断问题类型
            ├─ 所有结果都差 → 公式/常量/API选择
            ├─ 个别值错误 → 边界条件/除零/溢出
            └─ 误差整体偏大 → FP16精度不足 → 尝试FP32中间计算

Symptom-cause quick reference table

Symptom Possible cause Diagnostic direction
Output all 0 or random errors Missing pipeline synchronization / DataCopy unaligned / GlobalTensor.SetValue Check EnQue / DeQue, data alignment, switch to LocalTensor.SetValue + DataCopyPad ⭐⭐⭐
sum=0, max_err=输入级别 Output not written out Check output queue type (VECIN vs VECOUT)
sum=0, max_err≈0 Output all 0/uninitialized Check UB overflow, buffer allocation
特定参数范围失败 Threshold/boundary error Verify threshold calculation, check branch conditions
非对齐数据失败 DataCopy alignment issue Switch to DataCopyPad
FP16 差但 FP32 好 Insufficient precision Use FP32 for intermediate calculations
Cast 后数据错误 RoundMode error half → float use CAST_NONE, float → half use CAST_ROUND
BF16 passes but FP16/FP32 fails (1) Some APIs do not support BF16, and BF16 takes a simpler fallback path, which happens to be correct; (2) BF16 and FP16/FP32 have different precision characteristics (BF16 mantissa 7bit vs FP16 10bit), resulting in differences in precision thresholds or overflow behavior First investigate the differences in API fallback branches, then check whether the precision thresholds (rtol/atol) are adapted to each dtype
FP32 passes but FP16/BF16 fails Insufficient precision in half-precision intermediate computations Increase precision: Cast → compute in FP32 → Cast back to half precision
Output is completely unchanged after modifying the code Binary not updated / compiler cache Clean build/ and $HOME/atc_data/kernel_cache/ then retry

Diagnostic pattern: "FP32 passes but FP16/BF16 fails"

This is the most common precision diagnostic signal: FP16/BF16 usually share the same Cast-to-FP32 computation path in Ascend C (if constexpr (std::is_same_v<T, bfloat16_t> || std::is_same_v<T, half>)), FP32 passing indicates that the core algorithm is correct, and the problem lies in the half-precision conversion step.

确认: FP32通过,FP16/BF16失败
    │
    ├─ 检查中间计算精度
    │   ├─ FP16/BF16 Cast→FP32 计算路径是否正确?
    │   ├─ 是否有未升精度的中间运算(如直接 Add<half>)?
    │   └─ 验证:将 FP16 路径的中间计算全部用 FP32,观察结果
    │
    ├─ 检查 Cast RoundMode
    │   ├─ half→float 应使用 CAST_NONE
    │   ├─ float→half 应使用 CAST_ROUND
    │   └─ 验证:对比 Cast 前后的数值
    │
    ├─ 检查 Pipeline 同步
    │   ├─ FP16/BF16 路径有额外的 Cast 操作,Cast 后是否 EnQue/DeQue?
    │   ├─ FP32 路径无 Cast,天然无此同步问题
    │   └─ 验证:在 Cast 后加 PipeBarrier,若正确则确认同步问题
    │
    └─ 检查 Buffer 大小
        ├─ FP16/BF16 路径需额外 Cast buffer(2× innerDim × sizeof(float))
        ├─ FP32 路径不需要 Cast buffer
        └─ 验证:检查 Tiling 中 castBuf 大小计算

Diagnostic pattern: "BF16 passes, but FP16/FP32 fails"

This is a valuable diagnostic signal and may be caused by two types of reasons:

Reason 1: API not supported leading to differences in fallback paths. Some Ascend C arithmetic/reduction APIs do not support BF16, and developers implement a simpler fallback path for BF16. The BF16 fallback passing indicates that the logic is correct, and the problem lies in the complex APIs called in the FP16/FP32 path.

Reason 2: Differences in precision thresholds / numerical ranges. BF16 (mantissa 7bit, exponent range same as FP32) and FP16 (mantissa 10bit, smaller exponent range) have different precision characteristics: BF16 is less prone to overflow but has lower mantissa precision, while FP16 is prone to overflow but has higher mantissa precision. If the verification thresholds (rtol / atol) are not differentiated and adapted, or FP16 overflows while BF16 does not, BF16 will pass but FP16 will fail.

确认: BF16通过,FP16/FP32失败
    │
    ├─ [原因1] API fallback 路径差异
    │   ├─ 搜索代码中 if constexpr (std::is_same_v<T, bfloat16_t>) 分支
    │   ├─ BF16 走的 fallback 路径 vs FP16/FP32 走的主路径,差异在哪里?
    │   ├─ 列出 FP16 / FP32 路径中使用但 BF16 路径未使用的 API
    │   ├─ 逐个验证差异 API 的参数(mask、repeatTime、stride)
    │   └─ 临时将 FP16 路径改为与 BF16 相同的 fallback 实现,观察是否通过
    │
    ├─ [原因2] 精度阈值 / 数值范围差异
    │   ├─ FP16 是否溢出?(FP16 max ≈ 65504,BF16 指数范围同 FP32)
    │   ├─ 验证阈值(rtol/atol)是否按 dtype 区分?
    │   │   ├─ BF16: rtol=1e-2 级别(mantissa 仅 7bit)
    │   │   └─ FP16: rtol=1e-3 级别(mantissa 10bit)
    │   └─ 检查中间计算是否因 FP16 的更高精度要求暴露了算法缺陷
    │
    └─ 交叉验证
        ├─ 检查 asc-devkit 文档确认相关 API 是否支持 BF16
        ├─ 如果 API 不支持 BF16 → 优先按原因1排查
        └─ 如果 API 支持 BF16(BF16/FP16 走相同路径)→ 优先按原因2排查

Common pitfalls quick reference

Pitfall Symptom Solution
Missing pipeline synchronization Output all 0 or random errors EnQue/DeQue synchronization is required after DataCopy ⭐⭐⭐
DataCopy unaligned Small-scale data all 0/abnormal Use DataCopyPad ⭐⭐⭐
GlobalTensor.SetValue Output is all 0 Switch to LocalTensor.SetValue + DataCopyPad to move out to GM ⭐⭐⭐
Cast RoundMode Data is garbled after Cast Use CAST_NONE for half→float, CAST_ROUND for float→half ⭐
Insufficient FP16 precision Even simple calculations have errors Use FP32 for key intermediate values
exp/log overflow Inf or NaN appears Subtract the maximum value before computing
Subtractive cancellation Large error in a-b when a≈b Use a numerically stable equivalent formula
Reduce error Reduce results have larger error than element-wise Use an FP32 accumulator
Division-by-zero risk NaN or abnormally large values Add epsilon protection

Pipeline synchronization debugging

Core issue: DataCopy / DataCopyPad are asynchronous DMA operations, and performing Vector computations directly on the copied data may read incomplete data!

// ❌ 错误:AllocTensor 后直接用
LocalTensor<T> x = inQueue.AllocTensor<T>();
DataCopy(x, gm, size);
Compute(x);  // 错!可能读到未完成搬运的数据

// ✅ 正确:DeQue 后再计算
LocalTensor<T> x = inQueue.AllocTensor<T>();
DataCopy(x, gm, size);
inQueue.EnQue(x);
LocalTensor<T> xIn = inQueue.DeQue<T>();  // 等待搬运完成
Compute(xIn);

Temporary debugging method:

DataCopy(x, gm, size);
PipeBarrier<PIPE_ALL>();  // 临时加,如果结果正确说明是同步问题
Compute(x);

If PipeBarrier can solve the problem, it indicates a synchronization issue → Fix: switch to the EnQue/DeQue mechanism

Misconception Correct understanding
Data is available after AllocTensor AllocTensor only allocates memory and does not wait for the copy
DataCopy is synchronous DataCopy is asynchronous DMA and returns immediately
It works without EnQue/DeQue Synchronization with EnQue/DeQue or PipeBarrier is required
PipeBarrier has good performance PipeBarrier is a full pipeline stall and has poor performance

For details, see references/common-traps.md


Debugging strategy levels

调试方法
    │
    ├─ 快速方法(优先尝试,≤7次)
    │   ├─ 误差分布分析 → 识别误差模式
    │   ├─ Printf 特定位置 → 缩小范围
    │   └─ 常见陷阱排查 → 对症下药
    │
    └─ 二分调试(保底手段)
        └─ 快速方法尝试≥7次或方法穷尽时立即切换

Important principle: do not blindly try more than 7 times


Problem localization methods

1. Comparison method (compare with working code)

Find code that works normally and compare differences line by line

2. Boundary bisection method

Record the passing/failing threshold and analyze the branch selection

3. Numerical verification method

Do not trust estimation formulas; use code to compute actual values

4. Buffer debugging key points

Problem Symptom Solution
VECIN used for output Output equals input Output must use the VECOUT queue
Double Buffer miscalculation Incorrect threshold Multiply by 2 when calculating the threshold

For the detailed localization process, see references/diagnosis-workflow.md


Precision standard source priority

  1. Priority 1: precision requirements explicitly specified in the operator development Plan
  2. Priority 2: Huawei Ascend official precision standard documentation
  3. Priority 3: default value of this Skill (fallback only)
Data type rtol atol
FP16 1e-3 1e-4
FP32 1e-5 1e-6
INT - 0

Agent Usage Guide

Debugging count rules

计数器 = 0
每次尝试快速方法(误差分析/Printf/陷阱排查)→ 计数器+1
当 计数器 >= 7 或 快速方法穷尽 → 立即切换二分调试

💡 Experience recommendation: if multiple attempts have made no progress (the number of failing cases has not decreased), it is recommended to:

  1. Check whether the compilation cache has been cleared (rm -rf build/ $HOME/atc_data/kernel_cache/)
  2. Verify whether the sha256 of the binary actually changed after modification
  3. Switch to a completely different debugging strategy (e.g., degrade from bisection to a minimal working path)

Debugging summary requirements

After each successful debugging stepmustform a summary:

  • Places where the documentation description is unclear
  • Places that need improvement and recommended solutions
  • Points that cause confusion for the Agent
  • Debugging process record

Summary template:references/debug-summary-template.md

Checklist

Debugging phase:

  • A minimal reproducible case has been fixed
  • asc-devkit has been searched to confirm API usage ⭐
  • Cache and temporary files have been cleared
  • Pipeline synchronization issues have been investigated(DataCopy 后是否 EnQue/DeQue)⭐⭐⭐
  • The issue of output being all 0 has been investigated(DataCopy 对齐 / GlobalTensor.SetValue → LocalTensor.SetValue + DataCopyPad)⭐⭐⭐
  • Official examples have been compared with the current implementation
  • Number of attempts < 7
  • Switch to bisection debugging immediately upon reaching the threshold

Reference Materials

Workflow

Problem Diagnosis

Debugging Tools

Hands-on Case Studies