MNN Vulkan 后端性能优化实战指南:从基准测试到 Kernel 优化的完整工作流
MNN Vulkan 后端性能优化实战指南从基准测试到 Kernel 优化的完整工作流【免费下载链接】MNNMNN: A blazing-fast, lightweight inference engine battle-tested by Alibaba, powering high-performance on-device LLMs and Edge AI.项目地址: https://gitcode.com/GitHub_Trending/mn/MNN本文是 MNN 开源推理引擎 Vulkan 后端buffer 后端面向 Adreno / Mali / Apple 移动 GPUkernel/算子性能优化与新特性集成的完整技术指南覆盖基准建立、CPU/GPU 瓶颈判定、shader 外科式修改、三层正确性验证、交替 A/B 真机测速以及 cooperative matrix / subgroup 等 Vulkan 新特性的集成流程。读完你将掌握一套可复现、防踩坑的 Vulkan 优化方法论并能直接应用于 MNN 的 LLM prefill/decode 场景。一、优化工作流总览与核心原则Vulkan 后端的性能优化不能靠先猜再优化MNN 将其沉淀为一条可执行的流水线依据 skills/vulkan-optimize/SKILL.md 与同目录 benchmark/kernel-opt/integrate 三份分步文档选择优化方向模型级优化方向 A/ 指定算子优化方向 B/ 新特性集成方向 C建立基准Profile 全模型先分 CPU/GPU 瓶颈再定位 GPU 内瓶颈 kernel迭代优化每次只改一个点至少尝试 3 种技巧交替 A/B 验证集成验证全量回归 小/大模型跨规模验证 代码质量审查沉淀经验把可复用方法论回写到 optimization-handbook.md。整个流程围绕 11 条核心原则展开其中最容易改了不生效的根因集中在这几条改.comp必跑 makeshader 等价流程GLSL 源不会被构建系统直接编译运行时读的是AllShader.h/cpp里由makeshader.py生成的 SPIR-V 字节数组.comp →glslangValidator -V→spirv-opt -O→xxd嵌入。dispatcher 选路要先摸清同一个 op 常有多条 kernelCoopMat / subgroup / nosubgroup / 融合 vs 分离盲改往往根本没被调度不要把 fallbacknosubgroup路径性能当 baseline。packed weight 必须 packing/unpack 双向镜像host weight prepare shader 写出的字节布局要与 decode shader 读取逐 bit 匹配。正确性 oracle 先于性能优化前要有已知正确的 baseline数学等价的改动应与 baseline 逐 token 一致。真机才算数且面向多个 vendorVulkan 同时跑 AdrenoAndroid、MaliAndroid、AppleiOS/MoltenVKdriver 差异极大Mac MoltenVK ≠ Android Adreno。Buffer / Image 是编译期二选一由MNN_VULKAN_IMAGE决定两个后端是完全独立的代码树。换 shader 后必清 pipeline cache持久化的VkPipelineCachetmp/mnn_cachefile.bin在 shader 变更后会 stale → 直接 segfault。二、选择优化方向A/B/C 三轨场景方向说明提升整个模型推理性能A模型级优化Profile 全模型 → 定位瓶颈先分 CPU/GPU→ kernel 或算子级优化 → 重新 profile → 迭代用户指定优化某个算子B指定算子优化直接进入指定算子判断 kernel 级或算子级集成 Vulkan 新特性coop matrix / subgroup / 扩展C新特性集成理解示例代码 → 适配 MNN → 特性检测 fallback → 验证三个方向共享顺序执行、允许回退、每步验证的通用规则每个步骤都有明确的通过标准。三、方向 A模型级优化的执行流程Profile 全模型op 级 shader 级耗时 ↓ 先判断瓶颈在 CPU 调度 还是 GPU kernelhandbook §1.4 ├─ CPU 调度瓶颈 → 算子融合减 op / indirect batch / fixResizeCachehandbook §2/§6 └─ GPU kernel 瓶颈 → 定位耗时占比最高的 kernel/op ├─ Kernel 级 → Kernel 优化流程 └─ 算子级 → 算子级优化流程 ↓ 重新 Profile 全模型验证整体提升 ↓ 定位下一个瓶颈重复直到满足需求Step A.1Profile 全模型用-DMNN_GPU_TIME_PROFILEON编译——注意这是编译期宏而非运行时开关。Vulkan profiler 有两块输出[Execution Profiling]op 级按 op 类型Convolution / Attention / Raster / …聚合 GPU 时间[Shader Profileing]shader 级按具体 shader 名glsl_..._comp的 GPU timestamp。⚠️ 两块输出都跨 execute 累计到程序退出且含 load 期的 auto-tune forward——分析稳态时只取Prepare for tuning opt End之后的块。通过标准拿到 op 级 shader 级耗时排序确定第一个优化目标并已判断瓶颈在 CPU 还是 GPU。Step A.2判断优化级别信号级别进入流程端到端 ≫ GPU kernel 累计GPU 只占几分之一CPU 调度瓶颈算子融合 / indirect batch / fixResizeCache单个 shader 占比高、本身有优化空间Kernel 级→ Kernel 优化流程同一算子多个 shader 合计耗时高 / 有大量格式转换算子级→ 算子级优化流程算子计算模式不适合 GPU单 work-item 串行算子级→ 算子级优化流程Step A.3验证并迭代重新 profile确认瓶颈耗时下降 端到端提升未满足则回到 A.1 定位下一个瓶颈。四、方向 B指定算子优化与算子级优化流程用户指定算子时先 profile 算子内各 shader 耗时最慢的单个 shader 走 Kernel 优化流程跨 kernel 边界的问题合并/拆分 dispatch、改中间排布、融合 epilogue走算子级优化流程。算子级优化流程方向 A/B 共用定位算子内所有 shader读 Execution::onEncode/onResize ↓ Profile 各 shader 耗时占比 ↓ 整体分析策略 - 合并 dispatch减少命令录制 中间 bufferVulkan CPU 调度重收益常更大 - 融合 epilogue把 unpack/scale 折进 matmul省一次 dispatch temp - 拆分提高并行度 - 改中间数据排布消除格式转换 / raster - 用 cooperative matrix 重写 matmul ↓ 迭代验证直到算子整体性能满足需求各手段的适用场景与本仓库的真实案例手段适用场景本仓库案例融合 epiloguematmul 后有独立 unpack/转置 passconv1x1 coop 把 COOP_to_C4 折进 matmul epilogue小 N 收益大 N 反伤 occupancy → 按 N 门控coop matrix 重写GEMM/QKVAdreno 支持 coopattention QK·V 用 coopscalar qkv_acc 102ms → coop 54mssubgroup 归约有 tree reduction barrierprefill softmax 用 subgroupMax/Add 替代树形37→23ms合并 dispatch / indirect batch命令录制占大头MNN_GPU_RECORD_BATCH让多 op 共享 command bufferprefill 56%Vulkan 关键提醒算子级优化前先确认瓶颈是 GPU 还是 CPU 调度。若是 CPU 调度GPU kernel 再快端到端也不动。五、Kernel 优化流程从瓶颈分析到交替 A/B分析 shader 的计算强度 / BW 利用率handbook §1 ↓ 判断瓶颈类型compute / memory / occupancy ↓ 从 §2 技巧 §5 速查表选匹配方法 ↓ 实施 → 验证正确性 → 测量性能交替 A/B ↓ 未达预期换一种技巧重试阶段文档目标基准benchmark.md建立性能基准分析瓶颈类型优化kernel-opt.md至少尝试 3 种技术迭代提升集成integrate.md全量回归、代码审查、性能报告迭代至少 3 种技术按难度递进先手低难度push_constant、indirect batch、epilogue 合并写再上中难度subgroup 归约、融合 epilogue 按规模门控最后高难度cooperative matrix 重写、算子整体重写。停止条件须全满足已试 ≥3 种 / 达标或连续 3 次 5% 提升 / 每次都有 A/B 数据记录。六、编译与真机运行Android唯一来源编译cd project/android/build_64 # 首次配置确认 buffer 后端 LLM cmake .. -DMNN_VULKANON -DMNN_VULKAN_IMAGEOFF -DMNN_BUILD_LLMON \ -DMNN_SUPPORT_TRANSFORMER_FUSEON -DMNN_LOW_MEMORYON -DMNN_ARM82ON make llm_demo -j8 # SEP_BUILDOFF → 会重编 libMNN.so # 需要 GPU per-op/shader 耗时cmake -DMNN_GPU_TIME_PROFILEON . #测干净 tok/s 时务必 OFF要点参数MNN_VULKAN_IMAGEOFF明确走buffer 后端LLM 全链路走 bufferON则是source/backend/vulkan/image/*的独立代码树两边改动互不影响make MNN不会连带重编 Vulkan 静态库必须用make llm_demo改 shader 后AllShader.cpp变了也会重编该宏在 source/backend/vulkan/CMakeLists.txt 中定义并分别驱动 buffer/image 两棵代码树的构建。推送 运行adb push libMNN.so llm_demo /data/local/tmp/MNN/ adb -s serial shell cd /data/local/tmp/MNN rm -f tmp/mnn_cachefile.bin \ LD_LIBRARY_PATH. ./llm_demo model/config_vk.json prompt.txt ndecode换 shader 后必清tmp/mnn_cachefile.bin否则 stale pipeline cache 会 segfault。profile 命令示例benchmark.md §0.3adb -s serial shell cd /data/local/tmp/MNN rm -f tmp/mnn_cachefile.bin LD_LIBRARY_PATH. ./llm_demo model/config_vk.json 512.txt 2 21 prof.txt。入口定位grep -rn OpType_MyOp source/backend/vulkan/buffer/execution/ # buffer 后端 grep -rn OpType_MyOp source/backend/vulkan/image/execution/ # image 后端conv1x1 低 bit 选路VulkanConvolution.cpp 的onCreateuseInt8Conv is1x1 ├─ coopMat supported Adreno │ ├─ perChannelAsym S8S8S32 → VulkanConv1x1CoopA8 │ └─ else → VulkanConv1x1Coop (CoopMat 只支持 int4/int8) └─ → VulkanConv1x1General (native int8/int4/int2/int3) else → VulkanConvolutionSlideWindowsInt8attention prefill 走 VulkanAttention.cpprearrange_q → init_state → (per k-block: qk → softmax → qkv) → finalizecoop QKV / subgroup softmax 由设备能力选路。每个onEncode决定本次 dispatch 哪些 shader把目标 shape 代入确认再改对应.comp。仓库中已存在attention_prefill_coop_qk.comp、attention_prefill_coop_qkv.comp、dynamic_w8a8_coop_gemm.comp等 coop 路径 shader见 source/backend/vulkan/buffer/execution/glsl。七、Shader 修改流程含防污染# 1) 编辑 .comp确认 buffer 还是 image 后端 vi source/backend/vulkan/buffer/execution/glsl/my_kernel.comp # 2) 新文件在 glsl/macro.json 登记 useFP16决定是否生成 _FP16 变体 # 3) 重新生成 SPIR-V 嵌入数组⚠️不要直接跑全量makeshader.py——本机 glslang/spirv-opt 与仓库版本不同会把所有 shader 数组重编/重排AllShader.cpp出现几万行无关 diff污染。正确做法是只重生成改动的那几个数组外科式替换进AllShader.cpp# 对每个改动的 shaderfp32 fp16 变体用与 makeshader 相同的管线单独编译 # header(FP32/FP16) body → glslangValidator -V [--target-env vulkan1.1(若含 coop/subgroup/memory_scope)] → spirv-opt -O → xxd -i # 得到 const unsigned char glsl_name_comp[]{...}; unsigned int glsl_name_comp_lenN; # 再用脚本精确替换 AllShader.cpp 里对应的那一段正则匹配数组头到 _len 行。 # 新增 shader 还要在 AllShader.hextern 声明 VulkanShaderMap.cppname→数组 map追加。改完确认grep -c glsl_name_comp_len AllShader.cpp且用git diff --stat确认只有目标数组变了。SPIR-V 合法性可用spirv-val验证。新加 kernel 同步检查清单.comp主路径 _nosubgroup变体都加 /macro.json登记 / host pipeline 选择分支 /AllShader.{cpp,h}VulkanShaderMap.cpp三处注册 / weight stride buffer size 重算 / dispatcher 显式选路或 fallback。八、正确性验证三层 Oracle三层 oracle数值层 dump tensor → op 层MNNV2Basic.out单层 → 端到端跑模型。端到端关 sampler 随机性temperature:0.0greedyCPU/Vulkan 同 prompt 前 N token 应一致fp16 误差内。CPU oracle 不可用时的兜底低 bit 路径 CPU 本身就乱用冻结 baseline 二进制做 GPU-baseline vs GPU-opt 的逐 token 贪心对比数学等价改动应完全一致。改 kernel 前先git stash存一份 baselinelibMNN.so。模型本身可能就坏小模型极低 bit 量化 CPU 跑也乱如 Qwen3-0.6B 的 w2/w3用 4B/8B 才是有效验证样本。Mac MoltenVK 行为不代表 Android最终验收必须 Android 真机。数值容忍fp16 vs fp16 abs1e-2量化 dequantfp16 abs1e-1。集成阶段的回归命令integrate.mdVulkan 的 forward type 为 7单测用adb -s serial shell cd /data/local/tmp/MNN LD_LIBRARY_PATH. ./run_test.out op/XxxTest 7 precision numThread全量 op 把op/XxxTest换成op/通过标准是all tests passed。九、性能测量Android 真机上的防噪声方法小收益最容易被噪声骗手机 GPU 有两个陷阱冷启动首跑不算数首跑含 auto-tune pipeline 编译。清了mnn_cachefile.bin后第一次也是冷的。先 warm 再测。跨时段热漂移 ~±8–10%设备温度随时间变先测完 base 再测 opt不可比。必须交替 A/B——base 和 opt 两份二进制或同一二进制不同 env背靠背配对base→opt→base→opt看每轮配对里 opt 是否稳定胜出而非比两组绝对值。换 shader 做 A/B 时每次切库 pipeline cache 会 stale每轮跑前rm tmp/mnn_cachefile.bintok/s 不含 load清 cache 只影响 load 时间A/B 仍公平。带MNN_GPU_TIME_PROFILEON的 build 只看相对占比放大绝对耗时且改变调度最终收益以不带 profile 的干净 build 的端到端 tok/s 为准。十、优化技巧速查与瓶颈分析方法论先做 roofline 分析计算强度AI FLOPs / Bytes与ridge_point peak_FLOPS / peak_BW比AI ridge→ memory-bound ridge→ compute-bound。典型GEMV(decode) memory-boundGEMM(prefill) 随 batch 增长elementwise/raster ≈ memory-bound。移动 GPU LPDDR 理论带宽打 6–8 折为实测可达。BW 利用率BW_util actual_bytes / kernel_time / peak_BW50% 访存模式/launch 有问题50–70% cache miss/WG 大小可调70% 只能减数据量packed 存储。occupancy 墙roofline 说 memory-bound 但减流量/减 ALU 都不涨 → 大概率是 occupancy 墙。Vulkan compute shader 的 occupancy 受寄存器和**共享内存shared数组**双重限制——本仓库 conv1x1 融合 epilogue 引入shared[64*64]8KB使大 N conv occupancy 下降、148ms。⚠️ Vulkan 第一诊断CPU 调度 vs GPU kernel这是 Vulkan 区别于 OpenCL/Metal 的最关键一步。MNN Vulkan 的 prefill 端到端常常受 CPU 侧命令录制/调度瓶颈而非 GPU kernel。实测数据AdrenoQwen3-0.6B514-token prefill阶段耗时占比GPU 计算~263ms60%命令录制op onResize/onEncode ×1129~63ms14% ← CPU 侧最大submit / 等待~52ms12%allocMemory 其余 geometry shape 真显存分配~47ms11%结论CPU 调度开销~187ms GPU kernel 中可优化的部分。判断方法用MNN_GPU_TIME_PROFILEON拿 GPU kernel 累计与干净 build 的端到端 wall 时间比——GPU 累计 ≈ wall → GPU-bound优化 kernel 有效GPU 累计 ≪ wall → CPU 调度 bound优化 kernel 无效改去攻调度。模型规模不同瓶颈会翻转小模型0.6BCPU-bound大 int4 模型4Bconv GPU 占比大反而 GPU-bound。技巧速查表摘自 optimization-handbook.md §5#技巧针对瓶颈适用场景难度收益参考1Cooperative matrix 重写 matmulcompute/访存GEMMAdreno coopK 维够大高QKV −47% kernel2Subgroup 归约替代 tree reduction归约 barriersoftmax/reduce支持 subgroup中softmax −38% kernel3Epilogue 合并写coalesced storememoryscatter 写NC4HW4/转置 epilogue 非合并中大 N conv 回收约一半 regression4融合 epilogueunpack/scale 折进 matmuldispatch temp 往返matmul 后紧跟独立逐元素 pass中小模型 prefill 8%5按输出规模门控融合 vs 分离occupancy融合用 shared、大 N 反伤中4B −6%→2.6%6push_constant 替代小 uniformCPU 命令录制uniform ≤128B 的 op低raster onResize −15~25%e2e 小7indirect batchRECORD_BATCHsubmit 命令录制多 op 推理低prefill 56%先分清 CPU 调度 vs GPU kernelCPU-bound 选 6/7 §6 候选GPU-bound 选 1–5。关键技巧要点Coop matrix 重写 matmul技巧 1用coopmat...coopMatLoad/coopMatMulAdd/coopMatStore替代 scalar 累加COOP_M/N/K 用设备selectedFP16CoopMatShapeAdreno 常 16×16×16 或 64×64×16经 spec constant 传入local_size_x subgroup size。coop matrix 只对 int8/int4 有硬件定义K 维太小时 shared staging 开销盖过收益headDim128 做 coop-QK 实测 e2e −3%负收益已弃。Subgroup 归约技巧 2一个 workgroup 一个 subgrouplocal_size_x_id0设为 subgroup size用subgroupMax/subgroupAdd替代shared 数组 barrier stride 折半的树形归约需#extension GL_KHR_shader_subgroup_arithmetic : require--target-env vulkan1.1host 按getSubgroupSize()动态设 local size别 hardcode。⚠️ softmax kernel −38% 但 prefill e2e 0%CPU-bound收益体现在散热/长文脉/大模型。Epilogue 合并写技巧 3让输出的连续维在相邻线程间最快变化。NC4HW4 输出[N/4, M, 4]epilogue 循环里让m idx % TILE_Mgm 最快而非m idx / n4PerTile——后者相邻线程写地址跨步Mtoken 数完全非合并。融合 epilogue技巧 4matmul 把 tile 存进sharedbarrier()后直接按目标布局写出含 bias/激活省掉写 temp → 独立 pass 读 temp的一次 dispatch。⚠️ 引入的sharedstaging会吃 occupancy——必须配合技巧 5 按规模门控。按规模门控技巧 5保留两条路径——小 N 走融合零 temp省 dispatch大 N 走分离matmul 写 row-major temp不用 shared → 高 occupancy 一个独立 unpack pass。阈值靠逐 conv dump 出真实 N 分布确定2B 最大 conv N6144 偏好融合、4B N9728 偏好分离阈值取 8192并做成 env 可调MNN_VK_CONV_FUSE_MAXN。push_constant技巧 6layout(bindingN) uniform→layout(push_constant) uniformhost 侧allocUniformwriteBuffer→vkCmdPushConstants。收益比预期小raster onResize 只降 15–25%因为vkAllocateDescriptorSets才是大头。indirect batch技巧 7开MNN_GPU_RECORD_BATCHScheduleConfig::mode位0x200让mDirectfalse——1000 个 op 打包到少数 command buffer segmentsubmit 从 ~1129 次降到少数次。LLM 里通过 configvulkan_record_batch: true开启。这是攻 CPU 瓶颈的最大单一杠杆。十一、常见陷阱速查#陷阱后果规避A全量 makeshader 污染 AllShader.cpp几万行无关 diff只外科式重生成改动数组B持久化 pipeline cache 换 shader 后 stale直接 segfault每轮rm tmp/mnn_cachefile.binCbuffer/image 编译期二选一改错树白改grep MNN_VULKAN_IMAGE CMakeCache.txtDcoop/subgroup shader 缺 target-env vulkan1.1spirv-opt 拒绝/静默回退手动重生成时必带--target-env vulkan1.1Edescriptor set 池化在 Adreno 反变慢decode −12%净负目标 driver 实测后再动Fattention GPU kernel 微优化对 prefill e2e 常无效e2e 0%动 kernel 前先确认 GPU-boundG跨 session 顺序测 A/B 被热漂移欺骗噪声当收益必须交替 A/BHcooperative matrix 只支持 int8/int4数值乱/driver crashdispatcher 显式 gatew2/w3 走 GeneralIshared 数组吃 occupancy大 N 净 148ms评估 occupancy大规模走无-shared 分离路径JCPU 侧大头是 vkAllocateDescriptorSets82%push_constant 只省小头攻 descriptor set 或跨 forward 复用命令Ksubgroup 与 nosubgroup 双 shader 必须同步老 Mali 挂或走错逻辑两个变体都改Lcoop 端数 tile 越界读靠 robustBufferAccess 兜底UB输出对但是 UBhost 侧把 workspace 的 M 维 padding 到 COOP_M 倍数M未扩展路径吃错 buffer 大小OOB 读到下个 op 数据搜所有以mIsInt4分流处同步加处理Ndriver OOM / 设备重启手机重启先小模型验通路崩了让设备恢复十二、Packed weight 设计与新特性集成Packed weight 设计§4新加 quant bit / 调 tile 排布时先固定 5 个量tile最小访问区块Vulkan conv1x1 常见行主[N, padK/W]每 word 装 W 个 weight/ word 内 weight 数w2:16, w4:8, w8:4 per uint32/ 多 word splitw3 用 lo2hi1 双 word[N, padK/16, 2]/ bit 顺序低 bit 先/ signed 存储。signed/unsigned 与 originOffset导出器写出的 alphab min offset_signed*scaleoriginOffset 已折进 bias。Vulkan int8 path 用bitfieldExtract(packedW,0,8)会 sign-extendsigned bytes 直接当 signed 解无需再减 offset这点和 OpenCL/Metal 从 unsigned 解不同。w3 split[N, padK/16, 2]uint pairspair[0] 低 16bit 装 16 个 2bitpair[1] 低 16bit 装 16 个 1bitdecodeq (low2(i*2))3 | ((hi1i)1)2减 4 得 signed[-4,3]。host buffer size 乘wordsPerGroup2shader 内 stride 也 ×2。方向 C新特性集成流程触发条件是用户说用这个 Vulkan 特性/coop matrix/subgroup 扩展并提供示例代码没提供示例时主动要求.comp host 或完整可运行 demo、特性说明、目标算子、目标平台、预期收益。集成步骤特性检测 → shader 适配用FLOAT宏、NC4HW4、spec constant、扩展 require 头部注释→ 外科式重生成 三处注册 → host 选路if (feature supported) 用新 pipeline else 原路径两条都 createSet 绑定→ 编译验证。Fallback 必须设计coop 目前一般 gate 在gpuType()ADRENO supportCoopMat。设备能力查询在VulkanDeviceruntime 目录中auto coop vkBn-getDevice().getCoopMatInfo(); // supportCoopMat, selectedFP16CoopMatShape const auto sg vkBn-getDevice().getSubgroupInfo(); // size, stages, ops uint32_t sgSize vkBn-getDevice().getSubgroupSize();新特性用 spec constantlayout(constant_idN)host 经getPipeline(name, types, localSize, spec)传入或 build 宏控制路径 runtime 检测 fallback。coop/subgroup shader 需--target-env vulkan1.1makeshader 已按扩展关键字判断。仓库中 coop 相关 host 实现可参考 VulkanConv1x1CoopA8.cpp、VulkanConv1x1CoopAFP16.cpp 与 VulkanAttention.cpp。十三、集成验证与经验沉淀优化进入 MNN 主体前必须完成全量回归run_test.out op/ 7 ...全过跨模型规模验证至少小模型 大模型各测一遍如 0.6B 4B确认没有一个规模退步代码质量审查shader 三处注册、subgroup/nosubgroup 双变体、occupancy 评估、fallback 完善、阈值 env 可调性能报告实测交替 A/B 数据不写预期。提交信息格式建议[Vulkan:Perf] Optimize Xxx (coalesce epilogue / gate fusion by N / ...) - 技术1 - 技术2 Performance: 0.6B x% / 2B x% / 4B x% prefill (Adreno, interleaved A/B) All op/ tests passedMNN 有 clang-format-diff pre-commit 钩子手写 .cpp/.hpp 被拦时用git clang-format HEAD只格式化改动行但不要让它重排 AllShader.cpp 的字节数组。沉淀经验完成一个较复杂的优化任务后重写算子、新技巧奏效、踩了非显而易见的坑、验证/排除了某方向把可复用的方法论回写到 optimization-handbook.md——它是 Vulkan kernel/访存/调度级技巧与陷阱的唯一来源新技巧进 §2 登记 §5 速查表新陷阱进 §3新瓶颈定位/测量方法论进 §1验证通过某候选方向从 §6 移入 §2实测排除某方向在 §6 标注已排除 原因。只写方法论不写单次任务流水账技巧编号是稳定 ID只追加不复用。某具体 shape/kernel 的一次性发现属于 agent memory不进手册。十四、候选优化方向尚未落地 / 部分已排除有依据但未在 MNN 落地实测或已实测排除想用先做 spike 验证候选 AfixResizeCache 跨 forward 复用命令——同 shape 的第二次 forward 整段跳过 resize/encode预期省整个_allocForTensor~59ms。风险中、收益结构性未落地。候选 B算子融合减 op 数——在 GeometryComputer 层合并 raster或 Vulkan 后端把连续 raster 打包成一个 dispatch。工作量大。候选 Cregion 合并——已排除LLM 场景实测 LLM raster 只有 1% 可合并max_run2省 ~0.4ms噪声内。候选 Ddescriptor set 池化——已排除Adrenodecode −12% 净负其它 driver 可重试。候选 Ecoop matrix 用于 QK——已排除headDim128K 维太小e2e −3%更大 headDim 可重试。结语MNN Vulkan 后端的性能优化是一个先分清 CPU/GPU 瓶颈 → 建立可对比基线 → 单点突破 → 交替 A/B 验证 → 集成回归 → 沉淀方法论的闭环。核心心法总结为三点改.comp必走外科式 makeshader 流程、真机交替 A/B 才是唯一可信的测量方式、先量化瓶颈再选优化杠杆。按本文工作流操作即可在 Adreno/Mali/Apple 多 vendor 真机上稳定推进 conv/gemm/attention 等算子的 kernel 与调度级优化。【免费下载链接】MNNMNN: A blazing-fast, lightweight inference engine battle-tested by Alibaba, powering high-performance on-device LLMs and Edge AI.项目地址: https://gitcode.com/GitHub_Trending/mn/MNN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →