跳转至

BackendHandler:原则化的后端分发

跟踪 issue:#948

背景

早期版本的 PyPTO 在 pass 与 codegen 中直接根据 backend::BackendType 做分支:

if (backend::GetBackendType() != backend::BackendType::Ascend910B) { ... }

这种写法导致每新增一种后端,都要去整个代码库里翻这些散落的 if,并且为每一处 都补一条 case。BackendHandler 把所有这类分支集中到一个虚接口里,使新增后端 变成一次自包含的局部修改。

设计

BackendHandlerinclude/pypto/backend/common/backend_handler.h)是一个抽象 接口,它把后端之间所有"行为差异"显式命名出来。每个 Backend 子类各自持有一个 BackendHandler 子类的单例,并通过新引入的纯虚函数 Backend::GetHandler() 对外暴露。

                       ┌────────────────────────────┐
        Pass / Codegen │  PassContext::Current()    │
                       │     ->GetBackendHandler()  │
                       └─────────────┬──────────────┘
                       ┌────────────────────────────┐
                       │  BackendConfig::GetBackend │
                       │     ->GetHandler()         │
                       └─────────────┬──────────────┘
                ┌──────────────────────────────────────┐
                │  Backend910B / Backend950 / ...      │
                │     -> Ascend910BHandler::Instance() │
                │     -> Ascend950Handler::Instance()  │
                └──────────────────────────────────────┘

PassContext 上的便捷访问点满足 pass-context-config 规则的要求:pass 通过 当前 PassContext 查询后端行为,而不是直接读全局状态。

接口

方法 用途 Ascend910B Ascend950
GetPtoTargetArch() module attributes {pto.target_arch = "..."} "a2a3" "a5"
GetLaunchSpecCoreCountMethod() launch_spec 上设置核数的运行时 API 名 "set_block_num" "set_core_num"
GetDefaultSimPlatform() 默认仿真平台名 "a2a3sim" "a5sim"
GetExtraPtoasFlags() ptoas 额外参数 [] ["--pto-arch", "a5"]
RequiresGMPipeBuffer() ExpandMixedKernel 是否注入 GM 槽位缓冲 true false
RequiresSplitLoadTpopWorkaround() MemoryReuse 是否做 load + tpop_from_aic 原地复用危害规避 true false
RequiresVtoCFractalAdapt() AIV 端 V→C tpush 是否需要 fractal 适配 tile.move false true
RequiresRuntimeSubblockBridge() 拆分 AIV 包装器是否从 runtime 上下文取 subblock id true false
RequiresNoSplitDualAivDispatch() no_split 混合 kernel 是否仍需在两个 AIV lane 上同时下发 true false
BuildCrossCoreTransferView(dest, view) 跨核传输边界处的 tile 视图 Mat/Left/Right 转 NZ;Vec 保持原样 Mat/Left/Right 转 NZ(a5 硬件要求边界为 fractal);Vec 保持原样

新增后端流程

  1. src/backend/<arch>/backend_<arch>.cpp 中实现 Backend<Arch> 子类, 并把源文件加入 CMakeLists.txt
  2. src/backend/<arch>/backend_<arch>_handler.cpp 中实现 Backend<Arch>Handler 子类。
  3. Backend<Arch>::GetHandler() 返回你的 handler 单例。
  4. src/backend/common/backend.cpp 中给 GetBackendInstanceBackendTypeToString 各加一行,并在 BackendType 枚举中添加新值。 这是整个仓库里唯一按枚举展开的地方。

任何 pass / codegen 文件都不需要修改。可以用 tests/ut/backend/test_backend_handler.py 配合 tests/ut/ir/transforms/tests/ut/codegen/ 里的回归测试做验证。

Python 访问方式

handler 也通过 Python 绑定暴露:

from pypto.pypto_core import backend as _backend_core

# 全局后端类型已配置时:
handler = _backend_core.get_handler()

# 调用方已知道目标后端时:
handler = _backend_core.get_backend_instance(BackendType.Ascend950).get_handler()

handler.get_pto_target_arch()              # "a2a3" 或 "a5"
handler.requires_runtime_subblock_bridge()  # bool
handler.get_extra_ptoas_flags()            # list[str]

运行时相关的 Python 模块(pypto.runtime.runnerpypto.ir.compiled_programpypto.backend.pto_backend)现在通过这些访问器来获取后端行为,不再直接判断 BackendType,与 C++ 改造保持一致。