OpenCAEPoro优化(2)

前言:

首先有一点要注意:

修改代码时,要注意命名空间的冲突问题(主要是头文件中)

作者了解了相关这个项目的一些背景介绍;得到的主要信息是:这种大型程序一般都是优化的比较完善了,即使有优化空间,也很小了(不知道我们从github拉下来的是不是这样)

自上次发完 OpenCAEPoro优化(1)之后,作者使用vtune找出了程序热点图(发现并没有分析出什么有效信息),并整理了一下思路,打算对代码部分做出如下改动:

作者在此提供一个新思路(仅供参考哈):根据文件名称,推测出相应的.cpp文件的作用,并结合vtune分析其是不是执行主要功能的函数

一.更错

由于之前没有设置多机之间的免密通信,导致程序并没有真正在多机上跑

1.在gpu01上生成ssh密钥

运行下述命令

bash 复制代码
ssh-keygen -t rsa

2.将公钥复制到其他机器

在gpu01上输入如下命令并回车

bash 复制代码
ssh-copy-id gaohaixiao@gpu02

gpu03 gpu04 同理

3.测试免密登录

bash 复制代码
ssh gaohaixiao@gpu02

gpu03 gpu04 同理

4.使用SSH并行执行任务

可以通过循环来实现:

bash 复制代码
for i in {1..4}; do
    ssh gaohaixiao@gpu0$i 'mpirun -np 50 -machinefile ~/OpenCAEPoro_ASC2024/hostfile ./testOpenCAEPoro ./data/case1/case1.data verbose=1' &
done

二:对内存分配进行优化

这里以AllWells.cpp为例子

bash 复制代码
void AllWells::InputParam(const ParamWell& paramWell, const Domain& domain)
{
    OCP_FUNCNAME;

    // 预分配内存以提高性能
    solvents.reserve(paramWell.solSet.size());
    solvents.insert(solvents.end(), paramWell.solSet.begin(), paramWell.solSet.end());

    Psurf = paramWell.Psurf;
    Tsurf = paramWell.Tsurf;

    const auto& my_well = domain.GetWell();
    numWell = my_well.size();

    // 使用指针减少内存分配开销
    wells.reserve(numWell);
    for (USI w = 0; w < numWell; w++) {
        wells.push_back(paramWell.thermal ? new PeacemanWellT() : new PeacemanWellIsoT());
    }

    USI t = paramWell.criticalTime.size();
    vector<USI> wellOptTime;
    vector<WellOptPair> tmpOptParam;

    for (USI wdst = 0; wdst < numWell; wdst++) {
        const OCP_USI wsrc = my_well[wdst];
        const auto& wellSrc = paramWell.well[wsrc];

        // 使用引用避免多次访问
        auto* currentWell = wells[wdst];
        currentWell->name = wellSrc.name;
        currentWell->group = wellSrc.group;
        currentWell->depth = wellSrc.depth;
        currentWell->InputPerfo(wellSrc, domain, wsrc);
        currentWell->Psurf = Psurf;
        currentWell->Tsurf = Tsurf;
        currentWell->ifUseUnweight = wellSrc.ifUseUnweight;

        currentWell->optSet.resize(t);

        // 验证选项参数的数量
        const USI n0 = wellSrc.optParam.size();
        if (n0 == 0) {
            OCP_ABORT("NO Well Opt Param for -- " + wellSrc.name);
        }

        // 过滤重复的optParam.d
        tmpOptParam.clear();
        tmpOptParam.reserve(n0);
        for (USI i = 0; i < n0; i++) {
            if (i == 0 || wellSrc.optParam[i].d != wellSrc.optParam[i - 1].d) {
                tmpOptParam.push_back(wellSrc.optParam[i]);
            }
        }

        const USI n = tmpOptParam.size();
        wellOptTime.clear();
        wellOptTime.resize(n + 1);
        for (USI i = 0; i < n; i++) {
            wellOptTime[i] = tmpOptParam[i].d;
        }
        wellOptTime.back() = t;

        // 填充optSet
        for (USI i = 0; i < n; i++) {
            for (USI d = wellOptTime[i]; d < wellOptTime[i + 1]; d++) {
                currentWell->optSet[d] = WellOpt(tmpOptParam[i].opt);
            }
        }
    }
}

核心步骤:
减少内存分配次数:对于solvents的填充,使用insert方法而不是循环,这样可以减少多次调用push_back的开销

三.对循环进行优化

使用OpenMP

OpenMP 是一个用于支持多平台共享内存并行编程的 API,非常适合循环并行化

具体做法是在循环前加上下面这段代码,实现循环并行化

cpp 复制代码
// 使用 OpenMP 并行化循环
#pragma omp parallel for reduction(+:total)

四.优化结果

根据优化(1)中的经验,作者采用四机并行,52进程

结果如下:

可以看出,多机并行,优化循环,对内存分配进行优化是有效果的

相关推荐
叼烟扛炮20 分钟前
Linux 学习笔记(二十二):深入 Ext 文件系统(上)—— 磁盘、块与神秘的 inode
linux·笔记·学习
nlp研究牲20 分钟前
Linux 常用命令速查手册:英文全称、中文释义、巧记方法与实战示例
linux·运维·php
小张成长计划..25 分钟前
【Linux】28:封装线程,锁,条件变量,日志
linux
笨笨饿40 分钟前
# 59_CSDN博客自动写流程文章
linux·jvm·stm32·单片机·嵌入式硬件·mcu·51单片机
味悲43 分钟前
Nginx笔记
linux·运维·笔记·nginx
Escalating_xu1 小时前
【Linux 网络编程】传输层协议 UDP:从 8 字节首部到消息边界、缓冲区与 MTU
linux·网络·udp
Lucky_Turtle1 小时前
【Linux】ip命令,路由表相关配置
linux·运维·tcp/ip
dawnsky.liu1 小时前
在 RHEL 中使用 goose 实现主机运维
linux·运维·aiops
碧海银沙音频科技研究院2 小时前
基于炬芯ATS308X的BLE 无线方式离线日志传输导出功能实现
java·linux·服务器
kkkkkkkkkk_Z2 小时前
新手自学嵌入式 | 学习日记: Linux驱动进阶 —— Platform总线与I2C子系统实战
linux·运维·学习