Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 工业软件 / Industrial Software

求解器工程 / Solver Engineering

1. 工业求解器工程:从物理方程到体系结构优化 / Industrial Solver Engineering from Physical Equations to Architecture Optimization

2. 生产级求解器架构:模块边界、执行管线与可观测性 / Production Solver Architecture with Module Boundaries, Pipelines, and Observability

3. 结构求解器设计:从单元积分到非线性、动力与接触 / Structural Solver Design from Element Integration to Contact and Dynamics

4. CFD 求解器设计:有限体积、压力速度耦合与并行时间推进 / CFD Solver Design with Finite Volumes and Pressure-Velocity Coupling

5. 求解器数据结构:稀疏矩阵、场布局、Cache、NUMA 与 Ghost 数据 / Solver Data Structures for Sparse Matrices, Fields, NUMA, and Ghost Data

6. CAE 性能分析:CPU、GPU、NUMA、MPI 与 I/O 工具链 / CAE Performance Analysis Across CPUs, GPUs, NUMA, MPI, and I/O

7. 体系结构驱动优化:从性能证据到算法、数据与并行处理 / Architecture-Driven Optimization from Evidence to Algorithms and Parallelism

8. 求解器优化案例:结构算子、CFD 通量与 MPI 强扩展 / Solver Optimization Cases for Structural Kernels, CFD Fluxes, and MPI Scaling

本页目录

体系结构驱动优化:从性能证据到算法、数据与并行处理 / Architecture-Driven Optimization from Evidence to Algorithms and Parallelism ​

📅 创建时间:2026-07-23
🏷️ 标签:#性能优化 #Roofline #CPU #GPU #MPI #数值算法
📚 前置知识:[[05-cae-performance-analysis]]
📚 相关知识:[[../marine-cae/12-serial-and-algorithmic-acceleration]] [[../marine-cae/13-parallel-acceleration-map]]


1. 优化优先级 ​

推荐顺序:

  1. 删除不必要的物理、网格、时间步和输出工作;
  2. 改善离散方法、求解算法和预条件器;
  3. 减少数据规模、拷贝和格式转换;
  4. 改善数据布局、局部性和任务粒度;
  5. 并行化主要热点并处理负载均衡;
  6. 重叠计算、通信和 I/O;
  7. 最后处理 SIMD、Kernel Fusion 和指令级细节。

这个顺序不是绝对规则,但能防止花大量时间优化只占总时间 2% 的循环。

2. 先区分两类慢 ​

单次迭代慢 ​

可能来自:

  • SpMV、组装或通量 Kernel 低效;
  • Cache、带宽、NUMA;
  • GPU 传输与同步;
  • MPI 通信;
  • I/O。

迭代次数多 ​

可能来自:

  • 条件数差;
  • 网格质量差;
  • 离散格式或变量尺度;
  • 预条件器不合适;
  • 非线性切线不一致;
  • 时间步、松弛或耦合策略。
text
总时间 = 迭代次数 × 单次迭代成本
1

只优化其中一项可能被另一项抵消。例如较便宜但更弱的预条件器可能让总时间反而增加。

3. 建立可证伪假设 ​

好的假设:

perf 和 PCM 显示 SpMV 已接近实际内存带宽,values、colIdx 和 x 读取占主导;将节点三自由度 CSR 改为 3×3 BSR 应减少索引字节并改善连续访问。

不好的假设:

GPU 应该更快,试着改成 CUDA。

每个假设要说明:

  • 证据;
  • 推测的体系结构机制;
  • 唯一主要修改;
  • 预期影响的指标;
  • 正确性风险;
  • 如果失败,怎样推翻假设。

4. CPU:IPC 低 ​

IPC 低可能意味着:

  • 等待内存;
  • 分支预测失败;
  • 指令前端供给不足;
  • 长延迟除法、开方或依赖链;
  • 锁和同步;
  • 运行频率或线程调度问题。

处理顺序:

  1. 用 Top-Down 或计数器区分前端、推测和后端;
  2. 若 Memory Bound,继续检查 Cache、DRAM 和 NUMA;
  3. 若 Branch Bound,检查边界/材料/单元类型混合;
  4. 若 Core Bound,检查向量化、指令组合和依赖;
  5. 若等待,检查锁、Barrier 和任务划分。

不能仅凭 IPC 低就重写算法。

5. CPU:Cache Miss 和间接访存 ​

常见于:

  • CSR 的 x[colIdx];
  • CFD owner/neighbour;
  • 有限元单元节点 Gather;
  • 接触邻居和搜索结构。

可能处理:

  • 网格和自由度重编号;
  • 按空间或分区分块;
  • 将单元、Face 按类型和拓扑分组;
  • 批量处理多个场,复用已加载邻居;
  • 压缩索引;
  • 软件预取,但必须测量;
  • 对只用一部分分量的循环改为 SoA。

重编号可能改善 Cache,却恶化 Fill-in 或 MPI 边界,因此要测端到端。

6. CPU:内存带宽饱和 ​

证据:

  • PCM/LIKWID 显示带宽接近平台实际峰值;
  • 增加线程后带宽不再增长,时间也不再下降;
  • FLOPS 很低但 CPU 利用率高;
  • Roofline 位于带宽斜线附近。

处理:

  • 减少索引和数值字节;
  • CSR 转 BSR/SELL;
  • 合并多个向量循环;
  • 避免临时数组和重复读写;
  • Matrix-Free 用计算换流量;
  • 降低精度,但必须验证;
  • 在算法层减少 SpMV 次数;
  • 使用更强预条件器减少迭代。

带宽饱和时继续增加线程通常只增加能耗。

7. CPU:分支和 SIMD ​

结构/CFD 中常见分支:

  • 单元或边界类型;
  • 材料状态;
  • 限制器;
  • 接触活动状态;
  • 湍流壁面处理。

处理:

  • 按类型分桶后调用专用 Kernel;
  • 将常量条件移出循环;
  • 使用 Mask 处理短分支;
  • 对固定小矩阵模板化;
  • 分离内部面和边界面;
  • 为常见路径提供快路径。

分桶会增加预处理和数据重排,适合重复迭代较多的算例。

8. CPU:False Sharing、锁与原子 ​

证据:

  • Threading Profiler 显示锁或原子时间高;
  • 增加线程后 Cache 一致性流量上升;
  • 图着色后扩展性显著变化;
  • 线程完成时间差异大。

处理:

  • 线程私有缓冲;
  • 分区所有权;
  • 图着色;
  • COO 生成后归并;
  • Padding 高频计数器;
  • 批量归约;
  • 减少细粒度任务和共享队列竞争。

原子并非一定慢。冲突概率低时,它可能比复杂着色更好。

9. NUMA ​

证据:

  • numastat 显示大量远端页;
  • 单 Socket 快,跨 Socket 扩展差;
  • 绑定后性能明显变化;
  • 内存带宽集中在一个 Socket。

处理:

  • 并行 First Touch;
  • 线程绑核;
  • 每 NUMA 节点一个 MPI Rank;
  • 数据按子域分配;
  • 避免主线程串行初始化大数组;
  • 将线程私有 Scratch 放在本地节点。

需要同时检查 MPI 通信增加是否抵消 NUMA 收益。

10. GPU:启动开销和小 Kernel ​

时间线出现大量短 Kernel 和空洞时:

  • 合并连续向量操作;
  • 批量处理多个单元、方程或边界;
  • 使用 CUDA Graph 减少重复启动开销;
  • 将收敛统计留在设备端;
  • 避免每个小阶段都同步主机;
  • 对多算例使用批处理。

融合过度会增加寄存器、降低 Occupancy,并让代码难维护。以端到端时间决定是否保留。

11. GPU:数据传输和驻留 ​

证据:

  • H2D/D2H 占比高;
  • 每次迭代都有相同数组拷贝;
  • GPU Kernel 快但总时间不快;
  • 隐式 Unified Memory 缺页。

处理:

  • 主迭代数据常驻设备;
  • 只在输出或 Checkpoint 时下载必要变量;
  • 使用异步拷贝和双缓冲;
  • 把预处理或结果恢复也迁到设备;
  • 缓存矩阵和预条件数据;
  • 用增量通信代替完整字段复制。

数据所有权必须清晰,避免 Host 和 Device 两份状态彼此覆盖。

12. GPU:访存、分支和原子 ​

不合并访存 ​

用 SoA、重排、连续 Face/Cell 分组和块格式改善。

分支发散 ​

按边界、材料、单元或活动状态分桶。检查分桶成本和批次大小。

原子冲突 ​

有限元组装或 Face 对 Cell 散射可尝试:

  • 图着色;
  • owner/neighbour 分阶段;
  • COO + sort/reduce;
  • Block 私有累加;
  • 改为 Gather 形式;
  • Matrix-Free。

归约 ​

Krylov 点积和残差范数需要归约。设备内使用分层归约,MPI 场景进一步考虑合并或流水化全局归约。

13. MPI:负载不均 ​

证据:

  • 最慢 Rank 与平均 Rank 差异大;
  • Barrier/Allreduce 中大量等待;
  • 单元数相近但物理工作量不同;
  • 接触、化学或湍流模型集中在少数分区。

处理:

  • 使用计算权重而不是只按单元数分区;
  • 动态或阶段性重分区;
  • 将接触面、粒子和源项计入权重;
  • 平衡 AMG 粗层;
  • 避免某个 Rank 独占串行服务;
  • 输出每 Rank 工作量直方图。

重分区有迁移成本,适合长时间、多步计算。

14. MPI:通信占比高 ​

小消息过多 ​

合并字段和邻居消息,复用通信计划,避免每个变量单独交换。

Halo 占主导 ​

增加每 Rank 工作量、改善分区表面积/体积比、使用高质量图分区,或停止继续强扩展。

全局归约多 ​

尝试:

  • 合并多个统计量;
  • Pipelined CG/GMRES;
  • Communication-Avoiding 算法;
  • 降低不必要的逐迭代全局日志;
  • 在允许时减少收敛检查频率。

算法变体可能改变稳定性和舍入行为,需要单独验证。

计算通信重叠 ​

text
启动 Irecv/Isend
→ 计算内部区域
→ 等待
→ 计算边界区域
1
2
3
4

只有内部工作时间足以覆盖通信,且 MPI 能异步推进时才有效。

15. 线性求解器与预条件器 ​

直接法 ​

优化方向:

  • 重排序减少 Fill-in;
  • 复用符号分析;
  • 多右端项复用数值因子;
  • 使用块结构;
  • 控制并行线程和 NUMA;
  • 估计内存后再选择算法。

Krylov ​

总成本:

text
迭代数 ×(SpMV + 预条件 + 向量操作 + 全局归约)
1

AMG ​

需要分开测:

  • Setup;
  • 每次 Apply;
  • 层数和粗网格大小;
  • 各层 SpMV、平滑和通信;
  • 迭代减少收益。

短算例中昂贵 Setup 可能不划算;长算例或多右端项中复用非常重要。

ILU/IC ​

天然存在三角依赖。并行方法包括 Level Scheduling、Block ILU、Additive Schwarz 和近似逆。更高并行度可能降低预条件质量。

16. 离散和模型层优化 ​

在硬件优化前检查:

  • 网格是否在不重要区域过密;
  • 是否能使用自适应网格;
  • 稳态问题是否错误地长时间瞬态推进;
  • 载荷或参数扫描是否能复用矩阵和预条件器;
  • 是否能用延续法改善非线性;
  • 多工况是否可并行;
  • 输出字段和频率是否必要;
  • 是否适合模态降阶、POD/ROM。

减少一个数量级自由度通常比微调 Kernel 更有效,但不能牺牲关键物理分辨率。

17. 混合精度 ​

可选策略:

  • Field 或几何量使用 float,累加使用 double;
  • 预条件器低精度,外层 Krylov 高精度;
  • 直接法低精度分解加迭代改进;
  • GPU Tensor/Core 混合精度用于规则块。

必须检查:

  • 条件数;
  • 残差是否停滞;
  • 守恒和平衡;
  • 非线性路径;
  • 不同规模和工况;
  • 并行归约误差。

混合精度是数值算法设计,不是简单替换类型。

18. I/O ​

证据:

  • 输出阶段占比高;
  • 大量小写;
  • 所有 Rank 争用同一文件;
  • Checkpoint 周期产生 I/O 峰值;
  • 元数据操作多。

处理:

  • 降低输出频率和变量数量;
  • 使用块写和压缩;
  • Parallel HDF5/ADIOS2/MPI-IO;
  • 集合缓冲或 I/O Rank;
  • 异步写出;
  • 将可重算派生量留到后处理;
  • 错开多个作业 Checkpoint。

压缩会增加 CPU 成本,需比较总时间和存储成本。

19. 观察、解释与下一步 ​

观察到什么说明什么下一步检查什么
迭代数异常高数值算法或问题条件优先于硬件优化网格、尺度、离散和预条件对比
SpMV 接近带宽上限单次算子受数据移动限制索引字节、块格式、融合和 Matrix-Free
LLC Miss 高邻接访问和工作集局部性较差重编号、分块、布局和复用
分支失败高热循环混合了不同执行路径类型分桶、快路径和 Mask 效率
跨 Socket 扩展差NUMA 页和线程映射可能不匹配First Touch、远端访问和 Rank 映射
GPU 时间线有大空洞同步、主机准备或粒度限制设备CUDA API、CPU 栈和 Kernel 批次
GPU 拷贝占比高数据未常驻或所有权不清晰传输内容、频率和异步流水
Rank 等待差异大负载或节点性能存在长尾加权分区、最慢 Rank 和 Straggler
Allreduce 占比高强扩展进入延迟与同步区归约次数、流水化算法和停止规模
输出占比高I/O 而非求解器 Kernel 主导字段/频率、并行 I/O 和异步化

20. 何时停止优化 ​

出现以下情况应考虑停止:

  • 热点已接近 Roofline 或平台实际带宽;
  • 优化对象占端到端时间很小;
  • 加速收益小于代码复杂度和维护成本;
  • 数值稳定性或可重复性风险增加;
  • 目标硬件即将变化;
  • 更大收益需要改变业务需求或物理模型;
  • 并行规模已超过合理强扩展点。

最终目标是更快、更稳、更便宜地得到可信工程结论,而不是追求某个指标的极值。

下一篇:[[07-solver-optimization-case-studies]]

最后更新于:

Pager
上一篇6. CAE 性能分析:CPU、GPU、NUMA、MPI 与 I/O 工具链 / CAE Performance Analysis Across CPUs, GPUs, NUMA, MPI, and I/O
下一篇8. 求解器优化案例:结构算子、CFD 通量与 MPI 强扩展 / Solver Optimization Cases for Structural Kernels, CFD Fluxes, and MPI Scaling

持续记录,持续成长

Copyright © Tidenflow