#include <stdio.h>
#include <mpi.h>
#include <unistd.h>
#include <stdlib.h> #define S 4 //分块方阵的大小
#define RB 8 //行方向分块维数
#define B RB*RB //并行进程数
#define N S*RB //方阵行列数
#define BS S+2 //块包含交换数据的方阵大小
#define T 2 //迭代次数 //并行-重复非阻塞-笛卡尔64个进程块
/*
优化:通信接口分步优化 MPI_Start
要求:
1、仍然采取二维行列同时分块的方式,对数据进行区域分解。
2、使用笛卡尔虚拟拓扑的相关接口,进行二维进程网格阵列构建、邻居进程编号获取等操作。
3、使用64个进程,每个进程初始化一个二维子块,并负责该子块的Jacobi迭代计算。
4、使用重复非阻塞通信接口。
思路:使用虚拟进程和笛卡尔,每个进程都对上下左右块通信
*/
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 top=0,bottom=0,left=0,right=0; //标记每个block实际数据的边界
//int ltBID=0,rtBID=1,lbBID=2,rbBID=3;//标记四个角落位置的进程
MPI_Status arr_status[2+S*2]={0}; //
MPI_Request* arr_requestS = calloc(2+S*2,sizeof(MPI_Request)); //发送请求
MPI_Request* arr_requestR = calloc(2+S*2,sizeof(MPI_Request)); //接收请求
int dims[2]={N/S,N/S}; //8,8
int periods[2] = {0,0}; //每个维度中不定期
MPI_Comm cartcomm;
int pid; //当前进程ID
int size=0;
int coords[2] ={0}; //当前进程笛卡尔坐标
int nbrs[4] ={0}; //上下左右进程的id
enum DIR{UP,DOWN,LEFT,RIGHT}; MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&pid);
if(size == B)
{
MPI_Cart_create(MPI_COMM_WORLD,2,dims,periods,0,&cartcomm);
MPI_Cart_coords(cartcomm,pid,2,coords); //初始化
for(int i=0; i<BS; i++)
{
for(int j=0; j<BS; j++)
{
rows[i][j] = 0.0;
rows2[i][j] = 0.0;
}
}
//确定上下左右进程的id
MPI_Cart_shift(cartcomm,0,1,&nbrs[UP],&nbrs[DOWN]);
MPI_Cart_shift(cartcomm,1,1,&nbrs[LEFT],&nbrs[RIGHT]);
//有效数据边界初始化
if(pid%RB == 0)//left
{
for(int i=1;i<BS-1;i++)
rows[i][1] = 8.0;
}
if(pid%RB==RB-1)//right
{
for(int i=1;i<BS-1;i++)
rows[i][BS-2] = 8.0;
}
if(pid>=0 && pid<RB)//top
{
for(int i=1;i<BS-1;i++)
rows[1][i] = 8.0;
}
if(pid<B && pid>=B-RB)//bottom
{
for(int i=1;i<BS-1;i++)
rows[BS-2][i] = 8.0;
} //建立通信连接
for(int i=0;i<4;i++)
{
if(nbrs[i] == -1)
nbrs[i] = MPI_PROC_NULL;
}
//上下左右
MPI_Recv_init(&rows[0][1],S,MPI_FLOAT,nbrs[UP],0,cartcomm,&arr_requestR[0]);
MPI_Recv_init(&rows[BS-1][1],S,MPI_FLOAT,nbrs[DOWN],0,cartcomm,&arr_requestR[1]);
for(int i=1,k=2;i<BS-1;i++,k+=2)
{
MPI_Recv_init(&rows[i][0],1,MPI_FLOAT,nbrs[LEFT],0,cartcomm,&arr_requestR[k]);
MPI_Recv_init(&rows[i][BS-1],1,MPI_FLOAT,nbrs[RIGHT],0,cartcomm,&arr_requestR[k+1]);
} MPI_Send_init(&rows[1][1],S,MPI_FLOAT,nbrs[UP],0,cartcomm,&arr_requestS[0]);
MPI_Send_init(&rows[BS-2][1],S,MPI_FLOAT,nbrs[DOWN],0,cartcomm,&arr_requestS[1]);
for(int i=1,k=2;i<BS-1;i++,k+=2)
{
MPI_Send_init(&rows[i][1],1,MPI_FLOAT,nbrs[LEFT],0,cartcomm,&arr_requestS[k]);
MPI_Send_init(&rows[i][BS-2],1,MPI_FLOAT,nbrs[RIGHT],0,cartcomm,&arr_requestS[k+1]);
} //块内需要计算数据的边界索引
int rbegin,rend; //块内起始 终止列号
int cbegin,cend; //块内列起始 终止列号
rbegin = (pid>=0 && pid<RB)?2:1;
rend = (pid<B && pid>=B-RB)?BS-3:BS-2;
cbegin =(pid%RB == 0)?2:1;
cend = (pid%RB == RB-1)?BS-3:BS-2; //迭代
for(int step=0; step<T; step++)
{
//每个进程都完成收发数据才能计算
RequestStart(2+S*2,arr_requestR);
RequestStart(2+S*2,arr_requestS);
MPI_Waitall(2+S*2,arr_requestR,arr_status);
MPI_Waitall(2+S*2,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=1,m=0;i<BS-1;i++,m++)
{
for(int j=1,n=0;j<BS-1;j++,n++)
temprows[m][n] = rows[i][j];
}
MPI_Barrier(MPI_COMM_WORLD);
MPI_Gather(temprows,S*S,MPI_FLOAT,temprows1,S*S,MPI_FLOAT,0,MPI_COMM_WORLD); //对数据重新整理
//遍历temprows1
int index=0;
for(int rb=0;rb<RB;rb++)//块行索引
{
for(int cb=0;cb<RB;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(2+S*2,arr_requestR);
RequestFree(2+S*2,arr_requestS);
}
else if(pid==0)
{
printf("parameter:should -n %d\n",B);
}
free(arr_requestS);
free(arr_requestR);
MPI_Finalize();
return 0;
}

高性能计算-雅可比算法-MPI重复非阻塞优化(7)的更多相关文章

  1. 【MPI学习4】MPI并行程序设计模式:非阻塞通信MPI程序设计

    这一章讲了MPI非阻塞通信的原理和一些函数接口,最后再用非阻塞通信方式实现Jacobi迭代,记录学习中的一些知识. (1)阻塞通信与非阻塞通信 阻塞通信调用时,整个程序只能执行通信相关的内容,而无法执 ...

  2. Java锁与非阻塞算法的性能比较与分析+原子变量类的应用

    15.原子变量与非阻塞同步机制 在java.util.concurrent包中的许多类,比如Semaphore和ConcurrentLinkedQueue,都提供了比使用Synchronized更好的 ...

  3. java并发之非阻塞算法介绍

    在并发上下文中,非阻塞算法是一种允许线程在阻塞其他线程的情况下访问共享状态的算法.在绝大多数项目中,在算法中如果一个线程的挂起没有导致其它的线程挂起,我们就说这个算法是非阻塞的. 为了更好的理解阻塞算 ...

  4. 《Java并发编程实战》笔记-非阻塞算法

    如果在某种算法中,一个线程的失败或挂起不会导致其他线程也失败和挂起,那么这种算法就被称为非阻塞算法.如果在算法的每个步骤中都存在某个线程能够执行下去,那么这种算法也被称为无锁(Lock-Free)算法 ...

  5. 29、Java并发性和多线程-非阻塞算法

    以下内容转自http://ifeve.com/non-blocking-algorithms/: 在并发上下文中,非阻塞算法是一种允许线程在阻塞其他线程的情况下访问共享状态的算法.在绝大多数项目中,在 ...

  6. java并发编程(8)原子变量和非阻塞的同步机制

    原子变量和非阻塞的同步机制 一.锁的劣势 1.在多线程下:锁的挂起和恢复等过程存在着很大的开销(及时现代的jvm会判断何时使用挂起,何时自旋等待) 2.volatile:轻量级别的同步机制,但是不能用 ...

  7. 非阻塞同步机制与CAS操作

    锁的劣势 Java在JDK1.5之前都是靠synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程 持有守护变量的锁,都采用独占的方式来访问这些 ...

  8. Java并发编程实战 第15章 原子变量和非阻塞同步机制

    非阻塞的同步机制 简单的说,那就是又要实现同步,又不使用锁. 与基于锁的方案相比,非阻塞算法的实现要麻烦的多,但是它的可伸缩性和活跃性上拥有巨大的优势. 实现非阻塞算法的常见方法就是使用volatil ...

  9. 非阻塞同步算法与CAS(Compare and Swap)无锁算法

    锁(lock)的代价 锁是用来做并发最简单的方式,当然其代价也是最高的.内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的上下文切换和调度延时,等待锁的线程会被挂起直至锁释放. ...

  10. 【Java并发编程】9、非阻塞同步算法与CAS(Compare and Swap)无锁算法

    转自:http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral 锁(lock)的代价 ...

随机推荐

  1. 网站由http升级为https图文教程

    网站由http升级为https图文教程 本文是基于凯哥个人网站由http升级为https的记录. 前提说明:凯哥网站在AliYun备案的.所以基于此创建的.如果是腾讯云备案的域名也是类似的. 名词解释 ...

  2. Error:java: JDK isn't specified for module

    报错: Error:java: JDK isn't specified for module 背景: 删除原项目文件夹内所有文件,copy的新的配置文件与src文件夹等,期间打开该项目的IDEA一直处 ...

  3. RuleLinKClient - 再也不担心表达引擎宕机了

    原来有这么多时间 六月的那么一天,天气比以往时候都更凉爽,媳妇边收拾桌子,边漫不经心的对我说:你最近好像都没怎么阅读了. 正刷着新闻我,如同被一记响亮的晴空霹雳击中一般,不知所措.是了,最近几月诸事凑 ...

  4. 【论文解读】transformer小目标检测综述

    一.简要介绍       Transformer在计算机视觉领域迅速普及,特别是在目标识别和检测领域.在检查最先进的目标检测方法的结果时,我们注意到,在几乎每个视频或图像数据集中,transforme ...

  5. Git Bash OpenSSL – Generate Self Signed Certificate

    前言 以前就写过了, 只是写的太乱, 这篇是一个整理版. 以前的文章: Git Bash 创建证书 PowerShell 创建证书 我已经没有用 PowerSheel 做证书了, 所以就不介绍了. 参 ...

  6. SQL Server – Temporal Table 时态表

    前言 之前写过一篇, 但那个时候还没有开始用, 现在是要用了, 所以翻新一下呗. SQL server temporal table 学习笔记 主要参考: 官网 Temporal tables [译] ...

  7. MonoDevelop 的续集dotdevelop

    DotDevelop 是一个跨平台的 .NET 集成开发环境(IDE),它原本是 MonoDevelop 的分支项目,这个项目更侧重于 Linux 支持和 GTK3 升级,github:https:/ ...

  8. 报名开启|和你约定在 "Google 应用出海指南针"

    Google 谷歌发布的<2021 移动应用全球化指南>报告中提到,在移动互联网高度渗透的当下,全球用户迸发出来的广泛需求为中国新生代创业者带来了巨大的历史机遇.过去十年,依托于技术和人才 ...

  9. 离线安装Redis

    redis 直接去官网下载tar包就可以 主要是gcc 环境的安装包不太好找,我下载的还缺少 make 如果服务器比较干净,还得预装一下lrzsz-0.12.20.tar.gz 上传下载文件,unzi ...

  10. spring上 -基于Xml配置bean笔记

    4,Spring 内容 7,快速入门 需求:通过 Spring 的方式[配置文件], 获取 JavaBean: Monster 的对象, 并给该的对象属性赋值, 输出该对象信息. 代码结构: lib ...