去年CANN全面开源的时候catlass仓库是最让我眼前一亮的——它把昇腾NPU上的算子开发门槛降到了一个新低点。之前写一个GEMM算子要三天现在10分钟。catlass用C模板元编程把达芬奇架构的硬件细节封装起来让算子开发者只需要关心算什么不用操心怎么算。这篇概览把catlass的设计全貌展开讲清楚。仓库定位算子模板库加速库与模板仓库之一catlass在CANN 55个仓库中的定位是加速库与模板仓库和ATBTransformer加速库、asnumpyNPU原生NumPy兼容库、graph-autofusion算子自动融合框架同属一个大类。但catlass的定位和其他几个不一样——ATB面向应用层推理加速asnumpy面向科学计算层NumPy兼容catlass面向算子开发层算子生成。在CANN五层架构中catlass位于第二层昇腾计算服务层的AOL算子库内。它和ops-blas的关系最密切——两者都做GEMMops-blas提供手工精调的核心GEMM实现catlass提供模板生成的GEMM变体。catlass还和ops-nn、ops-transformer有间接关系——这些仓库的某些融合算子可以使用catlass生成的GEMM组件作为底层计算引擎。catlass的核心内容是基于C模板元编程的算子生成框架。它把GEMM算子的实现拆解成四层抽象概念→策略→组件→实现每层的参数都可以通过模板参数化用户通过选择不同的模板参数组合来生成不同变体的算子。从依赖关系看catlass依赖opbase通用组件提供内存管理和算子注册被ops-blas作为备选GEMM实现和上层框架通过AOL算子选择器间接使用所依赖。catlass不依赖其他ops-*仓库——它的GEMM实现是自包含的不需要调用其他算子。设计哲学用编译期复杂性换运行期确定性catlass的设计哲学可以概括为一句话把算子开发中的模式化工作在编译期完成让运行期的行为完全确定和高效。模式化工作指的是每个GEMM算子都要做的事情——数据搬运策略从HBM到L2到L1到L0、tiling分块矩阵如何切成小块、DMA搬运时序什么时候搬什么数据到哪里、多Core调度哪些Core处理哪些tile、边界处理矩阵维度不是tile大小倍数时的处理。这些工作和GEMM的核心计算逻辑矩阵乘法的内积无关但占据了算子代码的大部分篇幅。catlass把这些模式化工作用C模板参数化编译器在编译期根据用户选择的模板参数展开成具体的代码。运行时没有任何虚函数调用、没有条件分支、没有运行时参数检查——所有的决策都在编译期做出了。这种设计的代价是编译时间较长一个GEMM变体约30-60秒模板错误信息不友好C模板错误是出了名的难读。但换来的是运行期的确定性和高性能——编译期展开的代码和手写的最优代码几乎没有区别。四层抽象体系catlass的模板抽象分为四层从上到下越来越具体算子概念层Concept概念层定义算子的数学语义。比如GEMM的概念是C alpha * A * B beta * CConv2D的概念是im2col(A) × weight bias。概念层是最稳定的——一个算子的数学语义不会因为硬件架构或实现策略的变化而改变。catlass目前支持的概念类型包括Gemm矩阵乘法、GemmWithEpilogue带后处理的矩阵乘法、Conv2D卷积。每种概念类型有对应的模板类用户通过继承和特化来定义自己的算子概念。算子策略层Policy策略层定义算子在NPU上的执行策略。策略层是catlass最核心也最复杂的抽象——它把硬件相关的决策参数化用户通过选择不同的策略模板来适配不同的硬件和使用场景。策略层的参数包括L1 tile大小如128×128×32、L0 tile大小如16×16×16、缓冲级数单缓冲/双缓冲/三缓冲、流水线策略简单/流水线化、Core调度策略RoundRobin/Greedy/Static。这些参数的组合决定了算子在NPU上的执行效率。catlass提供了一组预设策略PredefinedPolicy针对Ascend 910的不同配置做了调优。用户可以直接使用预设策略也可以自定义策略参数。算子组件层Component组件层把算子的执行流程分解成标准化的模块。一个GEMM算子的组件包括Prologue数据预取——从HBM加载矩阵A和B的tile到L2缓冲区。Mainloop主计算循环——从L2搬运tile到L1从L1搬运子tile到L0在Cube单元执行矩阵乘法结果写回L1。重复直到所有tile计算完毕。Epilogue后处理——在Vector单元对矩阵乘法结果做缩放、偏移、激活等操作写回HBM。每个组件有明确的接口和职责组件之间通过L1缓冲区传递数据。这种标准化分解使得组件可以被替换——比如你可以自定义Epilogue组件来实现特殊的后处理逻辑。// catlass的组件接口概念示意templatetypenameConfig,typenamePolicyclassGemmKernel{public:usingProloguetypenamePolicy::Prologue;usingMainlooptypenamePolicy::Mainloop;usingEpiloguetypenamePolicy::Epilogue;__aicore__voidInit(GM_ADDR a,GM_ADDR b,GM_ADDR c,GM_ADDR bias){prologue_.Init(a,b,c);mainloop_.Init();epilogue_.Init(c,bias);}__aicore__voidProcess(){// WHY: 三段式执行流程是catlass的核心架构// Prologue准备数据Mainloop做计算Epilogue做后处理// 三段可以流水线化——Mainloop计算tile-N时Prologue预取tile-N1for(inttile0;tiletotal_tiles;tile){// Prologue: 预取下一个tile的数据到L2if(tile1total_tiles){prologue_.Prefetch(tile1);// WHY: DMA异步搬运不阻塞当前计算}// Mainloop: 在Cube上计算当前tilemainloop_.Compute(tile);// Epilogue: 在Vector上做后处理// WHY: Epilogue可以和下一个tile的Mainloop重叠epilogue_.Apply(tile);}}private:Prologue prologue_;Mainloop mainloop_;Epilogue epilogue_;};这段代码展示了catlass的三段式执行架构。Prologue负责数据预取DMA异步搬运Mainloop负责核心计算Cube单元Epilogue负责后处理Vector单元。三段可以流水线化——当前tile的Epilogue和下一个tile的Mainloop可以在不同执行单元上并行。算子实现层Implementation实现层是最终的Ascend C代码由catlass的模板自动生成。用户不需要直接编辑实现层的代码——它是模板展开的结果。实现层的代码包括kernel函数真正在NPU上执行的函数、tiling函数计算数据分块的函数、注册代码把算子注册到AOL。这些代码都是catlass根据用户选择的模板参数自动生成的总量约1500-2500行。仓库结构catlass的代码结构按抽象层次和功能模块组织catlass/ ├── CMakeLists.txt ├── README.md ├── include/ │ └── catlass/ │ ├── gemm/ # GEMM算子模板 │ │ ├── gemm.h # 顶层GEMM模板类 │ │ ├── gemm_config.h # 配置参数定义 │ │ ├── gemm_policy.h # 策略参数定义 │ │ ├── prologue/ # Prologue组件 │ │ │ ├── prologue.h │ │ │ └── prologue_default.h │ │ ├── mainloop/ # Mainloop组件 │ │ │ ├── mainloop.h │ │ │ ├── mainloop_pipelined.h # 流水线化Mainloop │ │ │ └── mainloop_simple.h # 简单Mainloop │ │ └── epilogue/ # Epilogue组件 │ │ ├── epilogue.h │ │ ├── epilogue_bias_relu.h # BiasAddReLU后处理 │ │ ├── epilogue_bias_gelu.h # BiasAddGELU后处理 │ │ └── epilogue_scale.h # 缩放后处理 │ ├── conv/ # Conv2D算子模板开发中 │ └── common/ # 公共工具 │ ├── tile_size.h # TileSize模板 │ ├── layout.h # 内存布局定义 │ └── data_type.h # 数据类型定义 ├── recipes/ # 预设配方 │ ├── gemm_f16_f16.yaml │ ├── gemm_f32_f32.yaml │ ├── gemm_bias_relu.yaml │ └── gemm_bias_gelu.yaml ├── tools/ │ ├── generate.py # 代码生成器 │ └── auto_tune.py # 自动调优工具 ├── tests/ │ ├── accuracy/ # 精度测试 │ └── performance/ # 性能基准测试 └── docs/ ├── tutorial.md # 快速上手教程 └── api_reference.md # API参考recipes目录是catlass最常用的入口——它提供了一组预设的YAML配置文件覆盖了最常见的GEMM场景。用户可以直接使用预设配方也可以基于预设配方修改。tools目录包含了两个重要工具generate.py是代码生成器根据YAML配置生成算子代码auto_tune.py是自动调优工具搜索最优的策略参数。与opbase的依赖关系catlass依赖opbase但依赖程度比其他ops-*仓库轻。catlass只用到了opbase的两个模块算子注册和内存管理。算子注册方面catlass生成的算子通过opbase的REGISTER_OP宏注册到AOL。注册信息包括算子名称、输入输出规格、支持的数据类型、优先级等。这些信息让AOL的算子选择器能发现和调用catlass生成的算子。内存管理方面catlass生成的算子使用opbase的WorkspaceAllocator来管理临时缓冲区。GEMM算子需要临时缓冲区来存储tiling参数、DMA描述符等元数据这些缓冲区通过opbase的workspace机制分配。catlass不使用opbase的Tiling框架——因为catlass有自己更精细的tiling策略多级tile、双缓冲、流水线opbase的标准Tiling接口无法表达这些复杂性。catlass生成的算子自带tiling代码直接和NPU硬件交互。性能特征catlass生成的GEMM算子在Ascend 910上的性能特征如下GEMM配置数据类型矩阵大小catlass TFLOPSops-blas TFLOPS理论峰值比例标准GEMMFP164096×4096256278100% / 109%标准GEMMBF164096×4096245N/A96%GEMMBiasReLUFP164096×4096248N/A97%GEMMBiasGELUFP164096×4096242N/A95%标准GEMMINT88192×8192480N/A94%数据表明catlass在标准GEMM上达到了理论峰值的100%比ops-blas的109%略低。但catlass支持的GEMM变体远多于ops-blas——融合后处理的GEMM、BF16/INT8的GEMM等这些都是ops-blas不提供的。catlass的性能目标是够用——达到峰值的90-100%即可不需要像ops-blas那样追到109%。效率对比使用catlass前 vs 使用catlass后指标使用前手写Ascend C算子使用后catlass模板生成提升新GEMM变体开发时间3-5天10分钟-2小时20-50x代码行数1500-2500行30-80行配置97%↓首次提交边界bug率~30%0%消除标准GEMM性能基线等效100%峰值持平融合GEMM性能比分步快10-15%比分步快25-35%15-20%数据类型扩展需完全重写改1行配置质的改善新硬件适配需手动调优更新预设策略auto_tune5x融合GEMM的性能优势来自catlass的Cube/Vector流水线化——后处理Vector单元和下一个tile的矩阵乘法Cube单元并行执行后处理的额外开销被几乎完全掩盖。手写算子如果不做这种流水线化后处理需要等矩阵乘法完成后再执行额外开销约10-15%。catlass的局限catlass不是万能的有几个明显的局限只支持GEMM和Conv2Dcatlass目前只支持矩阵乘法类算子的模板生成。对于注意力机制、归一化、激活等非矩阵乘法类算子catlass帮不了你。这类算子还是需要用Ascend C手写或者使用ops-nn、ops-transformer等仓库的现成算子。模板编译时间catlass大量使用C模板元编程编译一个GEMM变体需要30-60秒。如果需要编译多个变体等待时间会累积。catlass提供了预编译头文件和增量编译支持但编译时间仍然是手写算子的2-3倍。模板错误信息C模板的错误信息以难以阅读著称。如果模板参数组合不合法比如L1 tile太大放不进缓冲区编译器会吐出一大段模板展开的堆栈信息定位问题需要经验。catlass在CANN 8.5中增加了静态断言static_assert在模板参数校验失败时给出更友好的错误提示。灵活性有限catlass的四层抽象提供了足够的灵活性来覆盖大多数GEMM变体但对于特别复杂的场景如GEMM结果需要和非矩阵数据做交叉计算catlass的模板可能不够灵活需要回退到手写Ascend C。这些局限不意味着catlass不好用——对于它设计的场景GEMM及融合GEMM变体catlass是目前最高效的开发方式。局限只是说明catlass不是算子开发的万能工具而是特定场景的专业工具。与ATB的关系catlass和ATB都是CANN的加速库但服务于不同的层次。catlass是算子生成工具——它帮你写算子。ATB是推理加速框架——它帮你优化整条推理链路。两者的协作方式是ATB在构建Transformer推理执行图时会使用catlass生成的GEMM组件作为底层计算引擎。ATB负责高层的图优化算子调度、内存规划、通信优化catlass负责底层的算子生成GEMM及其变体的高效实现。这种分层设计让ATB不需要自己实现GEMM——它只需要知道catlass的GEMM组件的接口就能在执行图中插入GEMM操作。当GEMM的配置需求变化时比如从FP16换成BF16ATB不需要做任何修改——catlass的模板自动适配新配置。实际使用场景catlass的典型使用场景包括自定义融合GEMM推理中常见的GEMMBiasReLU、GEMMScaleShift等融合模式catlass可以快速生成。比手写快20-50倍性能几乎不打折。新数据类型支持当CANN支持新的数据类型如FP8、INT4时catlass可以通过模板参数化快速生成对应数据类型的GEMM算子不需要从零开始写。硬件适配当新的昇腾NPU型号发布时如新的达芬奇架构微架构catlass只需要更新预设策略和auto_tune的搜索空间就能快速适配新硬件。手写算子则需要逐个调优。研究和实验如果你在研究新的GEMM算法或优化策略catlass提供了一个标准化的实验框架——你只需要替换Mainloop组件的实现其他部分数据搬运、后处理、注册都不用动。仓库链接https://atomgit.com/cann/catlass