#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. mysql 8.0.18 根据.ibd文件和建库SQL恢复数据

    前提:执行建库SQL,(包括建表的SQL) 1. 在mysql 的data文件夹中,找到需要恢复的DB名称,清除其文件夹下的所有文件,将待恢复的.ibd文件复制到此文件夹内 2. 执行SQL,然后查询 ...

  2. 【YashanDB知识库】swap空间使用超大报错

    问题描述 问题单 使用GROUP_CONCAT函数时,数据库swap表空间上涨厉害 测试用例 drop table tmp1; create table tmp1(c1 int,c2 double,c ...

  3. 【YashanDB知识库】手动停止统计信息自动收集任务导致的性能变差

    [问题分类]功能使用 [关键字]统计信息收集 [问题描述]UAT对外演示环境因统计信息收集任务引起数据库整理性能变慢无应急处理手段 [问题原因分析] ● DROP_JOB程序用于删除一个非执行状态下的 ...

  4. 【漏洞分析】Penpie 攻击事件:重入攻击构造奖励金额

    背景信息 2024 年 9月 3日,Penpie 合约遭受重入攻击,攻击者在重入阶段向合约添加流动性来冒充奖励金额,从而获取合约内原有的奖励代币.资产损失高达 2734 万美元. 2024 年 5月, ...

  5. 使用gin实现简单的注册和登录功能

    一.前言 使用了gorm操作数据库,后端基于gin框架,只是一个简单的注册和登录与数据库交互的后端实现例子. 二.目录结构 -templates --regist.html --login.html ...

  6. 即构 UIKits 重磅发布!高效开发与自定义UI兼备,打造互动场景新标杆

    即构UIKits上线,新一代场景化实时互动SDK! 即构科技发布了首款面向中小团队的整合型实时互动产品UIKits , 基于场景化最佳实践,整合RTC.IM.直播.美颜等多款产品,打造了音视频通话UI ...

  7. Node.js开发博客项目笔记-搭建环境(2)

    搭建环境 首先新建blog-1文件夹,在文件夹下初始化package.json,执行命令: npm init -y 生成的package.json文件中的main属性默认值index.js改成bin/ ...

  8. Spring —— 事务简介

    Spring 事务 简介 事务作用:在数据层保障一系列的数据库操作同成功同失败 Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败 小案例             添加事务管理: ...

  9. Flutter 不容错过的 7 大亮点 | Google I/O 精彩回顾

    Flutter 在今年的 Google I/O 上发布了许多重磅更新,欢迎大家和我们一起了解其中不容错过的 7 大亮点, 点击这里 观看 Flutter 不容错过的 7 大亮点 视频了解更多信息. F ...

  10. foobar2000 v1.6.11 汉化版(更新于 2022.08.25)

    foobar2000 v1.6.11 汉化版 -----------------------[软件截图]---------------------- -----------------------[软 ...