高性能计算-雅可比算法-MPI重复非阻塞优化(7)
#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)的更多相关文章
- 【MPI学习4】MPI并行程序设计模式:非阻塞通信MPI程序设计
这一章讲了MPI非阻塞通信的原理和一些函数接口,最后再用非阻塞通信方式实现Jacobi迭代,记录学习中的一些知识. (1)阻塞通信与非阻塞通信 阻塞通信调用时,整个程序只能执行通信相关的内容,而无法执 ...
- Java锁与非阻塞算法的性能比较与分析+原子变量类的应用
15.原子变量与非阻塞同步机制 在java.util.concurrent包中的许多类,比如Semaphore和ConcurrentLinkedQueue,都提供了比使用Synchronized更好的 ...
- java并发之非阻塞算法介绍
在并发上下文中,非阻塞算法是一种允许线程在阻塞其他线程的情况下访问共享状态的算法.在绝大多数项目中,在算法中如果一个线程的挂起没有导致其它的线程挂起,我们就说这个算法是非阻塞的. 为了更好的理解阻塞算 ...
- 《Java并发编程实战》笔记-非阻塞算法
如果在某种算法中,一个线程的失败或挂起不会导致其他线程也失败和挂起,那么这种算法就被称为非阻塞算法.如果在算法的每个步骤中都存在某个线程能够执行下去,那么这种算法也被称为无锁(Lock-Free)算法 ...
- 29、Java并发性和多线程-非阻塞算法
以下内容转自http://ifeve.com/non-blocking-algorithms/: 在并发上下文中,非阻塞算法是一种允许线程在阻塞其他线程的情况下访问共享状态的算法.在绝大多数项目中,在 ...
- java并发编程(8)原子变量和非阻塞的同步机制
原子变量和非阻塞的同步机制 一.锁的劣势 1.在多线程下:锁的挂起和恢复等过程存在着很大的开销(及时现代的jvm会判断何时使用挂起,何时自旋等待) 2.volatile:轻量级别的同步机制,但是不能用 ...
- 非阻塞同步机制与CAS操作
锁的劣势 Java在JDK1.5之前都是靠synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程 持有守护变量的锁,都采用独占的方式来访问这些 ...
- Java并发编程实战 第15章 原子变量和非阻塞同步机制
非阻塞的同步机制 简单的说,那就是又要实现同步,又不使用锁. 与基于锁的方案相比,非阻塞算法的实现要麻烦的多,但是它的可伸缩性和活跃性上拥有巨大的优势. 实现非阻塞算法的常见方法就是使用volatil ...
- 非阻塞同步算法与CAS(Compare and Swap)无锁算法
锁(lock)的代价 锁是用来做并发最简单的方式,当然其代价也是最高的.内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的上下文切换和调度延时,等待锁的线程会被挂起直至锁释放. ...
- 【Java并发编程】9、非阻塞同步算法与CAS(Compare and Swap)无锁算法
转自:http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral 锁(lock)的代价 ...
随机推荐
- 万丈高楼平地起:UML类图
UML类图 UML类图 是一种静态的结构图,描述了系统的类的集合,类的属性和类之间的关系,可以简化了人们对系统的理解.UML类图 是系统分析和设计阶段的重要产物,是系统编码和测试的重要模型. 图示 类 ...
- Kubernetes-13:存储卷Volume介绍及使用
Volume介绍 Volume存在的意义 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题,首先,当容器崩溃时,kubelet会重启它,但是容器中的文件将丢失--容器以 ...
- 关于安装李沐深度学习d2l包报错的解决办法(保姆教程)
目录 目录:d2l包安装失败的解决过程 前言 一.李沐提供的安装方式 1. 创建一个新的环境 2. 激活 d2l 环境 3. 安装深度学习框架和d2l软件包 3.1 安装PyTorch的CPU或GPU ...
- 8.18域横向smb&wmi明文或hash传递
知识点 windows 2012以上版本默认关闭wdigust,攻击者无法从内存中获取明文密码: Windows2012以下版本如安装KB287199补丁,同样也无法从内存中获取明文密码: 解决方法: ...
- 为什么在 C++ 中,类的静态成员变量需要在源文件中进行定义?
为什么在 C++ 中,类的静态成员变量需要在源文件中进行定义? 类的静态成员变量需要在源文件中进行定义,以便在链接阶段能够正确地分配内存并为其分配地址. 当你在类的头文件中声明一个静态成员变量时,这只 ...
- echarts的x轴显示不全的解决办法
echarts的x轴显示不全的解决办法 一.背景 当x轴类目较多时,label显示时会自动间隔显示,也就是会隐藏掉中间的label,如下图: 二.解决办法 通过设置 xAxis.axisLabel.i ...
- CSS – background and styling img
前言 之前写过一些: W3Schools 学习笔记 (2) – CSS Image Sprites W3Schools 学习笔记 (3) – CSS Styling Images & CSS ...
- ASP.NET Core – Custom Input formatters For Partial Update and Handle Under-posting
前言 之前的文章有谈过关于 ASP.NET Core 处理 under-posting 的方式. 它会使用 class default value. 许多时候这可能不是我们期望的. 比如当我们想要 p ...
- [rCore学习笔记 026]第三章作业
写在前面 本随笔是非常菜的菜鸡写的.如有问题请及时提出. 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 编程题 ...
- C++11 线程同步接口std::condition_variable和std::future的简单使用
std::condition_variable 条件变量std::condition_variable有wait和notify接口用于线程间的同步.如下图所示,Thread 2阻塞在wait接口,Th ...