0
0

Ascend C 调试复盘:UB 容量账本、数据类型转换与最小复现

由失败现象建立可检验解释

9月22日围绕Sinh、int32转换、UB预算由4改6、InitBuffer及hang展开。可见材料包含一段对故障原因的解释,但没有完整kernel、所有缓冲声明或设备错误日志;因此“必然是32B对齐导致hang”仍是待验证假设。

UB账本怎样算

对每个同时存活的缓冲,记录位置、元素数、元素字节数、份数、对齐单位和生命周期。若该版本按32字节分配:

aligned_bytes_i = ceil(elements_i * dtype_bytes_i / 32) * 32
total_UB = sum(buffer_copies_i * aligned_bytes_i) + other_live_UB
要求 total_UB <= available_UB

这里的other_live_UB要查API临时空间和框架占用,不是随意加一个常数。不同物理位置要分别记账。

InitBuffer官方文档说明相关版本对len向上补齐32字节。单次补齐最多31字节;若几百个字节的误差无法解释实际差额,就不能只归因对齐。

ubDataNumber如果是按inputBytes计的预算系数,“6”不是固定6字节。比如inputBytes=4,则相当于每元素预算24字节。4改6使教学tile公式的块大小约变为2/3,但对齐、整除和尾块会改变精确结果。更保守后不挂是线索,不是根因证明。

Sinh的int32分支不是整数Sinh指令

可见代码是int32→float→Sinh→int32。float32连续精确表示整数的范围到2^24,超过后部分整数不可精确表示;Sinh增长很快,输出溢出和转换舍入比输入误差还值得注意。

CAST_TRUNC代表截断方向,不能替代溢出策略。应查该API对NaN/Inf和超范围转换的规定,并与参考实现一致。

“整数精度要求1e−6”需先问误差公式:绝对误差小于1e−6对两个整数通常意味着完全相等;相对误差对很大的整数允许非零差。若参考本来就是浮点再截断,测试目标也不同。

最小复现顺序

  1. 固定失败shape、dtype、输入值和设备版本,保留错误码与超时位置。
  2. 列出每个InitBuffer实参,打印tile、尾块、各buffer实际字节总和。
  3. 缩小tile但保持其它变量;再逐一替换Sinh、Cast、搬运和同步,观察失败是否移动。
  4. 检查索引越界、尾块长度、队列Alloc/EnQue/DeQue/Free配对及跨流水依赖。
  5. 对能运行的版本验证数值,再比较性能;不能只以“不挂”验收。

本次没有执行这些实验;复现步骤是建议。

一组可迁移的入门算子

Add练映射与带宽;Gather练索引与越界;Reduce/Norm练跨线程/跨核归约与数值顺序;GEMM练复用和矩阵单元;再到Softmax/RMSNorm融合和Attention。

教学例:x=[[3,4],[0,5]],按最后一维做L2向量范数得到[5,5];keepdim保留为[2,1]形状。矩阵范数和向量范数不能仅凭“都是norm”混用。ND描述一般N维布局语境,不意味着任何API支持任意stride或所有内部布局。

从Thrust transform+reduce到transform_reduce,再到CUB/手写kernel,用同一平方和比较中间数组、流量和kernel数量;不预设哪种实现最快。NVIDIA CCCL。

核查日期2026-09-23;旧CANN文档支持对齐原理,不作为当前设备全部API支持矩阵。