# MPI-OpenMP混合并行矩阵乘法实验 ## 项目结构 ``` gemm/ ├── gemm_serial.cpp # 串行版本实现 ├── gemm_parallel.cpp # MPI-OpenMP混合并行版本 ├── xmake.lua # 构建配置文件 ├── run_experiments.sh # 自动化测试脚本 └── README.md # 本文件 ``` ## 编译说明 ### 使用xmake编译(推荐) ```bash cd /home/yly/dev/hpc-lab-code/work/gemm xmake build ``` 编译后的可执行文件位于: - `build/linux/x86_64/release/gemm_serial` - `build/linux/x86_64/release/gemm_parallel` ### 手动编译 ```bash # 串行版本 mpic++ -O3 -march=native gemm_serial.cpp -o gemm_serial # 并行版本 mpic++ -O3 -march=native -fopenmp gemm_parallel.cpp -o gemm_parallel -lm ``` ## 运行说明 ### 串行版本 ```bash ./build/linux/x86_64/release/gemm_serial M N K use-blas ``` 参数说明: - M: 左矩阵行数 - N: 左矩阵列数/右矩阵行数 - K: 右矩阵列数 - use-blas: 是否使用BLAS(0=不使用,1=使用,当前版本未实现) 示例: ```bash ./build/linux/x86_64/release/gemm_serial 1024 1024 1024 0 ``` ### 并行版本 ```bash mpirun -np <进程数> ./build/linux/x86_64/release/gemm_parallel M N K ``` 参数说明: - 进程数: MPI进程数量 - M, N, K: 矩阵维度 示例: ```bash # 使用4个MPI进程,矩阵大小2048x2048x2048 mpirun -np 4 ./build/linux/x86_64/release/gemm_parallel 2048 2048 2048 # 使用16个MPI进程,8个OpenMP线程 export OMP_NUM_THREADS=8 mpirun -np 16 ./build/linux/x86_64/release/gemm_parallel 4096 4096 4096 ``` ## 自动化测试 使用提供的脚本自动运行所有实验并收集数据: ```bash cd /home/yly/dev/hpc-lab-code/work/gemm ./run_experiments.sh ``` 脚本会自动: 1. 编译程序 2. 运行串行基准测试 3. 运行实验一:固定OpenMP线程数,改变MPI进程数 4. 运行实验二:同时改变MPI进程数和OpenMP线程数 5. 运行实验三:固定总处理器数,改变MPI/OpenMP组合 6. 保存所有结果到CSV文件 ## 实验设计 ### 实验一:MPI进程数扩展性 **目的**:研究在OpenMP线程数固定为1时,不同MPI进程数的性能表现 **变量**: - 固定:OpenMP线程数 = 1 - 改变:MPI进程数 = 1, 2, 4, 9, 16 - 测试:不同矩阵尺寸 512, 1024, 2048, 4096 **测量指标**: - 运行时间(ms) - 加速比 = T_serial / T_parallel - 效率 = 加速比 / MPI进程数 ### 实验二:MPI-OpenMP混合并行扩展性 **目的**:研究同时改变MPI进程数和OpenMP线程数时的性能表现 **变量**: - OpenMP线程数:1, 2, 4, 8 - MPI进程数:1, 2, 4, 9, 16 - 总处理器数 = MPI进程数 × OpenMP线程数 - 测试:不同矩阵尺寸 512, 1024, 2048, 4096 **测量指标**: - 运行时间(ms) - 加速比 = T_serial / T_parallel - 效率 = 加速比 / 总处理器数 ### 实验三:MPI/OpenMP组合优化 **目的**:在总处理器数固定的情况下,研究不同MPI/OpenMP组合对性能的影响 **变量**: - 固定:总处理器数 = 16 - 改变:MPI/OpenMP组合 - 1 MPI进程 × 16 OpenMP线程 - 2 MPI进程 × 8 OpenMP线程 - 4 MPI进程 × 4 OpenMP线程 - 8 MPI进程 × 2 OpenMP线程 - 16 MPI进程 × 1 OpenMP线程 - 测试:不同矩阵尺寸 512, 1024, 2048, 4096 **测量指标**: - 运行时间(ms) - 加速比 = T_serial / T_parallel - 效率 = 加速比 / 总处理器数 ## 数据处理与绘图 ### 输出文件格式 **串行结果** (`serial_results.csv`): ```csv M,N,K,Time_ms 512,512,512,123.45 1024,1024,1024,987.65 ... ``` **并行结果** (`experiment_results.csv`): ```csv Experiment,M,N,K,MPI_Processes,OpenMP_Threads,Time_ms,Speedup,Efficiency Exp1,512,512,512,1,1,120.34,1.0267,1.0267 Exp1,512,512,512,2,1,65.43,1.8873,0.9437 ... ``` ### 绘图建议 使用Python (matplotlib)、Excel或R进行绘图: #### 图1:实验一 - MPI进程数扩展性 - X轴:MPI进程数 - Y轴:加速比(左轴)、效率(右轴) - 不同线条:不同矩阵尺寸 - 预期:加速比随进程数增加,但效率可能下降 #### 图2:实验二 - 总处理器数扩展性 - X轴:总处理器数 - Y轴:加速比(左轴)、效率(右轴) - 不同线条:不同OpenMP线程数 - 预期:混合并行可能比纯MPI或纯OpenMP更高效 #### 图3:实验三 - MPI/OpenMP组合影响 - X轴:MPI进程数 - Y轴:效率 - 不同线条:不同矩阵尺寸 - 预期:存在最优的MPI/OpenMP组合 ### Python绘图示例 ```python import pandas as pd import matplotlib.pyplot as plt # 读取数据 df = pd.read_csv('experiment_results.csv') # 实验一:MPI扩展性 exp1 = df[df['Experiment'] == 'Exp1'] fig, ax1 = plt.subplots(figsize=(10, 6)) for size in exp1['M'].unique(): data = exp1[exp1['M'] == size] ax1.plot(data['MPI_Processes'], data['Speedup'], marker='o', label=f'{size}x{size}') ax1.set_xlabel('MPI进程数') ax1.set_ylabel('加速比') ax1.set_title('实验一:MPI进程数扩展性(OpenMP=1)') ax1.legend() ax1.grid(True) plt.savefig('exp1_speedup.png') plt.show() ``` ## 性能分析与优化 ### 预期性能瓶颈 1. **通信开销**:MPI通信在大规模并行时可能成为瓶颈 2. **负载不均衡**:带状分块可能导致某些进程工作量较大 3. **内存带宽**:矩阵乘法是内存密集型操作 4. **缓存利用率**:小矩阵可能无法充分利用缓存 ### 可能的优化方向 1. **优化分块策略**: - 使用二维块循环分块代替带状分块 - 考虑缓存友好的分块大小 2. **优化通信**: - 使用非阻塞通信重叠计算和通信 - 减少通信次数,增加每次通信的数据量 3. **优化计算**: - 使用SIMD指令(向量化) - 优化循环顺序以提高缓存命中率 - 考虑使用Strassen算法等快速矩阵乘法 4. **混合并行优化**: - 找到最优的MPI/OpenMP组合 - 考虑NUMA架构的亲和性 ## 实验报告要点 1. **实验环境**: - 硬件配置(CPU核心数、内存大小) - 软件环境(MPI版本、编译器版本) 2. **实验结果**: - 三个实验的数据表格 - 性能曲线图 - 加速比和效率分析 3. **结果分析**: - 不同并行策略的性能比较 - MPI进程数和OpenMP线程数的最优组合 - 矩阵规模对并行效率的影响 4. **优化方案**: - 识别性能瓶颈 - 提出优化策略 - 实施优化并对比效果 5. **结论**: - MPI-OpenMP混合并行的优势 - 最佳实践建议 - 进一步改进方向 ## 故障排除 ### 编译错误 如果遇到MPI相关错误: ```bash # 检查MPI是否安装 which mpic++ mpic++ --version # 检查OpenMP支持 echo | clang++ -x c++ - -fopenmp -E - > /dev/null ``` ### 运行时错误 如果遇到MPI运行错误: ```bash # 检查MPI进程数是否合理 # 确保系统有足够的资源 # 检查OpenMP线程数设置 echo $OMP_NUM_THREADS ``` ### 性能异常 如果性能不如预期: 1. 检查CPU频率是否正常(是否降频) 2. 关闭其他占用资源的程序 3. 检查系统负载 4. 确认编译优化选项已启用(-O3) ## 参考资料 - MPI教程:https://mpitutorial.com/ - OpenMP官方文档:https://www.openmp.org/ - 并行编程模式:https://patterns.eecs.berkeley.edu/