ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

graph-autofusion V2 节点性能公式建模指南:从 AscendC/MicroAPI 源码到 ATT 性能公式的完整链路

graph-autofusion V2 节点性能公式建模指南:从 AscendC/MicroAPI 源码到 ATT 性能公式的完整链路 graph-autofusion V2 节点性能公式建模指南从 AscendC/MicroAPI 源码到 ATT 性能公式的完整链路【免费下载链接】graph-autofusionGraph-autofusion 是一个面向昇腾Ascend芯片的轻量级、解耦式组件集合旨在通过自动融合技术加速模型执行。 目前已开源 SuperKernel 组件和 Autofuse 组件未来将持续开放更多自动融合相关模块。项目地址: https://gitcode.com/cann/graph-autofusion本文是 CANN graph-autofusion 仓库中 V2 节点性能建模方法论的完整展开对应 .claude/skills/af-perf-modeler/SKILL.md 定义的建模规范并结合仓库内 codegen、ATT 性能注册与性能表的真实实现进行源码级佐证。读者将掌握如何为 Cast / Reduce / Compare 等 V2 算子建立可追溯、可验证的性能公式如何让 codegen 阶段才确定的循环参数repeat_time / call_count正确透传到 ATT 性能模型以及如何规避 MicroAPI 映射、placeholder 合并与循环计数中最常见的建模错误。一、建模目标与核心原则在 graph-autofusion 中V2 节点的性能公式perf formula服务于 ATTAscend Tiling Tuning的自动调优与性能预估当融合后的图被翻译为一组向量指令Vector Function / MicroAPI序列时性能建模需要回答这段指令在目标芯片上大约花费多少周期从而为 tiling 决策提供量化依据。该 SKILL 的适用场景包括Cast / Reduce / Compare 等算子的性能公式建模ATT 性能公式 reviewMicroAPI 成本分析repeat_time/call_count计算codegen 与性能公式对齐。其核心原则是一条硬约束性能公式必须从节点对应 AscendC/MicroAPI 源码和 codegen 实际传参反推不能只套现有公式或凭经验估算。这意味着建模的正确顺序不是先看现有 perf 公式再复述而是先读 API 源码与 codegen 调用生成逻辑再解释或修正现有公式。凡源码入口、API 参数、codegen 传参、分支含义或 MicroAPI 语义不确定都必须先向用户说明不确定点并询问不能编造公式。二、建模前提先定位五类源码动手建模前必须完整定位并读取以下五类文件它们是公式的证据链证据类别仓库路径作用codegen implautofuse/v35/ascir/generator/v2_ascir_codegen_impl.h通过GetApiName()确定算子对应 AscendC API通过GetApiCallName()确定 codegen 调用生成器AscendC API 源码autofuse/v35/ascendc/api_regbase/目标 API 的真实实现及其 helper是 MicroAPI 枚举与分支分析的唯一依据codegen API 调用生成autofuse/v35/codegen/由GetApiCallName()指向的{ApiCallName}::Generate决定生成代码实际传给 API 的参数性能表autofuse/v35/att/api_perf_register/perf_param_v2.cppkVfInstructPerfTable等性能常量表MicroAPI 类型必须在此存在当前性能注册/实现autofuse/v35/att/api_perf_register/ascir_api_perf_v2.cpp 与 autofuse/v35/att/api_perf_register/ascendc_regbase_perf.cpp当前 perf 实现建模时对照其是否已简化从源码结构看v2_ascir_codegen_impl.h中每个算子节点都同时实现了GetApiName()映射到 AscendC API与GetApiCallName()映射到 codegen 生成器而autofuse/v35/codegen/下按算子族组织了大量{ApiCallName}_api_call.cpp例如 cast_v2_api_call.cpp、compare_v2_api_call.cpp、binary_api_call_v2.cpp 与 reg_reduce_api_call.cpp以及面向 MicroAPI 层的 micro_api_call/如 micro_cast_api_call.cpp、micro_compare_api_call.cpp。如需从 codegen 向 ATT 透传参数需要参考VectorFuncNodeParams、EnrichAscirGraphNodeParams、FillSpecificParams、specific_params及其参数传递路径。这些符号在仓库中分别落位于 autofuse/common/ascir_node_param/ascir_node_param.h、autofuse/codegen/codegen.cpp 与 autofuse/att/gen_model_info/parser/specific_params_builder.cpp 等文件中。三、通用建模流程八步从源码到公式第 1 步定位算子源码入口从v2_ascir_codegen_impl.h找到目标算子对应的GetApiName()。在autofuse/v35/ascendc/api_regbase/下查找该 API 名称的定义。读取 API 实现及其调用的 helper——不只读 perf 代码因为性能公式必须还原源码的真实指令序列。若 API 名称和源码实现无法唯一对应先询问用户确认。第 2 步确认源码输入参数与 codegen 实际传参先分析 AscendC API 源码的函数签名确认参数含义、类型、顺序和模板参数。从v2_ascir_codegen_impl.h找到目标算子的GetApiCallName()。根据ApiCallName在autofuse/v35/codegen/下找到{ApiCallName}::Generate。从Generate中分析生成代码实际传入 AscendC API 的参数包括inputs、outputs、scalar、offset、stride、mask、loop 参数、tmp buf、axis 信息等。这里有一个极易混淆的语义对应关系必须牢记codegen 的inputs/outputs是生成代码用的TensorATT 性能计算的input_shapes/output_shapes是性能建模用的TensorShapeInfo。两者语义对应但不是同一个对象——建模时不能想当然地认为 ATT 侧能拿到 codegen 侧的 Tensor 信息。第 3 步必要参数从 codegen 传递到 ATT这是整个建模流程中最关键的环节。如果性能公式需要 codegen 阶段才能确定的参数例如 loop merge 后的cal_count、outer_repeats、stride、mask mode、特殊分支标记严禁在 ATT 中凭空假设。正确做法遵循下述链路确认 ATT 性能函数能访问什么对象如果只能访问NodeInfo必须走完整链路——EnrichAscirGraphNodeParams预注册空参数结构体 →{ApiCallName}::Generate填充具体值 →FillSpecificParams提取到NodeInfo。参考VectorFuncNodeParams、Reduce 参数和目标算子现有链路将所需参数定义成独立结构体并加入AscirNodeParams::specific_params可承载的类型。只对能在{ApiCallName}::Generate中确定的参数填值如ApiLoopParams、合轴后实参、实际生成分支EnrichAscirGraphNodeParams只预注册空结构体不要在预注册阶段猜具体值。{ApiCallName}::Generate填充给 ATT 的节点参数必须使用 codegen/merge 阶段的原始符号参数例如merge_info、ApiLoopParams中的 repeat、stride、count不要保存tpipe.tiler.ActualSize(...)、tpipe.tiler.Size(...)等用于生成 C 调用字符串的展开表达式——ATT 性能公式无法稳定识别这些 tiler 表达式。在FillSpecificParams或同等参数填充入口中解析目标算子类型并将节点参数写入NodeInfo如果性能函数确实能直接访问节点对象才允许绕过NodeInfo直接读 ext attr且必须在设计中说明原因。在 ATT 性能建模入口从NodeInfo读取该参数用于公式分支和循环次数计算缺失时必须有明确回退或报错策略。参数传递属于设计变更需说明兼容性、默认值和缺失参数时的处理方式。第 4 步分析源码分支保持与源码if constexpr、if、模板参数、dtype 特化、dim 分支、broadcast 分支、scalar 分支、mask mode 分支一一对应每个源码分支都要说明触发条件、codegen 参数来源和公式差异不允许只按 dtype 或经验简化掉源码中的关键分支。例如CompareScalar..., CMPMODE::NE这类带模式语义的模板 API其不同比较模式在性能表中对应不同表项见下文映射规则分支一旦被抹平公式就会失真。第 5 步枚举 MicroAPI以源码中的每个MicroAPI::xxx或 AscendC 基础向量 API 作为最小建模粒度。将源码 MicroAPI 映射到perf_param_v2.cpp中的kVfInstructPerfTable类型例如MicroAPI::Add映射为kAdd。映射前必须查perf_param_v2.cpp不要假设表项存在。从仓库看kVfInstructPerfTable是一张std::mapstd::string, std::vectorVfInstructPerf常量表每个表项形如{kAdd, {{VfInstructPerf{{kUInt8, kInt8, ...}, 4, 2}}, {VfInstructPerf{{kFloat32, kFloat16, kBfloat16}, 4, 1}}}}即同一指令按 dtype 分组给出(latency, throughput)见 perf_param_v2.cpp。如果找不到精确匹配使用kPlaceholder并在代码注释中说明真实 MicroAPI 名称和暂用原因。MicroAPI::DataCopy按 load/store 两类统一建模load 使用 input dtypestore 使用 output dtypeLoadDist、StoreDist、pack/unpack 模式只作为注释说明不因模式变化额外增加一条 DataCopy 成本。第 6 步计算 MicroAPI 执行次数每个源码中的 MicroAPI 都应能追溯到性能公式中的一次VfPerfUtils::AddVfInstructPerf计算。AddVfInstructPerf的最后一个参数次数必须来自源码循环次数或 codegen 透传参数。对嵌套循环计算总次数例如outer_count * repeat_time。对只在循环外执行一次的Duplicate、mask 创建、scalar 初始化等次数按源码实际执行次数建模不要误乘repeat_time。如果循环次数依赖运行时数据值必须说明无法精确获取的原因并采用保守估计或要求透传参数。第 7 步合并同类 MicroAPI同一种 MicroAPI 类型可以只调用一次VfPerfUtils::AddVfInstructPerf最后一个参数使用该 MicroAPI 在当前分支中的总执行次数。合并时必须保留注释或表格能追溯每一部分次数来自哪个源码位置。对kPlaceholder合并键必须包含真实 MicroAPI、操作方向/模式和 dtype三者都相同才能合并。即使性能表类型相同也禁止合并不同真实 MicroAPI例如Not与ShiftRights、Pack与UnPack。MicroAPI::DataCopy的 load 与 store 必须分开不能因为都映射为kPlaceholder而汇总。kPlaceholder直接调用VfPerfUtils::AddVfInstructPerf不要增加AddPlaceholderPerf一类包装函数。第 8 步套用统一 cost 结构每个 MicroAPI 通过VfPerfUtils::AddVfInstructPerf(type, dtype, max_latency, all_vf_instruct_cost, count)累加其语义为AddVfInstructPerf内部查询 latency 和 throughputlatency 取所有 MicroAPI 的最大值throughput * count累加到all_vf_instruct_cost。最终公式固定为Expr res VfPerfUtils::GetVFHeadCost() max_latency all_vf_instruct_cost; res.Simplify(); perf.pipe_res[PipeType::AIV_VEC] res;这一结构在仓库中有直接的实现佐证。vf_perf_utils.cpp 中的VfPerfUtils::AddVfInstructPerf对每个表项做latency af::sym::Max(CreateExpr(api_perf.latency), latency)与throughput throughput CreateExpr(api_perf.throughput) * repeat_time而VfPerfUtils::GetVFHeadCost()返回性能表中的GetVectorFunctionHeadCost()GetVectorFunctionPerfByStrideStatus则正是all_micro_api_cost max_latency vector_function_head_cost的累加实现。从源码注释可以确认第一版建模是简化模型仅考虑 MicroAPI 的 latency/throughput、调用次数和 Vector Function 启动开销三项每个 op 的 latency 取最大值、throughput 求和循环轴头开销与 MicroAPI 并发度留待后续版本见 vf_perf_utils.cpp。四、API 参数对齐原则性能模型透传的参数必须与实际 AscendC API 调用保持一一对应这是公式可信度的底线排除输入、输出 Tensor 后按 API 签名的原始顺序保存其余参数不要用repeat_count、flattened_count或分支标志替换原始参数。参数的维度、stride、mask、offset 和 loop 数组要保持与生成代码相同的语义粒度性能模型只在计算公式内部派生临时量。以CastExtend(dst, src, output_dims, output_stride, input_stride)为例节点参数应保存output_dims、output_strides和input_strides仅排除dst、src。CastExtend节点参数中的output_dims、output_strides、input_strides应来自merge_info/ApiLoopParams的原始表达式实际生成 API 调用时可以继续使用tpipe.tiler但传给性能公式的节点参数不能使用 tiler 展开结果。参数链路必须可追溯EnrichAscirGraphNodeParams预注册 →{ApiCallName}::Generate按实际调用填充 →FillSpecificParams提取 →NodeInfo→ perf 函数。如果原始 API 参数缺失必须明确回退到 shape 信息的条件和精度影响禁止在 ATT 中凭经验重建 codegen 已经确定的参数。五、MicroAPI 映射规则一般情况下性能表类型为 MicroAPI 指令名增加k前缀例如MicroAPI::Add对应kAdd、MicroAPI::UpdateMask对应kUpdateMask。该 SKILL 刻意不在文档内维护完整的一一映射表避免与性能表实现漂移建模时按以下顺序确认提取真实 MicroAPI 指令名以k 指令名作为候选性能表类型。在perf_param_v2.cpp和常量定义中确认候选类型真实存在并确认目标 dtype 受支持不能只根据命名猜测。对带模式语义的模板 API使用性能表中对应的语义后缀例如CompareScalar..., CMPMODE::NE对应kCompareScalarNE。如果没有精确表项使用kPlaceholder并按真实 MicroAPI、操作方向/模式和 dtype 分开调用。DataCopy的 load 与 store 即使都没有精确表项也必须分开建模并分别注释同一次 load 或 store 的LoadDist/StoreDist模式不额外重复建模。如果性能表已有对应 MicroAPI 类型但暂不支持源码中的真实 dtype仍按源码真实 dtype 调用该 MicroAPI 类型不要为了命中现有表项改成中间 dtype、输出 dtype 或kPlaceholder。性能表缺项应后续扩展公式必须先保持源码语义正确。从仓库实现看kPlaceholder与kUpdateMask均真实存在于 perf_param_v2.cpp 的性能表中且kPlaceholder在 broadcast_last_axis_perf_v2.cpp 等现有 perf 实现中被直接使用kUpdateMask也出现在 broadcast 类 perf 中——这印证了按真实 MicroAPI dtype 直接调用AddVfInstructPerf是仓库内的既定实践。六、Placeholder 调用示例错误不同真实操作或不同方向被汇总后续无法替换为精确表项。VfPerfUtils::AddVfInstructPerf(kPlaceholder, dtype, max_latency, all_vf_instruct_cost, repeat_time * 4);正确直接调用AddVfInstructPerf每个占位项都能追溯到唯一真实操作。// MicroAPI::DataCopy (load). VfPerfUtils::AddVfInstructPerf(kPlaceholder, input_dtype, max_latency, all_vf_instruct_cost, repeat_time); // MicroAPI::DataCopy (store). VfPerfUtils::AddVfInstructPerf(kPlaceholder, output_dtype, max_latency, all_vf_instruct_cost, repeat_time); // MicroAPI::Packuint32_t, int64_t, two calls with the same mode and dtype. VfPerfUtils::AddVfInstructPerf(kPlaceholder, int64_dtype, max_latency, all_vf_instruct_cost, repeat_time * 2); // MicroAPI::UnPackuint64_t, uint32_t. VfPerfUtils::AddVfInstructPerf(kPlaceholder, uint32_dtype, max_latency, all_vf_instruct_cost, repeat_time);注意示例中 load 与 store 各自独立调用、Pack按同 mode 同 dtype 合并为一次调用次数乘以 2、UnPack单独调用——这正是第 5、7 步规则的直接落地。七、建模输出模板每个算子的建模结论建议按以下模板输出保证可评审、可追溯### 源码依据 - codegen impl... - API 名称... - API 源码... - API 调用生成...::{ApiCallName}::Generate - 性能表.../perf_param_v2.cpp - 当前 perf 实现.../ascendc_regbase_perf.cpp ### 参数来源 | 源码参数 | codegen 传参来源 | ATT 是否可直接获取 | 处理方式 | | --- | --- | --- | --- | | dst | outputs[0] | 是/否 | ... | | src | inputs[0] | 是/否 | ... | | loop_param | ApiLoopParams | 否 | 需通过节点参数透传 | ### 分支分析 - 分支 A触发条件参数来源源码行公式差异 - 分支 B触发条件参数来源源码行公式差异 ### MicroAPI 计数 | MicroAPI | perf 类型 | 执行次数 | dtype | 说明 | | --- | --- | --- | --- | --- | ### 公式 cpp Expr max_latency CreateExpr(0); Expr all_vf_instruct_cost CreateExpr(0); // AddVfInstructPerf(...) Expr res VfPerfUtils::GetVFHeadCost() max_latency all_vf_instruct_cost; ### 不确定点 - 无或列出需要用户确认/源码待确认的问题。该模板与 SKILL 的验证要求一一对应源码依据覆盖五类证据文件参数来源强制逐参标注 codegen 来源与 ATT 可获取性分支分析强制穷举源码分支MicroAPI 计数强制可追溯到源码位置公式固定统一 cost 结构不确定点兜底一切未证实内容。八、常见错误对照表错误正确做法直接复述现有 perf 公式先读 API 源码和 codegen 传参再解释现有公式是否简化只看input_shapes/output_shapes同时看{ApiCallName}::Generate确认实际传入 API 的参数需要 loop 参数却在 ATT 中猜测通过节点参数从 codegen 透传或说明无法精确获取Generate 才能确定的参数却要求EnrichAscirGraphNodeParams计算具体值EnrichAscirGraphNodeParams只预注册空结构Generate填具体值性能函数只能访问NodeInfo却让 ATT 直接读 Node补FillSpecificParams把节点参数提取到NodeInfo只写入节点参数但 ATT 读取路径不明确明确链路预注册空结构 - Generate 填值 - FillSpecificParams - NodeInfo - perf给 ATT 的节点参数保存tpipe.tiler.Size/ActualSize展开值保存merge_info/ApiLoopParams原始符号表达式tiler 表达式只用于生成 C 调用字符串忽略if constexpr或 scalar/mask 分支每个源码分支单独列触发条件和计数把所有 MicroAPI 都乘repeat_time按源码实际循环层级计算次数找不到性能表项就跳过使用kPlaceholder并注释真实 MicroAPI性能表暂不支持真实 dtype 就换成支持的 dtype保持源码真实 MicroAPI 类型和 dtype后续扩展性能表多个同类 MicroAPI 重复调用多次合并为一次AddVfInstructPerf次数求和把不同真实 MicroAPI 汇总到一个kPlaceholder按真实 MicroAPI、方向/模式和 dtype 分开调用把DataCopyload 和 store 合并load 与 store 分开调用并分别注释因DataCopy的 pack/unpack 模式再额外补一条成本DataCopy 只按 load/store 建模dtype 分别使用 input/output用辅助函数包装kPlaceholder直接调用VfPerfUtils::AddVfInstructPerf(kPlaceholder, ...)UpdateMask使用kPlaceholder使用性能表已有的kUpdateMask未说明不确定点不确定时先提问或列入不确定点表中多数正确做法都能在仓库中找到既有实现kUpdateMask在 broadcast_api_perf_v2.cpp 中直接使用kPlaceholder在 broadcast_last_axis_perf_v2.cpp 中按 dtype 直接调用AddVfInstructPerf——说明占位项唯一可追溯不是纸面规范而是当前性能代码的实际风格。九、公式完成后的验证要求完成公式后至少检查以下十项API 源码入口能从GetApiName()追溯。API 调用参数能从{ApiCallName}::Generate追溯。ATT 使用的额外参数若来自 codegen已通过节点参数传递若性能函数只能访问NodeInfo必须确认EnrichAscirGraphNodeParams已预注册空结构、Generate已填值、FillSpecificParams已提取到NodeInfo。公式中的每个AddVfInstructPerf都能追溯到源码 MicroAPI。每个循环次数都能追溯到源码循环、codegen 参数或明确的保守估计。每个 MicroAPI 类型都在perf_param_v2.cpp中存在不存在时已用kPlaceholder并说明。每个kPlaceholder都有唯一的真实 MicroAPI、操作方向/模式和 dtypeload/store 及不同真实类型未合并。kPlaceholder均直接调用VfPerfUtils::AddVfInstructPerf未增加包装函数。MicroAPI::UpdateMask使用kUpdateMask。最终 cost 使用VfPerfUtils::GetVFHeadCost() max_latency all_vf_instruct_cost。这十项检查与第七节的输出模板逐段呼应也与 vf_perf_utils.h 暴露的VfPerfUtils接口GetVfInstructPerf/AddVfInstructPerf/AddVfInstructDtypeMappingPerf/GetVFHeadCost/GetVectorFunctionPerf一一对应确保公式既是从源码反推的又是与统一 cost 框架兼容的。十、与其他 Skill 的配合关系该 SKILL 属于.claude/skills/技能体系中的性能建模环节同目录还包含 af-code-reviewer、af-reg-ascir、af-test-developer 等。配套的 README.md 明确了其触发场景当用户提出计算 cast 算子的性能公式分析 compare 算子性能公式、讨论 ATT 性能建模、MicroAPI 成本、repeat_time/call_count或 codegen 与性能公式对齐时即可按本文的八步流程开展工作验证方式是在 opencode 中直接输入上述指令检查 Skill 是否生效。总结V2 节点性能建模的正确姿势是让源码AscendC API→ 生成codegen Generate→ 透传节点参数链路→ 查表perf_param_v2→ 累加统一 cost 结构五层证据环环相扣。凡公式中出现的每一个 MicroAPI、每一个循环次数、每一个 dtype都必须能在源码或 codegen 传参中找到出处——这正是该建模方法论区别于拍脑袋估算的本质所在。【免费下载链接】graph-autofusionGraph-autofusion 是一个面向昇腾Ascend芯片的轻量级、解耦式组件集合旨在通过自动融合技术加速模型执行。 目前已开源 SuperKernel 组件和 Autofuse 组件未来将持续开放更多自动融合相关模块。项目地址: https://gitcode.com/cann/graph-autofusion创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表