完成OpenCAEPoro

OpenCAEPoro的编译

可使用linux系统内火狐浏览器前往https://github.com/OpenCAEPlus/OpenCAEPoro_ASC2024将文件下载到家目录。开始按照文件的特殊顺序解压包。(如果没有解压zip文件的插件可以用以下代码)

git clone https://github.com/OpenCAEPlus/OpenCAEPoro_ASC2024

然后将下载好的压缩包进行解压操作

tar -xzf lapack-3.11.tar.gz
tar -xzf parmetis-4.0.3.tar.gz
tar -xzf hypre-2.28.0.tar.gz
tar -xzf petsc-3.19.3.tar.gz
tar -xzf petsc_solver.tar.gz
tar -xzf OpenCAEPoro.tar.gz

安装Lapack

进入lapack目录

cd lapack-3.11

编译lapack库

make blaslib
make cblaslib
make lapacklib
make lapackelib

查看文件状态

ls -lh *.a

所有库都编译完成

安装parmetis

进入parmetis目录

cd parmetis-4.0.3

readme中第二步为在脚本 build-parmetis.sh 中修改路径,在该脚本中找到并更改 make config 命令中的 prefix 参数,以指向正确的安装目录。

为了简化步骤,在此直接将ROOT_DIR添加至环境变量中

export ROOT_DIR=/home/pengziqiao/OpenCAEPoro_ASC2024

打开脚本文件进行修改

vim build-parmetis.sh

找到prefix那一行将/parmetis-4.0.3/parmetis-install前面的替换为ROOT_DIR(按i进入编辑模式,改完后esc退出编辑模式再:wq保存退出)

开始安装

sh build-parmetis.sh

出现报错,CMake 在尝试配置项目时找不到指定的 C 编译器 mpiicc 和 C++ 编译器 mpicxx

再仔细看一遍群里发的pdf,发现准备工作未完成,还未激活相关的套件。

source /opt/intel/oneapi/setvars.sh

在输入运行代码,编译完成。

安装hypre

进入 hypre-2.28.0目录

 cd hypre-2.28.0

同上,进入脚本中修改路径。

vim build-hypre.sh

找到configure一行,将prefix后hypre-2.28.0之前的内容替换为ROOT_DIR

输入安装程序

sh build-hypre.sh

检查是否编译完成

ls -R /home/pengziqiao/OpenCAEPoro_ASC2024/hypre-2.28.0/install

安装petsc

进入petsc-3.19.3目录

cd petsc-3.19.3

同上在脚本中进行修改。

vim build-petsc.sh

在输入以下代码

./configure CC=mpiicc CXX=mpiicpc \
        --with-fortran-bindings=0 \
        --with-hypre-dir=ROOT_DIR/hypre-2.28.0/install \
        --with-debugging=0 \
        COPTFLAGS="-O3" \
        CXXOPTFLAGS="-O3" \

参数含义:

CCCXX 分别设置为 mpiicc和 mpiicpc,这些通常是 MPI 编译器的名称。

--withfortran=0 选项,指示配置脚本不包含 Fortran 绑定。

--with-hypre-dir=ROOT_DIR/hypre-2.28.0/install \,制定安装路径

--with-debugging=0 选项指示编译过程不包含调试信息,这有助于生成更小、更快的二进制文件。

COPTFLAGSCXXOPTFLAGS 设置了 -O3 优化标志,这通常用于启用最高级别的编译优化。

make 命令并行编译一个项目,同时指定了 PETSC_DIRPETSC_ARCH 环境变量。

make -j 20 PETSC_DIR=$ROOT_DIR/petsc-3.19.3 PETSC_ARCH=arch-linux-c-opt all

make -j 20:这个命令告诉 make 工具同时运行多达 20 个并行作业。PETSC_DIR=$ROOT_DIR/petsc-3.19.3:这里你设置了 PETSC_DIR 环境变量,指向 PETSc。

PETSC_ARCH=arch-linux-c-opt:这里你设置了 PETSC_ARCH 环境变量,这通常用于指定 PETSc 的构建配置。

再测试一下是否工作正常。

​
make PETSC_DIR=/home/pengziqiao/OpenCAEPoro_ASC2024/petsc-3.19.3 PETSC_ARCH=arch-linux-c-opt all

​

输入执行脚本指令

sh build-petsc.sh  

编译完成

安装petsc_solver

进入petsc_solver目录

cd petsc_solver

修改build-petscsolver.sh文件中的路径为指定的ROOT_DIR

vim build-petscsolver.sh

修改CMakeLists.txt文件中的18和19行路径为/home/pengziqiao/OpenCAEPoro_ASC2024

执行安装指令

sh build-petscsolver.sh

安装OpenCAEPoro

进入OpenCAEPoro目录

cd OpenCAEPoro

在mpi-build-petsc.sh文件中修改路径为ROOT_DIR

运行mpi-build-petsc.sh文件

sh mpi-build-petsc.sh

测试安装

返回到OpenCAEPoro_ASC2024目录下,运行测试。

cd OpenCAEPoro
`mpirun -n p ./testOpenCAEPoro ./data/test/test.data`

其中p是并行运行的进程数,并且这个数字应该小于等于10.

mpirun -n 5 ./testOpenCAEPoro ./data/test/test.data

这里取p为5,得出结果。

测试完毕。

优化

改变进程数

针对case1进行优化,我们先看看case1的obejec time

mpirun -np 5 ./testOpenCAEPoro ./data/case1/case1.data verbose=1

再试试大一点的进程数10

​
mpirun -np 10
 ./testOpenCAEPoro ./data/case1/case1.data verbose=1

​

试试超过10如20

多机运行

为实现多机的并行运算,需要创建一个hostfile。

vim hostfile

然后列出所有参与计算的机器的IP地址和要在上面运行的进程数。

再输入运行指令,在原来代码基础上machinefile即可。(依然选取规定的最大值10)

cd OpenCAEPoro
mpirun -np 10 -machinefile /home/pengziqiao/OpenCAEPoro_ASC2024/hostfile ./testOpenCAEPoro ./data/case1/case1.data verbose=1

在多机运行的情况下甚至比单机运行的更慢,可能是由于MPI初始化。在MPI程序中,初始化MPI环境(MPI_Init)可能需要一定的时间,如果任务本身运行时间较短,这个初始化时间就可能占据了相当一部分的运行时间

总结一下规律就是进程数越大,能显著地缩减object time。多机运行并不一定比单机运行快。

vtune查看热点

然后再具体看看某一部分的耗时,用 intel 套件中的 vtune 来收集程序运行信息,获得程序运行的热点图,找到耗
时久的函数。

首先配置环境

source /opt/intel/oneapi/vtune/2024.0/vtune-vars.sh

再运行程序。

vtune -collect hotspots -result-dir=/home/pengziqiao/OpenCAEPoro_ASC2024/OpenCAEPoro/results /home/pengziqiao/OpenCAEPoro_ASC2024/OpenCAEPoro/testOpenCAEPoro

最后得到一个csv文件。

无法查看,根据报错可能是由于ssh连接到服务器但没开启X11转发

ssh -X pengziqiao@hostname
export PATH=$PATH:/opt/intel/oneapi/vtune/2024.0/bin64/vtune-gui
vtune-gui /home/pengziqiao/OpenCAEPoro_ASC2024/OpenCAEPoro/results_case1.gpu01/results_case1.gpu01.vtune

在src目录下进入vim,输入以下指令查找热点程序。

:vimgrep /dl_init/ **/*.cpp

图形化界面有bug,还是以命令行界面的为准。

vtune -collect hotspots -result-dir /path/to/vtune/results mpirun -np 10 ./testOpenCAEPoro ./data/case1/case1.data verbose=1
vtune -report hotspots -r /path/to/results.vtune

得到以下结果

性能数据显示,libpetsc.so.3.19:PETSc 库、libHYPRE-2.28.0.so:HYPRE 库消耗时间最长。

[Unknown]:表示性能分析工具无法识别或解析函数的名称。

先找到libpetsc文件的位置,可用以下指令。

grep -r "libpetsc.so.3.19.3"

发现不在修改范围内,尝试查询其他函数,也都不在范围内,没什么帮助。

输入输出的加速

默认情况下,C++ 标准库的 cin、cout与 C 的 scanf、printf是同步的。这意味着,每次进行 I/O 操作时,C++ 会等待 I/O 操作完成,这可能会降低性能,特别是在需要大量 I/O 操作的情况下。

std::ios::sync_with_stdio(false);
std::cin.tie(0); 
std::cout.tie(0);

我们查找OpenCAEPoro/src/* 中全部代码文件以及petsc_solver/src/PET SC_FIM_solver.cpp 中标明的可修改的代码段哪里有cin和cout,使用以下指令。

grep -r "std::cin" --include="*.cpp" /home/pengziqiao/OpenCAEPoro_ASC2024/OpenCAEPoro/src
grep -r "std::cout" --include="*.cpp" /home/pengziqiao/OpenCAEPoro_ASC2024/OpenCAEPoro/src

在 UtilMath.cpp 文件中,有一个注释行提到了 std::cout

在 UtilTiming.cpp 文件中,有三行代码使用了 std::cout 来输出信息,包括时间成本。

在 GmshGrid.cpp 文件中,有一行代码使用了 std::cout 来输出模型的维度信息。

同样在petsc_solver/src/PET SC_FIM_solver.cpp进行如上操作。

​
grep -r "std::cin" --include="*.cpp" /home/pengziqiao/OpenCAEPoro_ASC2024/OpenCAEPoro/src
grep -r "std::cout" --include="*.cpp" /home/pengziqiao/OpenCAEPoro_ASC2024/OpenCAEPoro/src

​

优化结果如下:

从结果来看只提升0.12%,可以当作误差了。

前人的经验分享

ASC24 OpenCAEPoro 齐鲁工业大学优化方案 | sethome的橱窗 个人博客

根据上面这位老哥的分享,可以知道OpenCAEPoro中的分区处理Partition.cpp文件使用线性搜索来查找send_buffer中的条目,极大地浪费了时间。将代码改为用哈希表来查找信息能极大地提高效率

    vector<vector<idx_t>>  send_buffer;
	vector<vector<idx_t>>& recv_buffer = elementCSR;
	recv_buffer.push_back(vector<idx_t> {myrank, 0, 0});

	unordered_map<idx_t, idx_t> ump_send_buffer;

	for (idx_t i = 0; i < numElementLocal; i++) {
		if (part[i] == myrank) {
			recv_buffer[0][1] ++;
			recv_buffer[0][2] += (xadj[i + 1] - xadj[i]);
		}
		else {
			// euphoria
			if(ump_send_buffer[part[i]]){
				idx_t k = ump_send_buffer[part[i]] - 1;
				send_buffer[k][1] ++;
				send_buffer[k][2] += (xadj[i + 1] - xadj[i]);
			}
			else{
				send_buffer.push_back(vector<idx_t>{part[i], 1, xadj[i + 1] - xadj[i]});
				ump_send_buffer[part[i]] = send_buffer.size();
			}

		}
	}

同样地将下面一处线性搜索的地方改为哈希表。

if(ump_send_buffer[part[i]]){
				idx_t s = ump_send_buffer[part[i]] - 1;
                              send_buffer[s][send_buffer_ptr[s * 4 + 0]++] = i + vtxdist[myrank];
                              send_buffer[s][send_buffer_ptr[s * 4 + 1]] = send_buffer[s][send_buffer_ptr[s * 4 + 1]++] + xadj[i + 1] - xadj[i];

                             copy(&adjncy[xadj[i]], &adjncy[xadj[i + 1]], &send_buffer[s][send_buffer_ptr[s * 4 + 2]]);
                             copy(&adjproc[xadj[i]], &adjproc[xadj[i + 1]], &send_buffer[s][send_buffer_ptr[s * 4 + 3]]);
                             send_buffer_ptr[s * 4 + 2] += xadj[i + 1] - xadj[i];
                             send_buffer_ptr[s * 4 + 3] += xadj[i + 1] - xadj[i];

			}

			}

结果不尽如人意,object time反而较于未优化时增加了。n

对比优化前后,assembling这一项明显增加了,有可能是冲突太多了,达不到O(1)的优化,退化为O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值