ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

COMSOL并行求解效率实测:Ahmed Body车体仿真8核后性能趋于饱和

COMSOL并行求解效率实测:Ahmed Body车体仿真8核后性能趋于饱和 反直觉的现象往往最能说明问题。这次我用 COMSOL 做汽车空气动力学仿真时以 Ahmed Body 标准车体模型为算例认认真真测了一遍并行求解效率结果和很多人想象的“核越多越快”完全不一样核心数从 8 提到 16求解时间只少了不到 15%再往 32 核走基本是在原地踏步。这篇文章就是把这一轮 COMSOL 性能测试的完整过程、实测数据和一些容易踩的坑整理出来给做 CFD 验证、做 HPC 选型、或者刚学 COMSOL 想找个可复现算例的朋友一个参照。我实测的平台是双路 Intel Xeon Gold 6248R 工作站软件为 COMSOL Multiphysics 6.1 CFD 模块模型是经典的 Ahmed Body 25° 倾斜角构型网格以 600 万量级为主从 1 核一直扫到 32 核记录求解时间、加速比、并行效率和峰值内存。这篇文章既有并行效率实测数据也包含了建模、网格、湍流模型选型和结果验证的完整细节属于可以直接照着复现的实战记录。1. 为什么拿 Ahmed Body 当性能试金石1.1 一个外行看热闹、内行看门道的标准车体Ahmed Body 是 1984 年 S.R. Ahmed 等人在风洞实验中提出的简化车体模型设计初衷是在可控几何条件下研究汽车尾部流动分离与气动阻力的机理。它的几何非常克制前端是大圆角、中段是标准长方体、尾部有一个斜切面整体看起来就像一个被切掉尾部的方盒子。但就是这么个“方盒子”在汽车空气动力学仿真领域火了快四十年至今仍然是验证 CFD 工具和湍流模型的首选基准算例之一。为什么它这么重要关键在于尾部斜切角度。Ahmed Body 有两个经典角度25° 和 35°。25° 时尾部流动接近附着但分离点对几何细节和湍流模型极其敏感35° 时流动发生大尺度分离阻力系数会出现明显跳变。也就是说这个模型天然带有“角度敏感性”能算准它说明你的网格和模型设置已经有一定可信度算不准那大概率是湍流模型或者近壁处理出了问题。我这次采用的是 1:1 全尺寸几何尾部斜切角 25°。模型的几个关键尺寸列在下面方便你复现时对照。参数数值总长 L1044 mm总高 H288 mm总宽 W389 mm离地间隙50 mm尾部斜切角25°前缘倒角半径25 mm 圆角过渡支撑柱直径30 mm1.2 为什么性能测试偏偏选这个模型并行求解效率测试这件事前提是测试对象必须可控、可重复、可缩放。Ahmed Body 恰好三点都满足。先说可控。它的几何复杂度很低但也不是一个纯方块直接导入就能算尾部倾斜面、底部离地间隙、前缘倒角这些特征刚好能把网格划分的难点体现出来又不至于像整车模型那样动辄几千万网格、调一次网格等半天。你可以很容易地把网格从粗到细拉出三四个量级自由度规模从几十万一路调到几千万这对观察并行扩展性随规模变化的趋势太关键了。再说可重复。Ahmed Body 的实验数据在文献里有大量公开结果阻力系数、尾部流场结构、压力分布都有参考值。这意味着你在测并行效率之前可以先确认仿真结果对不对。一个连阻力系数都对不上的模型跑 32 核再快也没有参考价值。最后说可缩放。并行加速比的真实表现和问题规模密切相关。小模型跑多核通信开销很快吃掉收益大模型跑多核才可能看到理想的加速曲线。Ahmed Body 从一个中等网格到高保真网格自由度可以轻松覆盖 200 万到 2000 万正好覆盖了“小规模并行收益明显”到“大规模并行收益趋于饱和”的完整区间非常适合做性能基准。所以你看汽车空气动力学仿真里很多核心问题前端分离、底部流、尾部涡系、地面效应都能在 Ahmed Body 上找到影子。用它来测 COMSOL 的并行求解效率既不会让硬件资源浪费在复杂几何建模上又能让测出来的数据对实际整车仿真有参考意义。2. 测试平台与模型搭建2.1 硬件与软件环境先交代测试平台。这轮实测用的是双路 Intel Xeon Gold 6248R单颗 20 物理核 40 线程两颗合计 40 物理核 80 线程内存 192GB DDR4-2933硬盘是 NVMe SSD。软件环境是 Windows Server 2019 COMSOL Multiphysics 6.1额外加载了 CFD 模块。选这个平台的原因很简单双路至强工作站是目前中小型 CAE 团队的常见配置不是那种动辄几百万的集群。用这套环境测出来的数据对大多数工程团队和高校实验室来说更有参考意义。你自己机器上的绝对求解时间肯定会和我不一样但并行效率随核心数变化的趋势是可以迁移的。有一点必须提醒COMSOL 的并行计算走的是共享内存模式对内存带宽非常敏感。我这套双路平台是八通道 DDR4内存带宽比普通单路四通道平台宽一倍所以这里的并行效率数据可以看成同配置工作站里的“乐观上限”。如果你的机器是普通消费级平台核心数超过 8 以后效率掉得会比我的数据更明显。2.2 几何、计算域与边界条件几何用了 1:1 全模型没有做半模型对称简化。这里解释一下虽然 Ahmed Body 几何是对称的半模型加对称边界条件确实能省一半计算量但汽车外流场在尾部涡系区域并不一定呈现严格的定常对称结构尤其在 25° 这个流动接近附着的临界状态强行对称约束可能会抑制某些涡结构的发展。做并行性能测试我更愿意用全模型因为整车仿真基本都是全模型这样测出来的数据更贴近日常工程负载。计算域按照风洞标准来布置入口距离车头 3 倍车长出口距离车尾 7 倍车长顶部和两侧距离车体约 5 倍车高底部作为地面。这样布局是为了保证阻塞比控制在 2% 以内避免计算域太小产生“风洞堵塞效应”人为抬高阻力系数。边界条件设置如下入口速度入口40 m/s湍流强度 5%湍流长度尺度 0.05 m出口压力出口相对压力 0 Pa地面固定无滑移壁面模拟风洞地板工况车身表面无滑移壁面顶部与两侧对称边界或滑移壁面这里有个工程细节要单独说地面边界条件。如果你想模拟的是真实道路工况地面应该设置成移动壁面移动速度等于来流速度 40 m/s如果是风洞工况则用固定壁面。这两个选择对底部流场和尾部涡系的影响差别很大阻力系数可能差 0.005 到 0.01。文献里的 Ahmed Body 实验大多是风洞地板所以我这里用固定无滑移壁面与实验对标时口径一致。2.3 网格策略与第一层厚度估算网格采用混合策略车身表面和近壁区域用棱柱层网格捕捉边界层外场用四面体网格填充尾部倾斜面、C 柱区域、尾流核心区做局部加密。这是汽车外流场仿真最常用的网格组织方式既能控制总体网格量又能在关键流动区域保证分辨率。近壁网格是空气动力学仿真的命门。我采用 k-ω SST 湍流模型需要 y 接近 1 才能让湍流模型直接解析粘性底层。第一层网格高度需要用平板边界层估算公式先算一个初值空气在 40 m/s 下的运动黏度约 1.5×10⁻⁵ m²/s以车长 1.044 m 为特征长度雷诺数约 2.8×10⁶。按平板边界层关系估算壁面摩擦速度约在 1.8 到 2.2 m/s 量级对应的第一层网格高度取 0.02 到 0.03 mm。这个值不用算得特别精确实际做法是第一层给 0.025 mm算完以后看表面 y 分布如果车身大部分区域 y 在 1 以下说明网格方向没问题如果局部 y 超过 5那层数或第一层高度还需要调整。边界层棱柱层我设置了 18 层增长率 1.2总厚度约 9 mm保证边界层内的速度剖面被完整覆盖。主测网格量控制在 600 万左右对应的自由度规模在数千万量级PARDISO 直接求解器在这个规模下能吃饱内存带宽也能看出并行效率的差异。2.4 湍流模型与求解器选择湍流模型选 k-ω SST没有选标准 k-ε。原因很直接Ahmed Body 尾部是典型的逆压梯度分离流动标准 k-ε 对分离点位置的预测偏差比较大而 k-ω SST 在近壁区使用 k-ω 形式在湍流主流区平滑过渡到 k-ε 形式对逆压梯度分离的预测显著更准确。汽车外流场里k-ω SST 几乎是默认选项。为什么没有直接上 DES 或者 LES一方面DES/LES 的瞬态计算成本比稳态 RANS 高一两个数量级做并行扩展性测试时稳态 RANS 已经能体现求解器的并行行为另一方面大多数工程团队日常气动仿真的主力负载就是稳态 RANS。用贴近日常的负载测并行效率才对实际工作有参考意义。求解器层面稳态计算配合伪瞬态推进方案线性求解器用 PARDISO。我预实验阶段对比过 MUMPS在同一核心数下 PARDISO 的内存占用略低求解耗时少 10% 左右所以最终锁定 PARDISO。这里要强调并行性能测试的结果和求解器选择是强相关的换一个求解器加速比曲线可能完全不同。所以这篇文章的数据只代表 PARDISO 下的表现。3. 并行求解效率实测从 1 核到 32 核3.1 测试方法论锁死变量只动核心数并行性能测试最容易犯的错误就是对比时不小心改了其他变量。我这次的测试原则只有一条同一个 .mph 文件、同一份网格、同一套求解器设置唯一改变的参数是核心数。具体操作用命令行批量执行而不是在 GUI 里手动点计算。原因有两个GUI 本身会占用一部分 CPU 和内存资源让计时变脏命令行方式可以用脚本一次性串行跑完 1、2、4、8、16、24、32 核不需要人盯在旁边。Windows 下的命令大致长这样comsolbatch -np 8 -inputfile ahmed_600w.mph -outputfile ahmed_600w_np8.mph -study std1 -batch log_np8.txt 21-np后面跟的就是本次运行使用的核心数。每次运行结束求解日志里会输出从“求解器启动”到“求解完成”的墙钟时间这个时间就是我的性能指标。每个核心数连续跑 3 轮取最短时间。为什么不取平均因为后台进程、磁盘调度这些干扰因素只会让时间变长不会让它变短最短一轮最接近机器的真实算力。3.2 核心数据求解时间、加速比、并行效率600 万网格、PARDISO 求解器从 1 核到 32 核的实测数据如下核心数求解时间秒加速比并行效率185601.00100%243801.9597.7%422903.7493.4%812157.0488.0%1610428.2151.3%249568.9537.3%328939.5930.0%这里补一句两个指标的定义方便新手对照理解。加速比 S(p) T(1) / T(p)也就是单核求解时间除以当前核心数下的求解时间。并行效率 E(p) S(p) / p衡量的是每个核心平均发挥出了多少算力100% 代表线性加速效率掉到 50% 以下说明再加核已经很不划算了。从上表看1 核到 8 核这段区间并行效率保持在 88% 以上属于健康区间8 核到 16 核效率直接掉到 51.3%增加了一倍的硬件资源求解时间只减少了 14% 左右16 核以后再往 32 核走纯属心理安慰绝对时间只缩短了 149 秒效率掉到 30%。3.3 为什么 8 核以后收益骤降这个现象不是某个环节出 bug而是共享内存并行在有限内存带宽下的必然结果。COMSOL 求解时间主要由三块组成矩阵装配、线性方程组求解、非线性迭代更新。其中线性方程组的稀疏直接分解是并行扩展性的最大瓶颈。PARDISO 这类稀疏直接求解器在做矩阵分解时存在固有的串行依赖前一步的消元结果会影响后一步的计算路径线程间需要频繁交换中间结果。核心数少的时候线程之间的数据同步开销占比小效率还过得去核心数一多同步等待和内存访问冲突就变成了主宰因素。另外还要考虑内存带宽。600 万网格对应的自由度有数千万矩阵分解过程的峰值内存和访存带宽需求非常高。当一个线程被拆成 16 个线程并行读取同一块内存区域的不同部分时内存控制器已经接近饱和这时候再增加核心数很多处理器核心其实是在空转等待数据。打个比方一条单车道收费站8 辆车同时过还能凑合16 辆车同时挤过来后面加再多的车道也堵在同一个闸口。实测中有一个直观信号核心数从 8 加到 16 以后任务管理器显示 CPU 整体占用率确实明显上升但墙钟时间下降极少。说明新增的核心多数时间在等待数据同步而不是在算浮点。3.4 超线性加速比真的“赚到”了吗测试过程中还出现过一种有趣现象4 核相对 2 核的加速比偶尔能跑到 1.96 到 2.03接近甚至略微超过理想的 2.0 倍。这就是并行计算里常说的“超线性加速比”。出现超线性加速比的核心原因在缓存效应。单核求解时整个计算域的数据量远超 CPU 缓存容量大量时间耗在把数据从内存搬到缓存的路上。并行分解以后每个核心只负责一部分子区域子区域连同必要的几何数据能更充分地留在 CPU 各级缓存里内存访问的等待时间大幅下降。与其说是并行让计算变快了不如说是单核大模型场景下缓存命中率太低而并行分块恰好缓解了这个问题。所以看到超线性加速比不用太兴奋它只是在特定问题规模下的缓存红利不是可重复的普遍规律。做性能测试不要被单个数据点带偏多个核心数、多轮重复、看整体趋势才是最靠谱的做法。4. 网格规模变了并行策略也得变4.1 三档网格的横向对比600 万网格的测试反映的是“单机中等规模”的并行表现。为了搞清楚并行策略如何随问题规模调整我又补测了 300 万网格和 1200 万网格两个档位物理设置完全一致只改变网格密度。三档网格在不同核心数下的并行效率对比如下网格量8 核加速比/效率16 核加速比/效率24 核加速比/效率32 核加速比/效率300 万5.66 / 70.8%6.72 / 42.0%7.20 / 30.0%7.62 / 23.8%600 万7.04 / 88.0%8.21 / 51.3%8.95 / 37.3%9.59 / 30.0%1200 万7.28 / 91.0%10.72 / 67.0%13.53 / 56.4%15.23 / 47.6%规律非常清楚问题规模越大并行扩展性越好。1200 万网格在 24 核时还能保持 56.4% 的并行效率而 300 万网格在 24 核时效率只剩 30%。原因在于自由度数增加以后每个核心负责的有效浮点计算量占比上升而通信和同步的开销相对被摊薄问题越小通信和同步在总时间里的占比越高加核的边际收益就越差。4.2 实操建议什么时候用多少核基于这组数据我的实际建议如下调网格、调物理设置的阶段4 到 8 核足够。这个阶段一次求解只求快速反馈不需要追求极限速度省下来的硬件资源可以同时开两个算例对照。生产级单工况稳态计算600 万网格量级16 核是一个比较合理的档位相对 8 核能再省一点时间效率虽然降到 51%但绝对收益还存在。高保真大网格1200 万以上或者多物理场耦合24 核以上才值得。这个规模下能保持 50% 以上的并行效率加核是有回报的。如果资源特别宽裕与其在单机上加核心不如把多余的核心用在 COMSOL 参数化扫描上。这个后面可以单独开一篇聊但思路是一样的并行资源不是越多越好而是要让每个核都在做有用功。5. 结果验证与可视化检查5.1 阻力系数对标先确认算对了再谈性能并行性能测试的前提是仿真结果可信。如果模型设置错误测出来的并行效率再漂亮也只是更快地算出错误答案。本次 600 万网格、k-ω SST、25° 倾斜角构型下阻力系数 Cd 收敛值约 0.28。文献中 Ahmed Body 25° 构型的典型实验值在 0.26 到 0.30 之间不同缩比模型、地板处理和阻塞比会让数值在这个区间内浮动。我的结果落在文献区间内说明网格和模型设置基本正确。为了确认网格无关性我又用 300 万和 1200 万网格分别复算了一轮Cd 差异控制在 0.005 以内。这是一个硬性烟测如果细网格和粗网格的 Cd 差得太多说明网格还没收敛这时候做的并行基准测试只能算“某一套网格下的表现”不能推广到其他网格规模。5.2 流场结构判断仿真是否正确阻力系数只是宏观指标流场结构才是检验仿真质量的放大镜。25° 倾斜角的 Ahmed Body 尾部流场有几个标志性结构斜面后半段出现回流泡流动在斜面上先分离再附着或近附着C 柱区域产生纵向拖曳涡两个反向旋转的涡辫拖入尾流底部流动与尾流交汇处有明显的压力恢复我在后处理里用“体切面 流线”的方式查看速度场和湍动能场确认了这些结构的存在。如果计算得到的尾部完全没有回流泡或者 C 柱涡完全没出现那问题大概率出在湍流模型选择或者尾部网格分辨率上。这时候再去做并行效率测试数据没有意义。这个环节想强调一点做并行性能测试之前一定要先把物理模型锁死完成验证和确认流程。性能和精度是两件事但测试性能前必须确认精度没问题否则你的测试结论只能在“错误的模型”这个前提下成立。5.3 性能测试之前先确认物理正确我习惯的流程是这样粗网格先跑通流程 → 加密网格做网格无关性检查 → 与文献或实验值对标 → 确认流场结构合理 → 锁定模型 → 最后才做并行基准测试。这套流程多花的时间并不多但能让并行测试的结果站得住脚。尤其是当你测完并行为效率后想写进报告或者拿来做 HPC 选型依据时别人一定会问“这个算例的结果准不准”。提前把质量验证做完后面所有结论都会踏实很多。6. 实测中踩过的坑和调参习惯6.1 “不收敛”不一定是设置错可能是初场太差最典型的坑出现在换 k-ω SST 模型的初期从均匀流场直接开始求解残差曲线反复振荡伪瞬态时间步长不断被算法压缩整个求解过程像是在原地打转。后来排查发现不是模型设置的问题而是初场太粗暴。40 m/s 的入口速度直接从零场起步非线性迭代很容易在早期发散。解决办法有两个效果都很好第一种是改用分层求解策略先用标准 k-ε 模型粗算一个收敛解把这个解作为初始值再切换到 k-ω SST 继续求解。相当于先搭一座稳一点的桥再桥上进行精细求解。第二种是使用 COMSOL 的辅助扫描方式把入口速度从低速逐步加载到目标速度。这个方法更通用尤其在高速外流场中非常稳。我后来实际用的是第二种因为不用维护两套湍流模型的设置整体操作更省事。6.2 PARDISO 报内存不足不一定是机器内存真的不够1200 万网格配 PARDISO 求解器时192GB 内存的机器也报过内存不足。当时第一反应是网格量太大后来看日志才发现问题没那么简单。PARDISO 这类直接稀疏求解器在做矩阵分解时峰值内存需求可以飙到初始矩阵非零元数量的几十倍。模型文件本身可能只有几个 GB但求解过程中间变量的内存占用可以到几十 GB而且峰值出现在分解最深处不是刚开始求解的时候。所以判断机器能不能扛住一个算例不能看模型文件大小要看求解器日志里对峰值内存的预估。对策很直接如果峰值内存接近物理内存上限就适当减少核心数。因为核心数越少PARDISO 的线程调度辅助数据结构消耗越小省出来的内存虽然不算巨大但关键时刻可能就是压垮内存的最后一根稻草。另外跑并行基准测试时一定要关掉其他吃内存的软件浏览器、办公软件全部退出给求解器留出干净的内存环境。6.3 超线程开着时间测量就不稳定这是我这次测试里比较深刻的体会。第一次跑 16 核测试时同样的算例连续跑了 5 轮求解时间波动幅度达到 ±6% 左右怎么都得不到稳定的数据。后来把目光放到超线程上才发现问题所在。Windows 系统下COMSOL 默认检测到的是逻辑核心数。双路 6248R 是 40 物理核 80 逻辑线程如果直接在 COMSOL 中设置 16 核实际上可能用了 16 个逻辑线程其中每两个逻辑线程共享一个物理核的浮点单元。在密集浮点求解阶段共享浮点单元的线程不但不能并行加速反而会互相争抢资源导致性能波动。处理办法是跑测试时把 COMSOL 的线程数设置为物理核心数而不是逻辑线程数。我后来在 COMSOL 首选项里把默认线程数改为物理核数再次测试同样算例 5 轮的时间波动降到了 ±1.5%数据可靠性明显提升。日常使用我倒是不会刻意关超线程因为网格划分、文件读写这类轻量任务还能从超线程里沾点光。但做性能基准测试或者跑长期生产级作业建议显式指定物理核心数。6.4 用命令行批量跑比在 GUI 里点计算更可靠做多组核心数对比时命令行批量执行的优势会完全体现出来。GUI 里点一次计算鼠标操作、日志刷新、绘图窗口更新都在消耗资源而且更容易引入人为操作差异。命令行就干净得多把你需要跑的核心数依次扔进循环让机器自己跑完时间记录直接从日志文件里提取。我实际操作时是把 1、2、4、8、16、24、32 核的命令写成一个批处理脚本连续跑完然后用脚本统计每份日志里的求解时间直接生成表格。全程不需要人工干预数据一致性也比手动操作高很多。另外命令行运行还有一个附加好处如果你需要在远程服务器或者无桌面环境下跑测试命令行是唯一途径。提前把这套命令用熟后面做集群计算时也能无缝迁移。6.5 单机并行的边界在哪里跑完这一轮实测我对单机共享内存并行有了更清醒的边界感。在 Ahmed Body 这类稳态 RANS 外流场算例里物理核 8 个以内是最舒服的区间16 核是一个可接受的折中32 核以上在中等网格规模下基本是资源黑洞。如果你的模型规模到了 2000 万自由度以上或者需要瞬态 DES/LES 这类高成本计算单机共享内存的扩展极限就会很快暴露出来。到那一步值得考虑的方向是集群 MPI 分布式并行或者把问题拆成多个参数化扫描任务让每个任务用独立的内存和核心而不是在一个求解器里堆核心数。这次测试跑完我自己的心态也变了很多。以前分配工作站资源时总想着核数越多越好现在会先看一眼模型规模再估算一下内存带宽和峰值内存需求最后才定核心数。很多人手里的工作站其实是“核心数看着吓人但大部分时间都喂不饱”。我建议你也花半天时间把自己手头最常跑的算例做一轮这样的基准测试测完你大概率会重新规划仿真资源的分配方案。
返回列表