AscendC Matmul L0 缓存(L0A)直调样例深度解析:减少 MTE1 重复搬运的使能条件与实现原理 人工智能深度学习算子库CANNAscend【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址https://gitcode.com/cann/asc-devkit点击查看免费下载导读本篇文章围绕 asc-devkit 仓库中的 Matmul L0 缓存L0 Cache直调样例展开讲解如何在 AscendC 算子中利用 Matmul API 的 L0 缓存特性通过让 A 矩阵数据在 A2 缓冲区驻留复用、与不同 B2 数据依次完成乘加运算从而减少 MTE1 的重复搬运。读完本文你将掌握 L0 缓存的使能条件全部常量化 Tiling 配置、singleCoreMbaseM且singleCoreKbaseK、样例工程的编译运行方式NPU/CPU/仿真三种模式以及该特性在 Matmul 库内部的自动判定与缓存命中实现原理。概述什么是 Matmul L0 缓存以左矩阵 A 为例Matmul 的 Cube 计算流水线中A 矩阵数据需要先由 MTE2 从 GM 搬运到 L1A1 缓冲区再经 MTE1 从 L1 搬运到 L0A2 缓冲区后才能参与乘加运算。所谓L0 缓存指的是当 A1 中数据搬运到 A2 后该份数据保持在 A2 中不释放后续循环中缓存数据依次与 B2 中不同的数据完成乘加运算从而避免同一份 A 数据被重复执行 MTE1 搬运。其核心收益即文档所述减少 MTE1 重复搬运。说明L0 缓存没有对外开关是否开启由 Matmul API 内部根据用户配置的 shape 信息自动推导开发者只需按照使能条件配置 Tiling 即可。使能条件L0 缓存的开启前提根据 matmul_l0cache 样例文档当前仅支持L0A 缓存使能场景要求如下需要配置全部常量化 Tiling 场景singleCoreM/singleCoreN/singleCoreK和baseM/baseN/baseK均需通过常量化接口设置singleCoreM baseM同时singleCoreK baseK。从源码看自动判定逻辑Matmul 库内部在编译期通过IsL0ACache/IsL0Cache常量表达式函数自动判断是否启用 L0 缓存实现在 matmul_utils.htemplate typename T, const auto MM_CFG __aicore__ inline constexpr bool IsL0ACache() { return (ToMatmulConfig(MM_CFG).singleCoreK ToMatmulConfig(MM_CFG).basicK) (ToMatmulConfig(MM_CFG).singleCoreM ToMatmulConfig(MM_CFG).basicM); }IsL0Cache在IsL0ACache之外还叠加了多项前提检查包括不支持含 scale 位置MX 量化的 A 类型、不支持 Load2dV2 特性、需要开启 Norm/MDL 调度、不允许intraBlockPartSum、A/B 布局需为LayoutMode::NONE、不允许isA2B2Shared等且singleCoreM等六个 shape 参数均需大于 0最终要求IsL0ACache IsL0BCache同时成立。可见文档中“singleCoreMbaseM且singleCoreKbaseK”正是命中IsL0ACache判定的核心 shape 条件其余条件则由 Matmul API 的默认模板CONFIG_NORM与使用约束共同保证。缓存命中机制TBufPoolL0 与调度器的 Hit 判断L0 缓存的落地实现位于缓存池专用特化类 tbuf_pool_l0_cache.h该类通过模板特化条件IsL0CacheA_TYPE, MM_CFG()与常规缓存池tbuf_pool_l0_common.h、tbuf_pool_l0_v200.h分流维护l0aPingCachedPos_/l0aPongCachedPos_以及对应的 l0b 两组缓存位置标记记录当前驻留在 A2/B2 中的数据块位置HitTPosition::A2(pos)判断请求的数据块是否已在缓存中命中命中时返回 true 并切换 ping/pong 标志ResetCache()通过WaitFlag/SetFlagHardEvent::M_MTE1事件同步解决多对象间的同步问题并将缓存位置重置为 -1。调度器侧Norm 调度 scheduler_norm.h的SplitA/SplitB配合Hit实现“命中即复用”// posA 由 MLoop 内层迭代序号与 KLoop 迭代序号共同计算 if (!(MATMUL_MODULE(TBufPoolL0)-template HitTPosition::A2(posA))) { a2 MATMUL_MODULE(TBufPoolL0)-template GetBufferTPosition::A2, TransAT(); MATMUL_MODULE(LoadToA2)-Load(...); // 未命中执行 MTE1 搬运 } else { a2 MATMUL_MODULE(TBufPoolL0)-template GetBufferTPosition::A2, TransAT(); // 命中跳过 MTE1 搬运直接复用 A2 中驻留的数据 }当singleCoreM baseM时 M 方向单核内无需切分同一份 A 数据块在 K 方向外层循环中可反复命中这正是“减少 MTE1 重复搬运”的底层来源。Hit中注释singleMK baseMK, no need to pingpong也印证了该设计。样例工程结构matmul_l0cache 样例位于 examples/01_simd_cpp_api/04_advanced_api/00_matmul/matmul_l0cache目录结构如下文件作用matmul_l0cache.asc算子主程序Tiling 生成、Matmul Kernel 实现、ACL 运行框架CMakeLists.txt编译配置声明运行模式与 NPU 架构选项scripts/gen_data.py生成测试输入数据A/B/Bias与 golden 结果scripts/verify_result.py校验算子输出与 golden 的误差是否在容差内data_utils.h二进制文件读写工具函数ReadFile/WriteFile算子实现剖析matmul_l0cache.asc1. Shape 与常量 Tiling 配置算子以常量方式定义矩阵规模与单核/基础分块参数matmul_l0cache.ascconstexpr uint32_t M 2560; // 原始矩阵 M 维 constexpr uint32_t N 2048; // 原始矩阵 N 维 constexpr uint32_t K 128; // 原始矩阵 K 维 constexpr uint32_t NUM_BLOCKS 20; // 参与计算的核数 constexpr bool IS_TRANS_A false; constexpr bool IS_TRANS_B false; constexpr bool IS_BIAS true; constexpr static int32_t SINGLE_M 256; // 单核 M 维 shape constexpr static int32_t SINGLE_N 1024; // 单核 N 维 shape constexpr static int32_t SINGLE_K 128; // 单核 K 维 shape constexpr static int32_t BASE_M 256; // 基础分块 MBASEM * BASEK * sizeof(typeA) L0A size constexpr static int32_t BASE_N 128; // 基础分块 NBASEN * BASEK * sizeof(typeB) L0B size constexpr static int32_t BASE_K 128; // 基础分块 KBASEM * BASEN * sizeof(typeC) L0C size注意这里SINGLE_M BASE_M、SINGLE_K BASE_K恰好满足文档给出的 L0A 缓存使能条件。注释中还给出了 L0 容量约束baseM * baseK * sizeof(typeA) L0A size、baseN * baseK * sizeof(typeB) L0B size、baseM * baseN * sizeof(typeC) L0C size对应源码 matmul_shape_tiling.h 中StaticTilingCheck的static_assert检查。2. 常量化接口组装 Matmul 对象通过MatmulShapeParams结构体定义见 matmul_config.h字段包括singleCoreM/singleCoreN/singleCoreK与basicM/basicN/basicK与GetMMConfigMatmulConfigMode::CONFIG_NORM、GetMatmulApiTiling定义见 constant_tiling.h完成编译期常量 Tiling 推导constexpr static MatmulShapeParams shapeParams {SINGLE_M, SINGLE_N, SINGLE_K, BASE_M, BASE_N, BASE_K}; constexpr static MatmulConfig CUSTOM_CFG GetMMConfigMatmulConfigMode::CONFIG_NORM(shapeParams); constexpr static auto CONSTANT_CFG AscendC::GetMatmulApiTilingA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE(CUSTOM_CFG); AscendC::MatmulA_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CONSTANT_CFG matmulObj;GetMatmulApiTiling在编译期把singleCoreM/singleCoreN/singleCoreK写入MatmulApiStaticTiling的M/N/Ka/Kb及baseM/baseN/baseK实现“全部常量化 Tiling”。A/B/C/Bias 类型均通过AscendC::MatmulTypeTPosition::GM, CubeFormat::ND, T, IS_TRANS_A声明本样例为halfA、B×floatC、Bias。3. Kernel 主体流程MatmulKernel的Init中通过SetGlobalBuffer绑定 GM 上的 A/B/C/Bias 张量并调用matmulObj.SetOrgShape(tiling.M, tiling.N, tiling.Ka, tiling.Kb)设置原始 shapeProcess中先根据GetBlockIdx()判断尾块tail并调用SetTail随后依次执行matmulObj.SetTensorA(aGlobal, IS_TRANS_A); matmulObj.SetTensorB(bGlobal, IS_TRANS_B); if (tiling.isBias) { matmulObj.SetBias(biasGlobal); } matmulObj.IterateAll(cGlobal); matmulObj.End();多核切分逻辑在CalcOffset中完成按mSingleBlocks (M singleCoreM - 1) / singleCoreM把 M 维切分到多个核mCoreIndex blockIdx % mSingleBlocks、nCoreIndex blockIdx / mSingleBlocks并据此计算 A/B/C/Bias 的偏移。核入口matmul_l0cache_custom通过CopyTiling从 GM 拷贝 Tiling并用REGIST_MATMUL_OBJ注册 Matmul 对象。4. Tiling 生成GenerateTiling使用matmul_tiling::MultiCoreMatmulTiling生成运行时 TilingSetDim(NUM_BLOCKS)设置核数SetAType/SetBType/SetCType/SetBiasType设置各矩阵类型A/B 为DT_FLOAT16C/Bias 为DT_FLOATSetOrgShape与SetShape(M, N, K)设置矩阵规模SetSingleShape(SINGLE_M, SINGLE_N, SINGLE_K)设置单核 shapeEnableBias(IS_BIAS)使能 BiasSetBufferSpace(-1, -1, -1)使用默认缓冲空间最后GetTiling得到 Tiling 数据并保存到 buffer。5. ACL 运行框架main函数按ASCENDC_CPU_DEBUG与__NPU_ARCH__选择平台实例CPU 调试时dav-2201对应 Ascend910B1dav-3510对应 Ascend950PR_9589完成aclInit→aclrtSetDevice→aclrtCreateContext→aclrtCreateStream初始化后通过aclrtMallocHost/aclrtMalloc申请主机与设备内存读取./input/x1_gm.bin、./input/x2_gm.bin、./input/bias_gm.bin并拷贝到设备以matmul_l0cache_customNUM_BLOCKS, 0, stream(...)启动 20 核 Kernel同步后将结果写回./output/output.bin最后按序释放资源。编译运行三种模式完整步骤配置环境变量根据当前环境上 CANN 开发套件包的安装方式配置环境变量source ${install_path}/cann/set_env.sh说明${install_path}为 CANN 包安装目录未指定安装目录时默认安装至/usr/local/Ascend下。NPU 模式编译与执行在样例根目录examples/01_simd_cpp_api/04_advanced_api/00_matmul/matmul_l0cache下执行mkdir -p build cd build; # 创建并进入 build 目录 cmake -DCMAKE_ASC_ARCHITECTURESdav-2201 ..;make -j; # 编译工程默认 npu 模式 python3 ../scripts/gen_data.py # 生成测试输入数据 ./demo # 执行编译生成的可执行程序执行样例 python3 ../scripts/verify_result.py output/output.bin output/golden.bin # 验证输出结果是否正确确认算法逻辑正确CPU 调试与 NPU 仿真模式使用 CPU 调试或 NPU 仿真模式时添加-DCMAKE_ASC_RUN_MODEcpu或-DCMAKE_ASC_RUN_MODEsim参数即可cmake -DCMAKE_ASC_RUN_MODEcpu -DCMAKE_ASC_ARCHITECTURESdav-2201 ..;make -j; # cpu 调试模式 cmake -DCMAKE_ASC_RUN_MODEsim -DCMAKE_ASC_ARCHITECTURESdav-2201 ..;make -j; # NPU 仿真模式注意切换编译模式前需清理 cmake 缓存可在 build 目录下执行rm CMakeCache.txt后重新 cmake。编译选项说明选项可选值说明CMAKE_ASC_RUN_MODEnpu默认、cpu、sim运行模式NPU 运行、CPU 调试、NPU 仿真CMAKE_ASC_ARCHITECTURESdav-2201默认、dav-3510NPU 架构dav-2201对应 Atlas A2 系列产品和 Atlas A3 系列产品dav-3510对应 Ascend 950PR950DT 系列产品这两个选项在 CMakeLists.txt 中以CACHE STRING形式声明编译时通过--npu-arch${CMAKE_ASC_ARCHITECTURES}传递给 ASC 编译器并链接tiling_api、register、platform、m、dl库。数据生成与精度校验生成输入与 golden 数据gen_data.py 以与算子一致的m, n, k 2560, 2048, 128生成数据A 矩阵x1_gmnp.random.uniform(-1, 1, [m, k])转float16B 矩阵x2_gmnp.random.uniform(-1, 1, [k, n])转float16Biasnp.random.uniform(-10, 10, [n])转float32goldennp.matmul(x1_gm.astype(np.float32), x2_gm.astype(np.float32)) bias_gm即标准矩阵乘加 Bias 的结果。数据分别写入./input/x1_gm.bin、./input/x2_gm.bin、./input/bias_gm.bin与./output/golden.bin。结果校验verify_result.py 通过np.isclose对比输出与 golden容差设置为RELATIVE_TOL 1e-3 # 相对误差容限 ABSOLUTE_TOL 1e-3 # 绝对误差容限 ERROR_TOL 1e-3 # 允许的错误元素比例上限错误元素比例不超过ERROR_TOL时打印并返回成功否则逐条打印前 100 个差异元素的索引、期望值、实际值与相对偏差。执行成功后终端输出test pass!支持的产品与 CANN 版本产品CANN 软件版本Ascend 950PR950DT 系列产品 CANN 9.1.0Atlas A3 系列产品 CANN 9.0.0Atlas A2 系列产品 CANN 9.0.0小结matmul_l0cache 样例完整展示了 AscendC Matmul L0 缓存特性的使用路径通过MatmulShapeParamsGetMMConfigCONFIG_NORMGetMatmulApiTiling实现全部常量化 Tiling并使singleCoreMbaseM、singleCoreKbaseK触发库内IsL0ACache编译期判定最终由TBufPoolL0缓存池与 Norm 调度器的Hit命中机制在运行时复用 A2 驻留数据、跳过重复的 MTE1 搬运。对于希望优化 Matmul 算子 MTE1 搬运开销的开发者可参照本样例的 shape 配置与编译运行流程并结合本文给出的源码依据深入理解其判定与调度细节。赞分享人工智能深度学习算子库CANNAscend【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址https://gitcode.com/cann/asc-devkit点击查看免费下载相关推荐Batch Matmul 复用 Bias 矩阵直调样例深度解析基于 CANN AscendC 的批量矩阵乘 Bias 复用实现Batch Matmul 复用 Bias 矩阵直调样例深度解析基于 CANN AscendC 的批量矩阵乘 Bias 复用实现 批量矩阵乘Batch Mat人工智能深度学习算子库CANNAscend打破Minecraft版本壁垒Amulet地图编辑器让你的世界创作无边界打破Minecraft版本壁垒Amulet地图编辑器让你的世界创作无边界 还在为Minecraft版本不兼容而烦恼吗当Java版的精美建筑无法在基岩版中打开桌面应用游戏开发openapi-fetch响应缓存实现内存缓存减少重复请求openapi fetch响应缓存实现内存缓存减少重复请求 为什么需要响应缓存 你是否遇到过这样的情况用户在页面上频繁切换标签或按钮导致相同的API请求开发工具代码生成后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考