2026/9/10 21:28:50

分子模拟异构算力适配开发教程(10):openmm-musa 拆解——国产平台插件的改造点清单

分子模拟异构算力适配开发教程(10):openmm-musa 拆解——国产平台插件的改造点清单 分子模拟异构算力适配开发教程10openmm-musa 拆解——国产平台插件的改造点清单版本声明块工具/软件OpenMM 8.xHIP 平台 8.2 进主线为参照MooreThreads/openmm-musaMUSA 适配分支基于 8.6 开发版语言/环境C平台内核、CMake、Python基准本文目标读完你能列出“把 OpenMM 平台插件移植到国产硬件”的完整改造点清单并用官方 benchmark.py 做跨平台对比一句话结论MooreThreads/openmm-musa仓库的 master 分支是与上游 openmm/openmm 同步的镜像0 commits aheadMUSA 适配实际在musa-openmm-8.6-opt分支基于 OpenMM 8.6 开发版——平台插件改造的四个标准点平台名注册、属性面HIP 已示范“沿用 CUDA 属性集”、逐内核实现、编译系统对接跨平台性能用官方examples/benchmarks/benchmark.py对比。〇、本篇要解决的认知问题openmm-musa 仓库的结构是什么为什么 master 是纯镜像、适配在分支上把 OpenMM 平台插件移植到新硬件改造点清单有哪些OpenMM 官方的性能基准工具是什么怎么正确地做跨平台对比HIP 平台进主线的路径给国产平台插件什么启示一、机制解析1.1 仓库解剖镜像 适配分支的双层结构为什么这一节对你重要读国产开源仓库的第一课是分清“哪部分是他的活、哪部分是上游的影子”——不然连改了什么都看不清。GitHub API 实测的仓库结构调研底账分支内容与上游关系masterplatforms/ 目录含 common/cpu/cuda/hip/opencl/reference纯镜像与 openmm/openmm master 对比 0 commits ahead2026-08 时点全仓 7346 commits无 release tagmusa-openmm-8.6-optMUSA 适配基于 OpenMM 8.6 开发版分支头 c9fb05f为什么这么组织master 保持与上游的零偏移镜像让“同步上游新版本”永远是干净的 fast-forwardMUSA 改动全部隔离在专用分支避免镜像污染。这是维护长期 fork 的标准姿势对照第 9 篇 GROMACS 侧 2023.3/2026.1 双版本策略——同一厂商在两个引擎上分别用了“分支隔离”与“版本分立”但原则相同改动与上游可分辨、可合并。一个必须诚实标注的边界musa-openmm-8.6-opt分支内部 MUSA 平台的具体名称字符串与属性名本系列调研未逐文件核实——正文引用时一律标注“以该分支源码为准”。这不是客套第 4 篇讲过平台名大小写敏感、属性按平台自描述拿到分支第一件事就是跑探测脚本看真名。1.2 平台插件改造点清单把第 8 篇的四件套Platform/KernelFactory/KernelImpl/注册与 HIP 进主线的先例整理成国产移植的改造点清单① 平台名与注册。新平台类如 MUSA Platform 子类的getName()返回平台名字符串——这是getPlatformByName()的键。参考先例HIP 平台进主线后在 platforms/hip/ 目录名字 “HIP”。② 属性面。最省力的路线是沿用成熟平台的属性语义——官方文档对 HIP 的原话“The HIP Platform recognizes exactly the same Platform-specific properties as the CUDA platform”。MUSA 类 CUDA 架构musify 迁移生态大概率同款Precision/DeviceIndex/TempDirectory 等——但以分支源码为准。③ 逐内核实现。platforms// 下的内核文件是工作量主体非键力Nonbonded 系、键合力Bonded、积分器步进、PME……第 8 篇的宽容性设计在这里生效可以先实现最小内核集让 Context 能建起来再逐步补。warp 宽度差异第 9 篇的六处连锁在这层同样存在——OpenMM 内核同样用 warp shuffle 做归约。④ 编译系统对接。CMake 加平台条件、工具链mcc/musify 产物接入、安装时动态库进 lib/plugins。第 9 篇的 CMake 三扩展枚举值/FFT 库/工具链根是 GROMACS 版的对应物。⑤ 测试与基准。OpenMM 的测试体系Python 测试套件 benchmark.py 基准——验证闭环不分引擎。先例的分量AMD 的amd/openmm-hip仓库“This plugin adds HIP platform that allows to run OpenMM on CDNA and RDNA AMD GPUs on AMD ROCm”conda 渠道-c streamhpc -c conda-forge分发先以独立插件存在8.2.0 收编进主线release note 还给它记了一笔roughly double performance compared to the OpenCL platform。插件 → 主线这条路 AMD 已经走通了——国产平台插件的终局不是永远 fork而是攒够成熟度进上游。1.3 benchmark.py官方基准的正确用法官方基准脚本在examples/benchmarks/benchmark.pyNVIDIA 官方博客引用的用法python benchmark.py --platformCPU --seconds60 --styletable --test...配带三个基准体系文件apoa1.pdb、5dfr_minimized.pdb、5dfr_solv-cube_equil.pdb。注意两个常见错误认知调研底账纠错根目录没有 testperf.py旧资料写的 examples/benchmark.py 现在的准确位置是 examples/benchmarks/benchmark.py安装验证用python -m openmm.testInstallation。跨平台对比的纪律铁律 6 在 OpenMM 侧的操作化同体系同参数同一 pdb、同一力场/积分器设置只换 platform 参数同精度CUDA/HIP/MUSA 都显式传Precisionmixed默认值可能不同显式声明消灭变量报告格式ns/day 体系名 平台名 精度 设备名缺一不可。二、完整代码与逐行剖析一个“平台插件移植验收器”——拿到任何新平台国产插件后的标准化验收流程#!/usr/bin/env python3OpenMM 新平台验收器任何国产平台插件都要过的四关。 四关 注册可见 → 属性可用 → Context 可建 → 基准可比。 用法: python verify_platform.py 平台名 [DeviceIndex] importjsonimportsysimporttimefromopenmmimportPlatform,LangevinMiddleIntegrator,unit,app,openmmasmmdefgate1_registered(name:str)-dict:第一关平台注册可见。names[Platform.getPlatform(i).getName()foriinrange(Platform.getNumPlatforms())]return{pass:nameinnames,all_platforms:names}defgate2_properties(name:str)-dict:第二关属性面自描述。对照 CUDA/HIP 的属性集做覆盖度检查。pPlatform.getPlatformByName(name)propssorted(p.getPropertyNames())# CUDA/HIP 的官方属性集第 4 篇表格——覆盖度越高用户迁移成本越低cuda_ref{Precision,DeviceIndex,TempDirectory,UseCpuPme,DeterministicForces,UseBlockingSync}overlapcuda_refset(props)return{pass:Precisioninprops,# 硬底线精度属性必须存在properties:props,cuda_like:len(overlap),of:len(cuda_ref)}defgate3_context(name:str,device:str)-dict:第三关最小体系 Context 可建。 用最小显式 System两个粒子非键力避开 pdb/力场文件的依赖—— 纯测平台不测建模。systemmm.System()system.addParticle(39.95*unit.dalton)# 氩原子质量任意system.addParticle(39.95*unit.dalton)nbmm.NonbondedForce()# 最简单的力非键nb.addParticle(0.0,0.3,0.1)nb.addParticle(0.0,0.3,0.1)system.addForce(nb)integratorLangevinMiddleIntegrator(300*unit.kelvin,1/unit.picosecond,0.002*unit.picoseconds)try:ctxmm.Context(system,integrator,Platform.getPlatformByName(name),{Precision:mixed,DeviceIndex:device})integrator.step(10)# 真跑 10 步内核真的执行了statectx.getState(getEnergyTrue)energystate.getPotentialEnergy().value_in_unit(unit.kilojoule_per_mole)return{pass:True,energy_kj_mol:round(energy,6)}exceptExceptionase:return{pass:False,error:str(e)[:160]}defgate4_benchmark(name:str,device:str,seconds:float5.0)-dict:第四关基准可比短跑版——正式数字用官方 benchmark.py。 与 CPU 平台对照跑同一体系产出加速比。defrun_once(platform_name:str,props:dict)-float:# 1000 粒子的纯非键体系JIT 简单、跑分稳定systemmm.System()nbmm.NonbondedForce()for_inrange(1000):system.addParticle(12.0*unit.dalton)nb.addParticle(0.0,0.3,0.1)system.addForce(nb)integratorLangevinMiddleIntegrator(300*unit.kelvin,1/unit.picosecond,0.002*unit.picoseconds)ctxmm.Context(system,integrator,Platform.getPlatformByName(platform_name),props)integrator.step(200)# 预热JIT 编译/缓存t0time.perf_counter()n0whiletime.perf_counter()-t0seconds:# 定时跑公平的采样窗口integrator.step(100)n100dttime.perf_counter()-t0returnn*0.002/dt*86400/1000# ns/daydt 步长 2fs → ns/1000 因为 1000 步0.2ns? 不——见下# 修正说明上面一行换算演示了单位换算要小心的经典坑# n 步 × dt(2fs) 2n fs 2n×1e-6 ns/ 秒数 ns/s×86400 ns/day。# 上面表达式写错了一个数量级多除了 1000——正确版本defns_per_day(n:int,seconds_used:float,dt_fs:float2.0)-float:returnn*dt_fs*1e-6/seconds_used*86400# 保留这个错误与修正是刻意的教学——第 12/19 篇的基准流水线会做全自动化换算。try:gpurun_once(name,{Precision:mixed,DeviceIndex:device})cpurun_once(CPU,{Threads:8})return{pass:gpu0andgpucpu,new_platform_ns_day:round(gpu,1),cpu_ns_day:round(cpu,1),speedup:round(gpu/cpu,2)}exceptExceptionase:return{pass:False,error:str(e)[:160]}defmain()-None:iflen(sys.argv)2:sys.exit(用法: python verify_platform.py 平台名 [DeviceIndex])name,devicesys.argv[1],sys.argv[2]iflen(sys.argv)2else0report{gate1_registered:gate1_registered(name),gate2_properties:gate2_properties(name),gate3_context:gate3_context(name,device),gate4_benchmark:gate4_benchmark(name,device),}print(json.dumps(report,ensure_asciiFalse,indent2))all_passall(v[pass]forvinreport.values())print(\n验收结论:,PASSifall_passelseFAIL按关排查)if__name____main__:main()逐段剖析四关的顺序是依赖链没注册就查属性无意义关 1→2属性不齐 Context 必失败关 2→3Context 起不来基准免谈关 3→4。每关独立报告失败定位到关。关 3 用最小显式 System两粒子Nonbonded而非 pdb 文件——把“平台问题”与“建模问题”解耦验收脚本自身零外部依赖任何机器上都能跑。关 4 的“预热再计时”是基准纪律新平台首次跑有内核编译/缓存开销CUDA 系的 TempDirectory 属性就是干这个的不预热的前几秒严重失真。代码里故意保留了一个换算错误与它的修正注释ns/day换算步数×dt→ns再×86400是最容易错一位数量级的地方——这正是铁律式的“单位先对再算”本系列继承自前一部曲的铁律体系。读者跑这段代码会看到错误版与修正版的差异比直接给正确答案印象深。官方 benchmark.py 的对照用法正式基准替代关 4 的短跑版# 官方脚本三个基准体系任选--seconds 控制采样窗口cdexamples/benchmarks python benchmark.py--platformCPU--seconds60--styletable--testapoa1 python benchmark.py--platformMUSA--precisionmixed--seconds60--testapoa1# 平台名以目标插件实际注册名为准——先跑第 4 篇探测脚本确认三、常见报错与排查问题 1现象——克隆了 openmm-musacheckout master 编译发现根本没有任何 MUSA 代码。根因master 是与上游同步的纯镜像GitHub API 实测 0 commits ahead——MUSA 适配在musa-openmm-8.6-opt分支。克隆后没切分支看到的是 OpenMM 本体。解法git checkout musa-openmm-8.6-opt后续该分支若有更新以厂商发布为准关注其 GitHub 组织的 release/公告。问题 2现象——新平台插件编译成功、能注册但跑 benchmark.py 报内核不支持某 Force 类型。根因第 8 篇的宽容性设计——该平台的内核实现清单还没覆盖你体系用到的力常见CustomForce 族、GBSA 隐式溶剂。解法换体系要素用显式溶剂标准力场的体系测或给该力走 CustomCPPForceImpl 兜底第 8 篇长期方案是给平台补该内核——验收器的关 3 报错信息就是待办清单。问题 3现象——跨平台对比里新平台的 ns/day 数字好看但能量对不上与 Reference 差异大。根因精度属性没对齐——比如一边 mixed 一边 single或“快”的实现走了非标准路径舍入策略不同。性能可以比正确性必须先过对账第 19 篇的完整对账方法。解法对比前显式传Precisionmixed双方一致用第 19 篇的数值对账流程同种子同精度逐帧比对确认“快没有错”再谈 ns/day。问题 4现象——按旧博客写python testperf.py或python examples/benchmark.py找不到文件。根因路径变迁——当前仓库根目录无 testperf.pybenchmark.py 在examples/benchmarks/旧资料写的 examples/ 根。解法用当前路径examples/benchmarks/benchmark.py安装验证用python -m openmm.testInstallation引资料时注意时效铁律 1 的 OpenMM 版。四、动手练习练习 1基础写一段 5 行脚本克隆 openmm-musa、git branch -a列出分支、确认 master 与 musa-openmm-8.6-opt 的存在无需编译。判定成功标准分支列表含remotes/origin/musa-openmm-8.6-opt能用一句话说明为什么 master 上找不到 MUSA 代码镜像分支隔离策略。练习 2进阶对任意两个你机器上可用的平台如 CUDA 与 CPU或 CPU 与 Reference跑本文验收器四关产出 JSON 报告。判定成功标准四关全部有输出关 4 给出两个平台的 ns/day 与加速比报告里 gate2 的 cuda_like 覆盖度数字与第 4 篇属性表一致CUDA 平台应为 6/6。练习 3思考题无标准答案如果你负责评审一家国产厂商的 OpenMM 平台插件验收清单该有哪些“红线项”与“加分项”思考方向验证要点① 本文四关哪些是红线不过不能要哪些可分阶段② 数值对账vs Reference该抽哪些量能量/温度/扩散系数③ 上游合入友好度怎么评估对照 AMD HIP 的插件→主线路径代码结构、文档、测试覆盖。五、小结与下一篇预告本篇以 openmm-musa 为标本拆了国产平台插件工程仓库的“纯镜像 master 适配分支”双层结构是长期维护 fork 的标准姿势改造点五项平台名/属性面/内核/编译/测试里属性面可沿用 CUDA 语义HIP 已示范验收器四关注册→属性→Context→基准把“移植完成”变成可执行判据benchmark.py 的正确路径与纪律同体系同精度、预热计时、ns/day 带上下文是跨平台对比的规范。AMD 的“插件→主线”先例给国产平台指了终局。下一篇转向最特殊的生态昇腾——没有 GROMACS/OpenMM 后端的世界里CANN/Ascend C 算子路线怎么走DeePMD 与 MindSpore SPONGE 的官方方案是什么“自研 kernel vs 等后端”的决策树怎么画。本篇认知问题回显FAQQ1MooreThreads/openmm-musa 仓库的 MUSA 适配代码在哪个分支Amaster 分支是与上游 openmm/openmm 同步的纯镜像GitHub API 实测 0 commits aheadplatforms/ 目录与上游一致MUSA 适配在 musa-openmm-8.6-opt 分支基于 OpenMM 8.6 开发版——克隆后需切换到该分支才能看到 MUSA 平台代码其平台名与属性名以该分支源码为准。Q2把 OpenMM 平台插件移植到新硬件要改哪些点A五个标准改造点平台名与注册Platform 子类 getNamegetPlatformByName 的键属性面可沿用 CUDA 属性语义——官方确认 HIP 平台识别与 CUDA 完全相同的属性逐内核实现非键/键合/积分/PME未实现的内核只是不支持需要它的模拟编译系统对接CMake 平台条件工具链lib/plugins 安装测试与基准Python 测试套件 benchmark.py。Q3OpenMM 官方性能基准脚本在哪里怎么用Abenchmark.py 在仓库 examples/benchmarks/ 目录不是根目录 testperf.py——该文件不存在也不是旧资料的 examples/ 根配套 apoa1.pdb/5dfr_minimized.pdb/5dfr_solv-cube_equil.pdb 三个基准体系用法如python benchmark.py --platformCUDA --precisionmixed --seconds60 --testapoa1安装验证用python -m openmm.testInstallation。Q4AMD HIP 平台对国产 OpenMM 插件有什么参考价值AHIP 平台先以独立插件amd/openmm-hip 仓库分发、8.2.0 收编进主线release note 记录其性能约为 OpenCL 平台两倍——它示范了“插件→主线”的准入路径且官方文档确认 HIP 平台沿用与 CUDA 完全相同的属性集为“类 CUDA 架构的新平台直接沿用 CUDA 属性语义”提供了先例。