高性能计算-雅可比算法MPI通信优化(5)
雅可比算法原理:如下图对方阵非边界元素求上下左右元素的均值,全部计算元素的数值计算完成后更新矩阵,进行下一次迭代。


测试目标:用MPI实现对8*8方阵雅可比算法迭代并行计算,用重复非阻塞的通信方式
#include <stdio.h>
#include <mpi.h>
#include <unistd.h>
#define N 8 //方阵行列数
#define B 4 //并行进程数
#define S N/(B/2) //分块方阵的大小
#define BS S+1 //块包含交换数据的方阵大小
#define T 2 //迭代次数
//并行-重复非阻塞-4*4分块并行计算,共4个块,每个计算块包含其他块计算数据的块大小为 5*5
/*
优化:通信接口分步优化 MPI_Start
*/
void printRows(int pid,float rows[BS][BS])
{
printf("result in %d\n",pid);
for(int i=0;i<BS;i++)
{
for(int j=0;j<BS;j++)
printf("%.3f\t",rows[i][j]);
printf("\n");
}
}
void RequestStart(int count,MPI_Request arr_request[])
{
for(int i=0;i<count;i++)
MPI_Start(&arr_request[i]);
}
void RequestFree(int count,MPI_Request arr_request[])
{
for(int i=0;i<count;i++)
MPI_Request_free(&arr_request[i]);
}
int main(int argc,char* argv[])
{
float rows[BS][BS],rows2[BS][BS],temprows[S][S],temprows1[N][N],finalrows[N][N];
int pid;
int top=0,bottom=0,left=0,right=0; //标记每个block实际数据的边界
int ltBID=0,rtBID=1,lbBID=2,rbBID=3;//标记四个角落位置的进程
MPI_Status arr_status[BS]={0}; //
MPI_Request arr_requestS[BS] = {0}; //发送请求 第0个:行数据请求
MPI_Request arr_requestR[BS] = {0}; //接收请求 第0个:行数据请求
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&pid);
//初始化
for(int i=0; i<BS; i++)
{
for(int j=0; j<BS; j++)
{
rows[i][j] = 0.0;
rows2[i][j] = 0.0;
}
}
//有效数据边界初始化
if(ltBID==pid || rtBID==pid)
{
top = 0;
bottom = S-1;
}
else
{
top = 1;
bottom = S;
}
if(ltBID==pid || lbBID==pid)
{
left = 0;
right = S-1;
}
else
{
left = 1;
right = S;
}
//数据初始化
if(ltBID==pid || rtBID==pid)
{
for(int j=left;j<=right;j++)
rows[top][j] = 8.0;
}
else if(lbBID==pid || rbBID==pid)
{
for(int j=left;j<=right;j++)
rows[bottom][j] = 8.0;
}
if(ltBID==pid||lbBID==pid)
{
for(int i=top;i<=bottom;i++)
rows[i][left] = 8.0;
}
else if(rtBID==pid || rbBID==pid)
{
for(int i=top;i<=bottom;i++)
rows[i][right] = 8.0;
}
//建立通信连接
if(ltBID==pid)
{
MPI_Recv_init(&rows[S],S,MPI_FLOAT,pid+2,0,MPI_COMM_WORLD,&arr_requestR[0]);
for(int i=top,k=1;i<=bottom;i++,k++)
{
MPI_Recv_init(&rows[i][S],1,MPI_FLOAT,pid+1,0,MPI_COMM_WORLD,&arr_requestR[k]);
MPI_Send_init(&rows[i][S-1],1,MPI_FLOAT,pid+1,0,MPI_COMM_WORLD,&arr_requestS[k]);
}
MPI_Send_init(&rows[S-1],S,MPI_FLOAT,pid+2,0,MPI_COMM_WORLD,&arr_requestS[0]);
}
if(rtBID==pid)
{
MPI_Recv_init(&rows[S][1],S,MPI_FLOAT,pid+2,0,MPI_COMM_WORLD,&arr_requestR[0]);
for(int i=top,k=1;i<=bottom;i++,k++)
{
MPI_Recv_init(&rows[i],1,MPI_FLOAT,pid-1,0,MPI_COMM_WORLD,&arr_requestR[k]);
MPI_Send_init(&rows[i][1],1,MPI_FLOAT,pid-1,0,MPI_COMM_WORLD,&arr_requestS[k]);
}
MPI_Send_init(&rows[S-1][1],S,MPI_FLOAT,pid+2,0,MPI_COMM_WORLD,&arr_requestS[0]);
}
if(lbBID==pid)
{
MPI_Recv_init(&rows[0],S,MPI_FLOAT,pid-2,0,MPI_COMM_WORLD,&arr_requestR[0]);
for(int i=top,k=1;i<=bottom;i++,k++)
{
MPI_Recv_init(&rows[i][S],1,MPI_FLOAT,pid+1,0,MPI_COMM_WORLD,&arr_requestR[k]);
MPI_Send_init(&rows[i][S-1],1,MPI_FLOAT,pid+1,0,MPI_COMM_WORLD,&arr_requestS[k]);
}
MPI_Send_init(&rows[1],S,MPI_FLOAT,pid-2,0,MPI_COMM_WORLD,&arr_requestS[0]);
}
if(rbBID==pid)
{
MPI_Recv_init(&rows[0][1],S,MPI_FLOAT,pid-2,0,MPI_COMM_WORLD,&arr_requestR[0]);
for(int i=top,k=1;i<=bottom;i++,k++)
{
MPI_Recv_init(&rows[i],1,MPI_FLOAT,pid-1,0,MPI_COMM_WORLD,&arr_requestR[k]);
MPI_Send_init(&rows[i][1],1,MPI_FLOAT,pid-1,0,MPI_COMM_WORLD,&arr_requestS[k]);
}
MPI_Send_init(&rows[1][1],S,MPI_FLOAT,pid-2,0,MPI_COMM_WORLD,&arr_requestS[0]);
}
//块内需要计算数据的边界索引
int rbegin,rend; //块内起始 终止列号
int cbegin,cend; //块内列起始 终止列号
rbegin = 1;
rend = S-1;
cbegin = 1;
cend = S-1;
//迭代
for(int step=0; step<T; step++)
{
//每个进程都完成收发数据才能计算
RequestStart(BS,arr_requestR);
RequestStart(BS,arr_requestS);
MPI_Waitall(BS,arr_requestR,arr_status);
MPI_Waitall(BS,arr_requestS,arr_status);
//计算
for(int i=rbegin;i<=rend;i++)
{
for(int j=cbegin;j<=cend;j++)
rows2[i][j] =0.25*(rows[i-1][j]+rows[i][j-1]+rows[i][j+1]+rows[i+1][j]);
}
//更新
for(int i=rbegin;i<=rend;i++)
{
for(int j=cbegin;j<=cend;j++)
rows[i][j] = rows2[i][j];
}
}
//打印
sleep(pid);
printRows(pid,rows);
//Gather data from all processes
for(int i=top,m=0;i<=bottom;i++,m++)
{
for(int j=left,n=0;j<=right;j++,n++)
temprows[m][n] = rows[i][j];
}
MPI_Barrier(MPI_COMM_WORLD);
MPI_Gather(temprows,16,MPI_FLOAT,temprows1,16,MPI_FLOAT,0,MPI_COMM_WORLD);
//对数据重新整理
//遍历temprows1
int index=0;
for(int rb=0;rb<2;rb++)//块行索引
{
for(int cb=0;cb<2;cb++)//块列索引
{
for(int r=0;r<S;r++)
{
for(int c=0;c<S;c++)
{
finalrows[rb*S+r][cb*S+c] = *((float*)&temprows1+index++);
}
}
}
}
if(pid==0)
{
fprintf(stderr,"\nResult after gathering data:\n");
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j++)
fprintf(stderr,"%.3f\t", finalrows[i][j]);
fprintf(stderr,"\n");
}
fprintf(stderr,"\n");
}
RequestFree(BS,arr_requestR);
RequestFree(BS,arr_requestS);
MPI_Finalize();
return 0;
}
高性能计算-雅可比算法MPI通信优化(5)的更多相关文章
- SSE图像算法优化系列二:高斯模糊算法的全面优化过程分享(一)。
这里的高斯模糊采用的是论文<Recursive implementation of the Gaussian filter>里描述的递归算法. 仔细观察和理解上述公式,在forward过程 ...
- 小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化)--转载
小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化) 在上回<小波学习之一>中,已经详细介绍了Mallat算法C++实现,效果还可以,但也存在一些问题,比如,代码 ...
- Java 排序算法-冒泡排序及其优化
Java 排序算法-冒泡排序及其优化 什么是冒泡排序 基本写法 优化后写法 终极版本 源码及测试 什么是冒泡排序 这里引用一下百度百科上的定义: 冒泡排序(Bubble Sort),是一种计算机科学领 ...
- Parallel Computing–Cannon算法 (MPI 实现)
原理不解释,直接上代码 代码中被注释的源程序可用于打印中间结果,检查运算是否正确. #include "mpi.h" #include <math.h> #includ ...
- 图的最短路算法 Dijkstra及其优化
单源最短路径算法 时间复杂度O(N2) 优化后时间复杂度为O(MlogN)(M为图中的边数 所以对于稀疏图来说优化后更快) 不支持有负权的图 #include<iostream> usin ...
- KMP串匹配算法解析与优化
朴素串匹配算法说明 串匹配算法最常用的情形是从一篇文档中查找指定文本.需要查找的文本叫做模式串,需要从中查找模式串的串暂且叫做查找串吧. 为了更好理解KMP算法,我们先这样看待一下朴素匹配算法吧.朴素 ...
- 南理第八届校赛同步赛-F sequence//贪心算法&二分查找优化
题目大意:求一个序列中不严格单调递增的子序列的最小数目(子序列之间没有交叉). 这题证明贪心法可行的时候,可以发现和求最长递减子序列的长度是同一个方法,只是思考的角度不同,具体证明并不是很清楚,这里就 ...
- SSE图像算法优化系列十:简单的一个肤色检测算法的SSE优化。
在很多场合需要高效率的肤色检测代码,本人常用的一个C++版本的代码如下所示: void IM_GetRoughSkinRegion(unsigned char *Src, unsigned char ...
- 关于tarjan算法的空间优化
最近随着对tarjan算法理解的加深,我发现用另外一种途径实现tarjan的方法,且可以省去DFN数组,大大节省了空间.经过大量测试,已经无误.以下将分阶段阐述进行优化的过程. 第一阶段 下面来说一下 ...
- 【机器学习】支持向量机(SVM)的优化算法——序列最小优化算法(SMO)概述
SMO算法是一一种启发式算法,它的基本思路是如果所有变量的解的条件都满足最优化问题的KKT条件,那么这个最优化问题的解就得到了.因为KKT条件是该优化问题的充分必要条件. 整个SMO算法包括两个部分: ...
随机推荐
- Redis解读(5):Redis深入理解及生产高可用
Redis单线程如何处理高并发 1.阻塞IO 与 非阻塞 IO Java 在 JDK1.4 中引入 NIO,但是也有很多人在使用阻塞 IO,这两种 IO 有什么区别? 在阻塞模式下,如果你从数据流中读 ...
- centos上yum无法使用的问题以及无法用yum安装screen,iftop,nethogs等的解决办法
大家可能都发现了centos8已经不在更新了.当我们使用yum安装某些工具的时候,会提示安装源失败 解决方案:删除repo文件 然后重新下载即可修复yum安装报错问题1.进入/etc/yum.repo ...
- 【Docker学习系列】Docker学习2-docker设置阿里云镜像加速器
在上一篇中,我们学会了在centos中安装docer.我们知道,镜像都是外网的,镜像一般都是比较大的,因为种种原因,我们知道,从外网下载比较慢的.所以,本文,凯哥就介绍怎么将docker的镜像拉取设置 ...
- 【YashanDB数据库】数据库运行正常,日志出现大量错误metadata changed
问题现象 客户在麒麟kylin v10 sp1环境上部署YashanDB,运行正常, 但是在巡检中发现run.log中有大量错误日志文件metadata changed,需要排查原因 问题单:前置机大 ...
- 痞子衡嵌入式:在MDK开发环境下自定义安装与切换不同编译器版本的方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在MDK开发环境下自定义安装与切换不同编译器版本的方法. Keil MDK 想必是嵌入式开发者最熟悉的工具之一了,自 2005 年 Ar ...
- Angular – CLI
前言 一年半没有写 Angular 了. 现在又要开始写了. 复习过程中也顺便整理一下笔记呗. 介绍 CLI 是 Angular 的辅助工具. 输入一些 command 它会帮你 create 一些有 ...
- Azure Computer Vision 之 Smart Crop 智能裁剪图片
前言 一个网站通常有许多地方会用到同一张图,但是比例又不一样. 一般的做法就是用 CSS 的 cover 和 contain 来处理. 由于 cover 只会保留中间信息, 所以很多时候需要人工裁剪. ...
- 解密Prompt系列38.多Agent路由策略
常见的多智能体框架有几类,有智能体相互沟通配合一起完成任务的例如ChatDev,CAMEL等协作模式, 还有就是一个智能体负责一类任务,通过选择最合适的智能体来完成任务的路由模式,当然还有一些多智能体 ...
- 深入理解ConcurrentHashMap
HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进行put操作,调用了HashMap的putVal(),具体原因: 假设两个线程A.B都在进行put操作,并且hash函数计算 ...
- 智和信通搭建高可靠、真稳定IT运维平台,助力能源行业高效生产
在能源企业信息化高度发展的背景下,北京智和信通有限公司推出全栈式运维管控平台--"智和网管平台",助力能源企业搭建高可靠.真稳定的IT运维平台,实现高效稳定生产. 信息化飞速发展, ...