已开启
增加 Autofuse V2 Broadcast 性能建模 #235
高煜博创建于 8月11日
8月11日 添加了label:requirement
8月11日 将 hamburgerbobo 设为负责人
8月11日 修改了issue 的描述
8月11日 关联了pull request:feat: 支持 Broadcast V2 性能建模(#235)
8月14日 关联了pull request:feat: add Broadcast V2 performance modeling (#235)
8月26日 修改标题为 “增加 Autofuse V2 Broadcast 性能建模”,原标题为“[Requirement|需求建议]: 增加 Autofuse V2 Broadcast 性能建模”
8月26日 修改标题为 “增加 Autofuse V2 Broadcast 性能建模”,原标题为“[Requirement|需求建议]: 增加 Autofuse V2 Broadcast 性能建模”
简介
目的
本文档描述 Autofuse V2 Broadcast 的性能建模方案。目标是使 ATT 性能公式与实际生成的
BroadcastExtend和独立Duplicate路径一致,并将BroadcastExtend内部 helper 完整下钻到实际执行的Reg::*。目标读者包括 Autofuse codegen、ATT、AscendC API 和测试开发人员。本文档只定义设计,不包含实现代码。
范围
本设计包含:
BroadcastExtend性能模型。Duplicate性能模型。broadcast_extend_impl.h、broadcast_3510_extend_impl.h和broadcast_gather_3510_extend_impl.h中全部可达分支的 Reg 调用次数。本设计不包含:
无对应项的实际函数调用统一使用
kPlaceholder。ApiCall::PostProcess生成且可能被多个输出/消费者共享的 UB scalar同步、
GetValue或 Duplicate 成本重复归属到 Broadcast;这些调用属于生产节点执行边界。BroadcastApiCall以need_tmp_buf=true生成的 B64 四参数 Duplicate 路径。V2BroadcastRegApiCall仅复用BroadcastScalar(..., false),不会进入仓内DuplicateInt64四参数实现;本任务不为未注册到 V2 ATT 的旧 codegen 路径建模。
MicroAPI::Duplicate性能模型。VF 不进入BroadcastRegApiCall或BroadcastExtend,继续使用既有 parser 类型和 VF 性能路径;本任务不修改 VF parser 或公共 VF 计数接口。总体概述
软件概述
项目介绍
Broadcast 属于 Autofuse V2 向量计算节点。当前 V2 注册仍通过
GetPerfFunc(kBroadcast)复用 V1BroadcastApi,V1 公式主要按合并后的输入输出 shape 区分 1D 至 4D 场景,无法反映 V2 codegen 实际调用的BroadcastExtend及其 E2B、Gather、对齐、非对齐、64-bit 和 more-dim 分支。源码依据如下:
autofuse/v35/ascir/generator/v2_ascir_codegen_impl.h:259-296autofuse/v35/codegen/reg_api_call/reg_broadcast_api_call.cpp:23-125autofuse/v35/ascendc/api_regbase/broadcast.h:16-22autofuse/v35/ascendc/api_regbase/broadcast_extend_impl.h:34-278autofuse/v35/ascendc/api_regbase/broadcast_3510_extend_impl.h:20-1324autofuse/v35/ascendc/api_regbase/broadcast_gather_3510_extend_impl.h:19-482autofuse/v35/att/api_perf_register/ascir_api_perf_v2.cpp:512-514产品环境介绍
本功能位于 Autofuse 编译期 ATT/codegen 链路,使用仓内 AscendC RegBase Broadcast 源码作为语义依据。
不新增 CANN Toolkit、runtime 或 Python 依赖,不修改外部接口。实际 Reg API latency/throughput 仅使用
PerfParamTableV2::GetVfInstructPerfTable()中已有数据。软件功能
BroadcastExtend的原始dst_shape/src_shape或独立Duplicate的原始count。Reg::*或MicroAPI::*。kPlaceholder,不猜耗时。设计约束
BroadcastExtendrank 必须位于[1, 9]。branch_id、repeat_time或 Reg 次数。tpipe.tiler.Size(...)或ActualSize(...)字符串,必须保存原始表达式配方。Load的实际 Reg API统一使用kLoad;所有含Store的实际 Reg API统一使用kStore。kPlaceholder;包括但不限于CreateMask、Arange、Gather、GatherB、PopStackBuffer、GetPhyAddr和同步管理函数。Div<int16/int32>保留真实kDiv和真实 dtype;在获得权威性能数据前不得猜测或替换 dtype。VFHead + max_latency + sum(throughput * count)。假设和依赖关系
constRank等于dst_shapes.size(),合法公开入口为1..9;动态 shape 指 rank 固定、shape 值运行时确定,不把公开入口不可达的
constRank=-1当成动态 rank。Tiler::sizes/actual_sizes和 Tensor 元数据构造与生成 C++ 实参、TensorActualSize、TensorVectorizedSize及 LocalTensor view 大小同源的ge::Expression。TernaryOp能表达比较、相等和Mod(expr, divisor) == 0条件。BroadcastRegApiCall::Generate不产生 Where/Compare类型的
CreateComputeNodeOuterFor,因此不新增outer_call_count。kPlaceholder只保证调用次数可追溯,不代表绝对性能精度已闭环。W=-1,允许 unaligned 分支进入 dynamicfallback;这与入口
constRank固定不矛盾。uint16_twrapper/loop/stride 的值和合轴乘积均不超过 65535;普通 Gather/GatherWrapper 最终 index 仅在 B8/B16 的 16-bit index consumer 中受 65535
限制,GatherB 与 B32/B64-effective 使用真实 32-bit index。所有源码
uint32_tsize/乘积 consumer 均不得超过
UINT32_MAX。限制按实际 consumer 应用:顶层 Copy 不消费uint16_twrapper 值,但其uint32_tsrcSize/dstSize乘积仍不得溢出,且AlignUp(dstSize, ONE_BLK_SIZE/sizeof(T))的加法要求静态dstSize <= UINT32_MAX - (ONE_BLK_SIZE/sizeof(T) - 1)。普通、BOOL 和 B64 三参数 Duplicate 最终匹配 CANNint32_t countoverload,因此count不超过INT32_MAX;仓内uint8/int8overload 的第三参数为uint32_t,但其下层int32_tconsumer 要求实际参与size+1的uint8 dst_view_size或int8 count不超过
INT32_MAX-1。对应有效下层 count 为ceil_div(dst_view_size,2)或ceil_div(count,2),允许 65536。其余未进入
int32_tconsumer 的原始count/dst_view_size只受UINT32_MAX限制。这里的 16-bit index-consumer 边界只适用于B8/B16 ordinary Gather,不适用于 Duplicate。静态可证明某个实际 consumer 超界时返回失败;动态表达式以
正常域为调用前提,只为满足前提的实例生成公式,超界后的截断、回绕、除零或不终止行为没有有限有效性能
公式,也不构造伪造的非法分支成本。
需求分析与设计
整体介绍
采用“原始参数透传 + ATT 分层复现分支 + 逐 Reg 计数”的方案:
Vector Function 不使用上述独立节点参数,也不经过本设计的
BroadcastApiV2路径。其既有 parser 类型和VF 性能行为保持不变。
功能需求
功能需求 1:最小原始参数透传
介绍
仅透传实际性能公式必需、且 ATT 不能从已有
NodeInfo精确恢复的 API 原始参数。输入
BroadcastExtend<T, constRank>(dst, src, dst_shape, src_shape)。Duplicate(dst, scalar, count)。处理
dst_shape/src_shape。out.actual_size同源解析后的count、与传入 LocalTensor view 的GetSize()同源的dst_view_size,以及决定前置同步和取值调用的输入 source kind。Size(expr)在 codegen 中按tpipe.tiler.sizes替换,ActualSize(expr)先按tpipe.tiler.actual_sizes、再按sizes替换;ATT 参数必须保存替换后的ge::Expression,不能只保存 role。Tiler::TensorActualSize的同一公式构造ge::Expression,包括各非零 stride 轴的actual_size/size选择、stride 乘积和最终+1,不能使用只支持乘法的ParamExprProduct。dst_view_size按TensorVectorizedSize(out) - TensorVectorizedOffset(current_axis, out)的同源表达式构造,用于准确复现
uint8_toverload 中忽略size、改读dst.GetSize()的行为。输出
struct BroadcastExtendParams { std::vector<ge::Expression> dst_shapes; std::vector<ge::Expression> src_shapes; }; enum class BroadcastScalarSourceKind { kConstant, kUbScalar, kTensorVecIn, kTensorVecCalc, kTensorOther, }; struct BroadcastDuplicateParams { ge::Expression count; ge::Expression dst_view_size; BroadcastScalarSourceKind source_kind{BroadcastScalarSourceKind::kTensorOther}; }; using BroadcastCallParams = std::variant<std::monostate, BroadcastExtendParams, BroadcastDuplicateParams>; struct BroadcastNodeParams { BroadcastCallParams call_params; };不透传
const_rank、srcSize/dstSize、stride、loopNum、Extendbranch_id、repeat_time、Reg 次数或outer_call_count。source_kind不是 Extend 分支 ID,而是BroadcastScalar已确定且 ATT 无法从 API 参数恢复的前置调用语义;
dst_view_size是传入 Tensor 参数在仓内 B8 overload 中实际读取的原始属性,不是派生次数。功能需求 2:BroadcastExtend tiling 和顶层分支
介绍
ATT 按
GetBroadcastTilingInfoExtendImpl复现 API 内部参数,不按经验重建。输入
dst_shapes、src_shapes和NodeDetail中的真实 dtype。处理
srcSize/dstSize。uint32_tBrcType 并执行扩维或loopNum处理。dstStride/srcStride。srcSize == dstSize、srcSize == 1和srcStride[dim-1]选择顶层路径。dstShape[0]==1 && oriSrcShape[0]==1时,按源码跳过首轴并以
dstShape+1/srcStride+1调用对应 3D wrapper;该判定位于 4D wrapper 前,不能按普通 4D 建模。src==1 && dst!=1(B)或src==dst(E)决定。rank1-4 不合轴,但动态 shape仍需先枚举每轴 B/E 状态以构造 stride 并选择 Copy/Duplicate/Last/NLast。rank5-9 若条件为动态,必须在合轴前
按源码判定顺序递归构造 B/E 条件分支;每个分支先得到确定的规范化 rank、shape 和 stride,再进入
wrapper/leaf 选择,不能在单一可变长度容器上事后只为 leaf 条件补 ternary。
分支必须与直接使用该静态 shape 构造的模型选择相同规范化结果和 leaf。
输出
规范化 tiling 上下文和选中的 wrapper 类型。
功能需求 3:wrapper 分支覆盖
介绍
所有静态和动态 wrapper 条件必须与源码一致。
输入
规范化 shape、stride、BrcType、rank 和
loopNum。处理
Last 分支:
last == BLK && T != B8last < HALF_VLHALF_VL <= last <= VLlast > VLlast < HALF_VLlast <= VLlast > VLlast < HALF_VL && T != B8last <= VLlast > VLdim > 4或 wrapper 返回 truedynamic Last 不重新选择 E2B、Gather 或 aligned leaf,只按
last<=VL进入 4D less unaligned,或进入4D large unaligned。
3D E2B 条件保持为:
4D E2B 条件保持为:
NLast 分支:
last < HALF_VL && last % BLK == 0last < HALF_VL && last % BLK != 0HALF_VL <= last <= VLlast % VL == 0 && size0 > DEFAULT_BLK_NUMlast < HALF_VLlast <= VLlast < HALF_VL && T != B8last <= VLdim != constRankdim > 4或 wrapper 返回 truedynamic NLast 的 large aligned 分支固定使用 WithBlock,不重新选择 WithVL。B64 原末轴 Broadcast 会追加公共
轴 2:固定 rank1 进入 NLast2,rank2/3 分别进入 NLast3/NLast4,rank4 固定进入 NLast more-dim 并逐次执行
Gather4;rank9 还需乘被移除原首轴形成的
loopNum。输出
唯一 leaf 和 leaf 外层循环乘数。动态 shape 输出对应
TernaryOp,不默认选择任何分支。功能需求 4:完整下钻到 Reg/MicroAPI
介绍
helper 只有在到达实际执行的
Reg::*、MicroAPI::*或仓内无实现源码的基础 API 时才能停止。仓内有实现的 helper 只计算展开后的终端调用,不能同时计算 helper 自身和内部调用。
输入
wrapper 选择结果和 leaf 参数。
处理
调用图闭合规则:
E2bLoadReg::LoadAlignBrcLoadReg::LoadAlignGatherWrapperGenGatherIndex -> VfGenIndex/VfGenIndexB8 -> Reg::*和VfGatherBrc/VfGatherBrcB8 -> Reg::*GatherWrapperForFourDimGenGatherIndexForFourDim -> VfGenIndexForFourDim -> Reg::*和VfGatherBrcForFourDim -> Reg::*BrcNlastWrapperForMoreDimGatherWrapperForFourDim不可继续下钻的成功路径函数边界同样必须计数:
DataCopy、PopStackBuffer、LocalTensor::GetPhyAddr、GetTPipePtr、FetchEventID、SetFlag和WaitFlag。其中 load/store 语义分别映射kLoad/kStore,其余性能表无项时使用互相独立、可追溯的
kPlaceholder。失败时才执行的 assert/log 不计。以下声明不产生性能成本:
Reg::CreateMask是实际函数调用,必须计数。输出
按真实 API、方向、模式和 dtype 区分的终端调用次数集合。
功能需求 5:循环次数和统一 cost
介绍
每条 Reg API 的 count 等于其实际外围循环乘积,循环外初始化、复用 load 和 tail 调用单独计算。
输入
设 2D 为
(a,b)、3D 为(a,b,c)、4D 为(a,b,c,d)。处理
独立 Duplicate:
uint8/int8Duplicate(dst, scalar, count)call_count=1;kDuplicate性能组件component_count=ceil_div(count,V_T);包括booluint8_tDuplicateReinterpretCast<uint16_t>、GetSize、下层外部Duplicate<uint16_t>的call_count各 1;下层参数n=ceil_div(dst_view_size,2),kDuplicate<uint16>组件次数ceil_div(n,V_uint16)int8_tDuplicateReinterpretCast<uint16_t>、下层外部Duplicate<uint16_t>的call_count各 1;下层参数n=ceil_div(count,2),kDuplicate<uint16>组件次数ceil_div(n,V_uint16)call_count=1,kDuplicate<int64/uint64>组件次数ceil_div(count,V_T)GetTPipePtr=1、FetchEventID(MTE2_S)=1、SetFlag(MTE2_S)=1、WaitFlag(MTE2_S)=1、GetValue=1GetTPipePtr=1、FetchEventID(V_S)=1、SetFlag(V_S)=1、WaitFlag(V_S)=1、GetValue=1GetValue=1ReinterpretCast、GetSize无性能表项,分别使用独立kPlaceholder。外部 Duplicate 保留一次真实 API 调用;其性能组件按公开
count参数和向量宽度映射为kDuplicaterepeat,不把 repeat 误写成 API 调用次数。独立 Duplicate 的
count和dst_view_size均允许为动态表达式,并使用本节统一 cost 结构。这里的执行边界从
BroadcastRegApiCall::Generate实际生成的语句开始。UB scalar 的变量初始化由其生产节点ApiCall::PostProcess生成,同一生产节点多个 UB scalar 输出还共享一次同步,因此 Broadcast 只计算读取已准备标量后的 Duplicate,不重复计算生产节点同步/GetValue;普通 Tensor Value 的同步/GetValue 由
BroadcastScalar自身生成,仍归 Broadcast 计数。本设计不修改生产节点 ATT 模型,也不宣称整图已包含 PostProcess 总成本;该排除只用于确定 Broadcast 的唯一
执行边界,避免把共享成本按消费者数量重复计入。
基础和 E2B:
BrcDuplicate(dstSize)Load=1;UpdateMask=Store=ceil_div(dstSize,VL)BrcLastE2B(a,b)r=ceil_div(a,VL/b);UpdateMask=Load=Store=rBrcLastE2BLargerThanVL(a,b,c)r=ceil_div(b,VL/c);三者为a*rBrcLastE2BLessThanVL(a,b,c)UpdateMask=1;Load=Store=aBrcLastE2B(a,b,c,d)r=ceil_div(c,VL/d);三者为a*b*rLess 和 Large:
UpdateMask=1;Load=Store=a*b / a*b*cUpdateMask=1;Load=Store=a*b*cLoad=StoreUnAlign=a / a*b / a*b*c;Post=1UpdateMask=1, Load=1, Store=a, Post=1UpdateMask=1;LoadPre=Load=Store=a*b / a*b*c;Post=1CreateMask=1;Load=a;UpdateMask=Store=a*rCreateMask=1;Load=a*b;UpdateMask=Store=a*b*rCreateMask=1;UpdateMask=a*c*r;Load=Store=a*b*c*rCreateMask=1;UpdateMask=Load=Store=a*rCreateMask=1;UpdateMask=a*r;Load=Store=a*b*rCreateMask=1;UpdateMask=b*r;Load=Store=a*b*c*rCreateMask=1;Load=r;Store=a*rCreateMask=1;Load=Store=a*b*r / a*b*c*rLoad=a / a*b / a*b*c;Store=LoadCount*(q+1);Post=1Load=1,mainLoad=a*q;Store=a*(q+1);Post=1LoadPre=a*b / a*b*c;Load=Store=outer*(q+1);Post=1普通 large 分支中
r=ceil_div(last,VL),q=floor(last/VL)。E2B 使用其源码专属 repeat 公式。Gather index 固定次数:
GenLastGatherIndexCreateMask=1, Duplicate=1, Arange=1, Div=1, Store=1GenNlastGatherIndexMul=1, Sub=1VfGenIndexCreateMask=1, Arange=1, Duplicate=6, Div=3, Mul=4, Sub=3, MulAddDst=2, Store=1VfGenIndexB8CreateMask=1, Arange=2, Duplicate=6, Div=6, Mul=8, Sub=6, MulAddDst=4, Store=2VfGenIndexForFourDimCreateMask=1, Arange=1, Duplicate=8, Div=4, Mul=5, Sub=4, MulAddDst=3, Store=1Gather 正文:
CreateMask=1, Load=1, UpdateMask=1, Gather=1, Store=1CreateMask=1, Load=2, UpdateMask=1, Gather=2, DeInterleave=1, Store=1CreateMask=1, Duplicate=1, Load=1, Muls=r, Add=r, Adds=1, Gather=r+1, Store=r+1, Post=1Load=2, Add=2r, Adds=2, Gather=2(r+1), DeInterleave=r+1,其余同非 B8CreateMask=1, Load=1, Gather=1, Store=r+1, Post=1Load=2, Gather=2, DeInterleave=1,其余同非 B8CreateMask=1, Load=1, GatherB=1, UpdateMask=1, Store=1CreateMask=1, Load=1, GatherB=1, UpdateMask=2, Store=r+1其中
r=ceil_div(size0,VL/size1)-1。GatherWrapper 正文:
外围基础调用次数:
CheckTensorPos=2,顶层GetPhyAddr=2PopStackBuffer=1;两个 baseGetPhyAddr使用不同 call_site 且各 1 次;offset call_site 1 次PopStackBuffer=1,GetPhyAddr=2PopStackBuffer=1,GetPhyAddr=1,GetTPipePtr=2,FetchEventID=2,两组SetFlag/WaitFlag这些次数与对应 wrapper 的实际调用次数相乘。8 次 UB 标量 index 写入不是函数调用,不构造 Placeholder。
动态 more-dim 外层乘数:
选中的 4D leaf 中每条实际 Reg count 分别乘
outer。BrcNlastWrapperForMoreDim对 helper 内全部 Regcount 乘
dstShape[0]。每次 BroadcastExtend 固定执行的CheckTensorPos/GetPhyAddrprelude 独立于 leaf body,始终只附加一次,不乘 wrapper、prefix、loopNum 或 dynamic outer。
先生成独立于性能表的调用计数账本:
struct BroadcastPerfComponent { std::string perf_type; std::string perf_dtype; Expr component_count; }; struct BroadcastApiParam { std::string role; Expr value; }; struct BroadcastCallCount { std::string call_site; std::string real_api; std::string data_dtype; std::string index_dtype; std::string mode; std::vector<BroadcastApiParam> api_params; Expr call_count; std::vector<BroadcastPerfComponent> perf_components; };call_site使用稳定的源码 helper + semantic slot 名识别调用位置,例如VfGenIndexB8.ArangeLow/ArangeHigh,不能使用源码行号或对象地址。每个源码 slot 独立成行,禁止跨call_site合并;同一 slot 位于循环内时用call_count表达循环次数。api_params只保存仓外高层终端中用于派生 component count 的参数。仓内已下钻 Reg、地址、栈和同步 slot 不保存逐次 offset/scalar 参数序列。
账本验收执行位置、mode、dtype 和次数,不追踪循环中每次调用的完整实参轨迹。
Canonical role 按下表命名和排序,不允许实现自行使用同义名称:
DataCopycopy_lengthDuplicatecountcall_count只表示真实终端函数调用次数;component_count表示该函数映射到性能表后的内部处理次数,两者禁止混用。
data_dtype/index_dtype保存真实模板语义;无 index 的调用将index_dtype留空。账本是执行数量验收的唯一事实来源。随后逐组件调用
AddVfInstructPerf生成成本;性能表存在函数但缺少perf_dtype时,仍以真实
perf_type + perf_dtype调用,允许既有查询返回零成本,但不得从账本删除、改 dtype或改成 Placeholder。
动态分支先对所有静态分支的终端调用身份
(call_site,real_api,data_dtype,index_dtype,mode,api_params roles)取并集。每个身份只保留一行,参数 value、call_count和每个component_count用与源码保序分支相同的嵌套TernaryOp表达;该分支不存在此调用时取 0。动态表达式特化后删除零 count 行,再与对应静态账本逐项比较。禁止只为最终总成本建 ternary 而丢失条件化账本。
条件化 union 账本只用于数量追踪和特化验收,不能直接逐行调用
AddVfInstructPerf,否则 count 为 0 的分支独有 API 仍会污染
max_latency。成本计算必须在每个静态分支内独立得到VFHead + branch_max_latency + branch_throughput,再按相同源码条件顺序用TernaryOp合并分支总成本。Expr res = VfPerfUtils::GetVFHeadCost() + max_latency + all_vf_instruct_cost; res.Simplify(); perf.pipe_res[PipeType::AIV_VEC] = res;例如 4D E2B 的
L=size0*size1*repeatTimes,其成本为最大 latency 加三项分别乘L的 throughput,而不是
L * max_latency。功能需求 6:Reg API 映射
介绍
只使用已确认的 VF 表项;无表项时不猜耗时。
输入
下钻所得真实 Reg API、模式、方向和 dtype。
处理
DataCopyreal_api=DataCopy,call_count=1账本项并保存copy_length=AlignUp(dstSize,ONE_BLK_SIZE/sizeof(T));按用户规则附kLoad、kStore两个性能组件,各component_count=ceil_div(copy_length,V_T)Load的 API,包括 E2B 和 unalignedkLoadStore的 API,包括 unaligned 和 postkStoreDuplicatekDuplicateUpdateMaskkUpdateMaskAdd/Adds/Sub/Mul/Muls/MulAddDst/Div/DeInterleavek*CreateMask/Arange/Gather/GatherBkPlaceholderPopStackBuffer/GetPhyAddr/GetTPipePtr/FetchEventIDkPlaceholderSetFlag/WaitFlagkPlaceholderLocalTensor::GetValuekPlaceholderLocalTensor::ReinterpretCast/GetSizekPlaceholderCheckTensorPoskPlaceholder,每次 BroadcastExtend 固定 2 次dtype 必须来自 impl 中每个终端调用的真实模板实例,不能统一使用节点输入 dtype:
ExtractUnsignedTypeBySize<sizeof(T)>对应uint8/uint16/uint32BrcType数据路径,kLoad/kStore均使用节点原始 dtypeBrcType=uint32CheckTensorPos<T>和顶层GetPhyAddr保持原始int64/uint64,不随 BrcType 改写data_dtype使用VfGenIndex*/Gen*Index的真实 signedint16/int32,index_dtype为空uint16,B32/B64-effective 使用uint32uint32indexdata_dtype保存真实 source 数据 dtype,index_dtype保存uint16/uint32consumer;perf_dtype使用实际指令主寄存器 dtype。B8Gather明确为data_dtype=uint8,index_dtype=uint16,perf_dtype=uint16;B8 中间 index 运算以uint16记录,DeInterleave/Store 以uint8记录uint8/int8Duplicatebool保持booluint16Duplicate;外层 Reinterpret/GetSize 注释保留原 B8 路径PopStackBuffer<T>和LocalTensor<T>owner dtype 为uint8;GatherB consumer index 仍为uint32PopStackBuffer<BrcIndexType>和 index Tensor owner dtype 为BrcIndexType=uint16;数据 Tensor 地址按对应 owner dtypeDiv<int16/int32>使用kDiv和真实 dtype。任何性能表已有函数但缺少该 dtype 的场景,包括 B64kDuplicate,仍调用真实k*和 perf dtype;不改成kPlaceholder、不替换 dtype、不补猜测性能表数据。这种缺项可能使最终成本项为 0,但真实 API、dtype 和执行次数必须保留在
BroadcastCallCount中并由 UT 验证。输出
每个
AddVfInstructPerf均可追溯到唯一源码 call_site。账本和成本层都禁止跨 call_site 合并;即使 perf类型、方向、模式、dtype 和 count 相同,也逐 slot 调用。Placeholder 同样禁止跨真实 API、方向/模式、
dtype 或 call_site 汇总。
非功能需求
可维护性
broadcast_regbase_perf.cpp/.h,不继续扩大现有ascendc_regbase_perf.cpp。可测试性
TernaryOp,不只验证静态 shape。可移植性
不硬编码芯片型号。实现继续由现有 V2/RegBase 注册和平台能力选择进入。性能数据来自当前 V2 表,未注册
API 不引入平台推测。
可靠性
特性交叉影响
libascendsk.so或 ABI/API.cpp由 glob 收集,无安装布局变化性能
编译时长
每个 Broadcast 增加最多 9 维 shape 解析和有限分支表达式构造。静态 shape 复杂度为
O(rank + Reg API 类型数);rank5-9 动态轴类别最坏产生2^rank个 B/E 状态,rank 上限为 9,静态条件即时折叠。不新增全图遍历;测试需关注模型生成时长和表达式规模,但首期不引入缓存。
执行性能
不改变 kernel 代码、runtime 调度或内存拷贝。ATT 公式变化可能改变 tiling 候选评分,这是需求预期行为。
含 Placeholder 的分支只保证结构和次数正确,不能宣称绝对性能误差已闭环。
BOOL 的
kDuplicate/kLoad/kStore/kPlaceholder当前均缺性能表 dtype,按用户约束保留bool的真实账本项,最终成本允许为 0;这是性能数据残余边界,不影响执行次数和分支验收,但不宣称 BOOL 绝对成本闭环。
内存和产物大小
每个 Broadcast 最多保存两组 9 维表达式,或
count/dst_view_size/source_kind。调用计数账本仅存在于一次性能公式计算中。新增独立 perf 源文件,不改变动态库、run 包、wheel 和安装路径布局。
接口设计
新增/修改接口描述
ascir_param::BroadcastExtendParams。ascir_param::BroadcastDuplicateParams。ascir_param::BroadcastNodeParams。NodeInfo和NodeDetail新增broadcast_node_params内部字段。ascendcperf_v2::BroadcastPerf。BroadcastApi切换到BroadcastApiV2。所有接口均为仓内编译期内部接口,不导出 C/C++ ABI,不改变 Python API。
接口检查项
软件设计
关键数据结构
BroadcastNodeParams使用嵌套 variant 表示 Extend、Duplicate 或未填充状态。其生命周期与 ASCIR 节点扩展属性一致,由 codegen 前预注册、Generate 填充、ATT parser 复制,不持有外部资源。
内部 tiling 上下文保存解析后的 rank、shape、stride、size、loopNum 和 BrcType,只存在于一次性能公式计算中。
关键技术/算法
GetBroadcastTilingInfoExtendImpl,包括 rank 大于 4 合并和 64-bit 扩维。BroadcastComputeExtend的 copy、duplicate、last/nlast 和 dynamic fallback。constRank=C与 wrapper 模板参数W的区别,覆盖固定 rank 5-9 的动态 fallback。流程设计
正常流程:预注册参数、codegen 填充、parser 提取、V2 perf 解析、分支选择、Reg count、cost 汇总。
兼容流程:仅历史或直接构造的
NodeInfo缺少参数时使用 V1 公式并记录 debug 日志。新 codegen 已进入但载荷无效时返回失败,禁止静默回退。
异常流程:shape/rank/表达式无效立即返回错误,不产生部分性能公式。
对子模块的修改
autofuse/common/ascir_node_param/ascir_node_param.hautofuse/common/ascir_node_param/ascir_param_builder.cppautofuse/v35/codegen/reg_api_call/reg_broadcast_api_call.cppautofuse/att/gen_model_info/parser/specific_params_builder.cppautofuse/att/gen_model_info/parser/tuning_space.hNodeInfo新增字段autofuse/att/gen_model_info/api_perf_register/api_perf.hNodeDetail新增字段autofuse/v35/att/api_perf_register/ascir_api_perf_v2.cppautofuse/v35/att/api_perf_register/broadcast_regbase_perf.hautofuse/v35/att/api_perf_register/broadcast_regbase_perf.cppautofuse/v35/att/CMakeLists.txt已使用递归 glob,无需修改。错误处理
系统错误
不新增内存、文件、runtime 或动态库资源。表达式或对象创建失败沿现有错误码返回。
接口错误
af::FAILED。不阻塞执行次数模型验收。
安全检查
兼容性检查
测试设计
测试边界
AscirNodeParams和BroadcastRegApiCall::Generate。BroadcastApiV2和BroadcastPerf。测试用例设计
dst_view_size/count分流、Reinterpret/GetSize 和下层 uint16 Duplicate 次数dst_view_size=TensorVectorizedSize-offset,下层 Duplicate 次数不使用完整 tensor sizeDuplicate<bool>调用 1 次、dtype 保持 bool、缺项账本不消失C=1..9 × 合法原始 B/E pattern × B64 扩维结果,覆盖 T-COPY、N2-、N3-、N4-、固定 NMore->CG-GW4、DN- 全 terminal family,并逐项验证完整账本CreateMask=1及 dynamic outer 乘数断言srcSize/dstSize、Gather 乘积和未进入 int32 consumer 的 Duplicate 参数覆盖UINT32_MAX;普通/BOOL/B64 Duplicate count 覆盖INT32_MAX;B8 size+1 consumer 覆盖INT32_MAX-1;各自下一值失败,动态未知保留Size、ActualSize和TensorActualSizesize0*size1*repeatTimes计划修改或新增测试文件:
autofuse/tests/ut/common/test_ascir_node_params.cppautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_broadcast_reg_api_call.cppautofuse/tests/ut/att/testcase/gen_model_info/expr_gen/test_pipe_perf_expr.cppautofuse/tests/v35/ut/att/gen_model_info/api_perf_register/test_broadcast_api_perf_v2.cppautofuse/tests/v35/st/att/gen_model_info/test_ascir_perf_v2.cpp测试命令
实现阶段执行:
预期结果:编译无错误、全部测试通过、无新增 warning、无超时或死循环。
验收标准
BroadcastExtend和独立 Duplicate 两类路径均可追溯到实际 codegen。dst_shapes/src_shapes/count/dst_view_size/source_kind是唯一新增性能参数,不透传派生次数或 Extend branch id。Size/ActualSize/TensorActualSize同源解析,动态尾块实参与ATT 参数逐项一致。
call_count等于源码真实调用次数;只有仓外高层终端允许call_count=1而组件 repeat 大于 1。不得导致执行次数记录消失。
UpdateMask/Load/Store均为size0*size1*repeatTimes。Tensor -> Generate payload,ATT UT 使用相同payload 字段值逐类验证
parser -> ledger;不要求 codegen UT 链接 ATT 库。dst_view_size、int8 使用count;所有顶层 Copy 保持节点原始 dtype。perf type/dtype/component_count
均与直接构造的同 shape 静态模型逐项一致。
CreateMask=1均被计数,dynamic leaf 按实际 outer 相乘。kLoad,所有含 Store 的 Reg API 使用kStore。k*/perf dtype,不猜性能数据。VFHead + max_latency + sum(throughput * count)。设计文档检查结果