HPC 经典算例在鲲鹏平台的迁移与性能验证:以二维热传导模拟为例
1、背景与写作定位
背景
高性能计算(HPC)广泛应用于流体力学、气象模拟、热传导、材料科学等领域。这些应用通常具有以下特征:
- 大规模迭代计算
- stencil 访问模式(数据局部性强,但存在频繁内存访问)
- 对 CPU 核心数、缓存体系和内存带宽敏感
本文以“经典数值计算模型”为例,模拟 HPC 典型算例特征,并展示如何在鲲鹏平台进行迁移、并行化和性能验证。重点是可复现、易实现、可展示性能特性,而非工业级 CFD 模拟。
硬件与系统环境
- 服务器型号:华为鲲鹏
- CPU 架构:ARMv8 多核,单机 64 核
- 内存:64 GB DDR4
- 操作系统:openEuler 22.03 LTS
- MPI 实现:Hyper MPI
- Python 环境:Python 3.11, Numpy, Matplotlib
迁移过程
为了在鲲鹏 ARM 架构上运行经典二维热传导算例,需要对原始 x86 平台程序进行适配。
- MPI 实现替换
- 原始程序使用 OpenMPI 进行多进程通信。
- 鲲鹏平台推荐使用 Hyper MPI,接口兼容 MPI,因此源代码无需修改,但编译与运行命令需更换为 Hyper MPI。
- 编译器与数据类型适配
- 确保使用支持 ARM 架构的 GCC 编译器,例如 gcc 12.2。
- 检查浮点类型和数组对齐,避免由于架构差异造成数值精度偏差。
- 并行策略优化
- ARM 多核 CPU 的缓存和 NUMA 特性与 x86 不同,可通过调整线程绑定和 NUMA 分配优化性能。
- 保持网格划分逻辑不变,每个进程负责连续行,边界行通信仍通过 Hyper MPI 实现。
- 环境与依赖适配
- 安装 Python 及数值计算库(Numpy、Matplotlib)用于可视化。
- 配置 Hyper MPI 环境变量和库路径,确保程序可以正确链接 MPI 函数。
- 验证与调试
- 首先在小网格上进行正确性验证,确保温度场演化一致。
- 再逐步扩大网格和进程数,观察性能变化,验证并行扩展性。
2、HPC 经典应用的共性计算特征
在大多数 HPC 应用中,无论是 CFD、气象模拟还是结构力学仿真,都会遇到类似计算模式:
- 大规模迭代
- 数值方法如 Jacobi、Gauss-Seidel 或 Lattice Boltzmann 通常需要上千至上万次迭代,保证收敛。
- Stencil 访问模式
- 每个网格点的新值依赖于相邻网格点,如二维 5-point stencil 或 9-point stencil。
- 数据访问模式连续且局部,但需要频繁读取和写入内存。
- 高访存带宽需求
- 每次迭代计算都要访问整个网格,内存访问成为性能瓶颈。
- CPU 核心数和缓存体系对性能提升至关重要。
鲲鹏 CPU 在多核和 NUMA 架构上的优化特性,这使其能够在这种模式下充分发挥计算能力。
3、算例选择:二维热传导模拟
3.1 数学模型
选择二维热传导方程作为算例,数学模型为:
离散化后可用 Jacobi 迭代求解:
- u_{i,j}^{(k)}表示第 k 步迭代后网格(i,j) 的温度
- 边界条件固定,内部网格迭代更新
可视化
# =========================
# 参数设置
# =========================
Nx, Ny = 50, 50 # 网格大小
dx, dy = 1.0, 1.0 # 空间步长
alpha = 0.1 # 热扩散系数
dt = 0.1 # 时间步长
steps = 100 # 迭代步数
3.2 网格划分方式
- 二维网格:
Nx × Ny - 内存布局:行主序存储
- 并行划分:
- Hyper MPI:将网格按行分配给不同进程
- OpenMP:每个线程处理若干行
这种划分一定程度上保证了数据的局部性,可以减少通信和线程争用。
4、MPI 并行二维热传导示例
4.1 算例设计思路
二维热传导问题是 HPC 领域的经典负载之一,它的特点有下面几个:
- 计算密集:每个网格点的更新依赖邻近点,迭代次数多,计算量大
- 数据规模可控:可通过网格大小自由调整计算量
- 并行划分逻辑清晰:每行或每块区域独立计算,只需交换边界数据
在本示例中,我们选择使用 Jacobi 方法进行迭代,然后采用 MPI 对行进行划分,每个进程负责部分行的计算任务,同时通过边界行通信保证数据正确性。
4.2 MPI 程序实现说明
程序主体流程如下:
- 初始化 MPI 环境
- 获取进程总数与当前进程编号
- 按行划分网格,每个进程存储自己的行 + 上下各一行 halo
- 初始化边界条件
- 每步迭代前交换上下边界行
- 进行 Jacobi 更新
- 迭代完成后可选汇总到主进程
- 统计运行时间
这里不追求复杂物理模拟,而是重点验证并行逻辑正确性和性能变化趋势。
本文采用 Hyper MPI 替代 OpenMPI 以适配鲲鹏平台,但程序接口保持一致。
4.3 C/MPI 示例代码
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define Nx 128 // 网格行数
#define Ny 128 // 网格列数
#define STEPS 100 // 迭代次数
int main(int argc, char **argv) {int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int rows_per_proc = Nx / size;int start_row = rank * rows_per_proc;int end_row = (rank == size-1) ? Nx : start_row + rows_per_proc;
// 分配本地数组,含上下 halo 行
double **u = malloc((rows_per_proc+2)*sizeof(double*));double **u_new = malloc((rows_per_proc+2)*sizeof(double*));for(int i=0;i<rows_per_proc+2;i++){
u[i] = malloc(Ny*sizeof(double));
u_new[i] = malloc(Ny*sizeof(double));for(int j=0;j<Ny;j++){
u[i][j] = u_new[i][j] = 0.0;
}
}
// 设置全局边界
if(rank==0){for(int j=0;j<Ny;j++) u[1][j] = 100.0; // 顶边界
}if(rank==size-1){for(int j=0;j<Ny;j++) u[rows_per_proc][j] = 100.0; // 底边界
}
MPI_Barrier(MPI_COMM_WORLD);double t0 = MPI_Wtime();
for(int step=0; step<STEPS; step++){// 上下边界通信
if(rank>0)
MPI_Sendrecv(u[1], Ny, MPI_DOUBLE, rank-1, 0,
u[0], Ny, MPI_DOUBLE, rank-1, 1,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);if(rank<size-1)
MPI_Sendrecv(u[rows_per_proc], Ny, MPI_DOUBLE, rank+1, 1,
u[rows_per_proc+1], Ny, MPI_DOUBLE, rank+1, 0,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
// Jacobi 更新
for(int i=1;i<=rows_per_proc;i++)for(int j=1;j<Ny-1;j++)
u_new[i][j] = 0.25*(u[i+1][j]+u[i-1][j]+u[i][j+1]+u[i][j-1]);
// 指针交换
double **tmp = u; u = u_new; u_new = tmp;
}
MPI_Barrier(MPI_COMM_WORLD);double t1 = MPI_Wtime();
if(rank==0){
printf("MPI 2D Heat Conduction (%d x %d) Steps=%d\n", Nx, Ny, STEPS);
printf("Processes: %d, Time: %f seconds\n", size, t1-t0);
}
for(int i=0;i<rows_per_proc+2;i++){free(u[i]); free(u_new[i]);
}free(u); free(u_new);
MPI_Finalize();return 0;
}
4.4 运行
mpicc mpi_heat2d.c -O3 -o mpi_heat2d
mpirun -np 1 ./mpi_heat2d
mpirun -np 2 ./mpi_heat2d
mpirun -np 4 ./mpi_heat2d
mpirun -np 8 ./mpi_heat2d
- 调整
-np参数即可观察不同进程数下执行时间变化。 - 输出:
MPI 2D Heat Conduction (128 x 128) Steps=100 ``Processes: 4, Time: 0.123456 seconds
4.5 分析
- 随着进程数增加,总执行时间明显下降
- 在进程数较小时,加速比接近线性
- 当进程数增加到一定程度,通信开销会略微限制加速比增长
- 验证了鲲鹏平台在 MPI 并行计算下的良好扩展性
5、Python 可视化与性能验证
5.1 二维热力图演化
用 Python 展示温度场演化:
import numpy as np
import matplotlib.pyplot as plt
#这里我就不放我的真实数据了,请替换为你的真实数据
Nx, Ny = xNum1, yNum1
steps = 50
u = np.zeros((Nx, Ny))
u[0, :] = uNum1
u[-1, :] = uNum2
u[:, 0] = uNum3
u[:, -1] = uNum4
def jacobi(u, steps):
u_new = u.copy()for _ in range(steps):
u_new[1:-1,1:-1] = 0.25*(u[2:,1:-1]+u[:-2,1:-1]+u[1:-1,2:]+u[1:-1,:-2])
u = u_new.copy()return u
u_final = jacobi(u, steps)
plt.imshow(u_final, cmap='hot', origin='lower')
plt.colorbar(label='Temperature')
plt.title('2D Heat Conduction - Step {}'.format(steps))
plt.show()
图:二维温度场热力图,红色表示高温,黄色/蓝色表示低温。
5.2 迭代步数对比
- 可绘制不同迭代步数下温度场变化
- 对比 10、25、50 步,观察收敛趋势
steps_list = [10, 25, 50]
fig, axs = plt.subplots(1,3, figsize=(12,4))
for i, s in enumerate(steps_list):
u_tmp = jacobi(u, s)
im = axs[i].imshow(u_tmp, cmap='hot', origin='lower')
axs[i].set_title(f'Step {s}')
fig.colorbar(im, ax=axs.ravel().tolist(), shrink=0.7)
plt.show()
图:不同迭代步数温度场对比图。
5.3 性能曲线示例
在单机多核上测试 HyperMPI:
表格 还在加载中,请等待加载完成后再尝试复制
绘制性能曲线:
threads = [1,2,4,8]
times = [12.35,6.45,3.28,1.75]
speedup = [times[0]/t for t in times]
plt.figure(figsize=(6,4))
plt.plot(threads, times, marker='o', color='blue')
plt.xlabel("Threads")
plt.ylabel("Execution Time (s)")
plt.title("HyperMPI Heat Solver Performance")
plt.grid(True)
plt.show()
plt.figure(figsize=(6,4))
plt.plot(threads, speedup, marker='o', color='green')
plt.xlabel("Threads")
plt.ylabel("Speedup")
plt.title("HyperMPI Heat Solver Speedup")
plt.grid(True)
plt.show()
Hyper MPI 多线程执行时间曲线
随着线程数增加,总执行时间显著下降。线程数越多,计算任务分配越均衡,单线程瓶颈减小。图中蓝色曲线表示实际执行时间,数据点上方标注了具体数值,便于直观对比不同线程数下的性能。
图 2:Hyper MPI 多线程加速比曲线
加速比随线程数增加而上升,但在高线程数时增长趋缓,说明通信开销开始限制性能扩展。绿色曲线为实际加速比,红色虚线表示理想线性加速比,直观展示实际性能与理论极限的差距。
6、性能优化
- 网格规模变化
- 小网格(128×128)容易被缓存命中
- 大网格(512×512 或更大)受内存带宽限制明显
- 可以观察加速比随网格变化的下降趋势
- 线程/进程并行度变化
- 单机多线程对小网格效果有限,网格大时提升显著
- MPI 多进程适合分布式场景,线程+进程混合模式可进一步提升性能
- 缓存
- 热力图可直观显示温度场更新
- 边界通信开销可通过 MPI profiling 工具观察
小结:鲲鹏平台多核 CPU 能充分利用 stencil 算法的并行性,热传导算例可作为数值计算迁移示例。
7、总结
完成这一算例实践之后:
- 可复现 HPC 算法
- Jacobi 迭代模拟热传导问题,计算密集且访存密集
- 鲲鹏平台的适配能力
- ARM 架构多核 CPU 对迭代/Stencil 型算法性能良好
- HyperMPI 与 openMPI 均可顺利运行
- 性能验证可视化
- 热力图展示二维温度场演化
- 线程/进程加速比曲线验证多核利用率
对于想迁移经典 HPC 算例到 ARM / 鲲鹏平台的开发者,这篇文章提供了可直接复现的路径、Python 可视化工具和性能验证方法。
鲲鹏开发工具-学习开发资源-鲲鹏社区:
www.hikunpeng.com/developer?u…
全文完