-
第6章 六个接口构成的MPI子集MPI_1 128个调用接口MPI-2 278个调用接口6.1子集介绍6.1.1MPI调用的参数说明6.1.2MPI初始化 int MPI_Init(int *argc, char ***argv)6.1.3MPI结束 int MPI_Finalize(void)6.1.4MPI当前进程标识 int MPI_Comm_rank(MPI_Comm comm, int *rank)6.1.5MPI通信域包含的进程数 int MPI_Comm_size(MPI_Comm comm, int *size)6.1.6MPI消息发送 int MPI_Send(void* buf, int count, MPI_Datatype, int dest, int tag, MPI_Comm comm)6.1.7MPI消息接收 int MPI_Recv(void*buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)6.1.8MPI返回状态 有三个域 MPI_SOURCE, MPI_TAG, MPI_ERROR 对status变量执行MPI_GET_COUNT调用可以得到接收的消息的长度信息6.2 MPI预定义数据类型6.3 MPI数据类型匹配和数据转换两个方面:宿主语言的类型和通信操作所指定的类型匹配;发送方和接收方的类型匹配类型匹配规则:有类型数据的通信,发送方和接收方均使用相同的数据类型 无类型数据的通信,发送方和接收方均以MPI_BYTE作为数据类型 打包数据的通信,发送方和接收方均使用MPI_PACKED数据转换: 数据类型的转换;数据表示的转换***.1MPI消息的组成信封:<源/目, 标识, 通信域>数据: <起始地址, 数据个数, 数据类型>***.2任意源和任意标识一个接收操作可以接收任何发送者的消息,而一个发送操作,则必须指明一个单独的接收者.MPI_AMY_SOURCE MPI_ANY_TAG***.3 MPI通信域包括:进程组和通信上下文. 第7章 简单的MPI程序示例7.1用MPI实现计时功能double MPI_Wtime(void) double starttime,endtime;...starttime = MPI_Wtime(); ... endtime = MPI_Wtime();printf("That tooks %f secodes\n", endtime - starttime); double MPI_Wtick();返回MPI_Wtime的精度,单位是秒。测试时钟是否准确。7.2获取机器的名字和MPI版本号int MPI_Get_processor_name(char* name, int* resultlen);int MPI_Get_version(int* version, int* subversion);7.3是否初始化及错误退出int MPI_Initialized(int* flag)int MPI_Abort(MPI_Comm comm, int errorcode)下面的例子将指定的master结点杀掉 #include"mpi.h"#include<stdio.h> int main(int argc, char** argv){ int node, size, i; int masternode = 0; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &node); MPI_Comm_size(MPI_COMM_WORLD, &size); for(i = 1; i < argc; i++){ fprintf(stderr, "myid=%d, procs=%d,argv[%d]=%s\n", node,size,i, argv[i]); if(argv[i]&&strcmp("lastmaster", argv[i]) == 0){ mastermode = size -1; } } if(node == masternode){ fprintf(stderr,"myid=%d is masternode Abort\n", node); MPI_Abort(MPI_COMM_WORLD, 99); } else{ fprintf(stderr, "myid=%d is not masternode Barrier!\n", node); MPI_Barrier(MPI_COMM_WORLD); } MPI_Finalize();} 7.4数据接力传送ws2_32.lib mpichd.lib ws2_32.lib mpich.lib 7.6任意源和任意标识的使用在接收中,通过使用任意源和任意tag标识,使得该接收操作可以接收任何进程以任何标识发给本进程的数据,但是该消息的数据类型必须和接收操作的数据类型一致。 第8章MPI并行程序的两种基本模式8.1对等模式的MPI程序设计8.1.1jacobi迭代8.1.4虚拟进程虚拟进程MPI_PROC_NULL,是不存在的假想进程,在MPI中的主要作用是充当真实进程通信的目或源,当一个真实进程向一个虚拟进程发送数据或者从一个虚拟进程接收数据时,该真实进程会立刻正确返回,如同执行一个空操作。8.2主从模式的MPI程序设计
#include "stdafx.h"
#include <stdio.h>
#include <mpi.h>//进程接力
// int main(int argc, char* argv[])
// {
// int rank, value, size;
// MPI_Status status;
// MPI_Init(&argc, &argv);
// MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// MPI_Comm_size(MPI_COMM_WORLD, &size);
// do
// {
// //发送数据
// if (rank == 0){
// fprintf(stderr, "n\Please give new value = ");
// //进程0读入要传入的数据
// scanf("%d", &value);
// fprintf(stderr, "%d read << (%d)\n", rank, value);
// //若不小于一个进程则向下一个进程传递数据
// if ( size > 1){
// MPI_Send(&value, 1, MPI_INT, rank +1, 0, MPI_COMM_WORLD);
// fprintf(stderr, "%d send (%d) >> %d\n", rank, value,rank+1);
// }
//
// }else{//接收数据
// MPI_Recv(&value, 1, MPI_INT, rank -1, 0, MPI_COMM_WORLD, &status);
// //MPI_Get_count(&status,)
// fprintf(stderr, "%d receive(%d) << >> %d\n", rank, value,rank- 1);
// if (rank < size -1 ){
// //如不是最后一个进程则将数据继续向后传递
// MPI_Send(&value, 1, MPI_INT, 0, rank + 1, MPI_COMM_WORLD);
// fprintf(stderr, "%d send (%d)>> %d\n", rank, value, rank+1);
// }
// }
//
// //执行同步,将前后两次数据传递分开
// MPI_Barrier(MPI_COMM_WORLD);
// } while(value >= 0);
//
// MPI_Finalize();
// printf("Hello World!\n");
// return 0;
// }
//
//进程之间相互问候// void Hello(void);
//
// int main(int argc, char* argv[])
// {
// int me, option, namelen, size;
//
// char processor_name[MPI_MAX_PROCESSOR_NAME];
// MPI_Init(&argc, &argv);
// MPI_Comm_rank(MPI_COMM_WORLD, &me);
// MPI_Comm_size(MPI_COMM_WORLD, &size);
//
// if (size < 2){
// //如果总的进程数小于2, 则出错推出
// fprintf(stderr, "system require at least 2 processes.");
// MPI_Abort(MPI_COMM_WORLD, 1);
// }
//
// //get current name
// MPI_Get_processor_name(processor_name, &namelen);
//
// fprintf(stderr, "Process &d is alive on &s\n", me, processor_name);
//
// //sync
// MPI_Barrier(MPI_COMM_WORLD);
//
// //greet each other
// Hello();
//
// //
// MPI_Finalize();
//
// return 0;
// }
//
// void Hello(void){
//
// int nproc, me;
// int type =1;
// int buffer[2], node;
// MPI_Status status;
// MPI_Comm_rank(MPI_COMM_WORLD, &me);
// MPI_Comm_size(MPI_COMM_WORLD, &nproc);
//
// if (me == 0){
// //进程0负责打印提示信息
// printf("\nHello test from all to all\n");
// fflush(stdout);
// }
//
// //循环对每个进程进行问候
// for (node = 0; node < nproc; node++){
// if (node != me){
// buffer[0]= me;
// buffer[1]= node;//greet node
//
// //send information to node
// MPI_Send(buffer, 2, MPI_INT, node, type, MPI_COMM_WORLD);
//
// //receive information from node
// //question 1. blocked or not blocked
// //question 2. when MPI_Recv returns, the information must be sent from node!
// MPI_Recv(buffer, 2, MPI_INT, node, type, MPI_COMM_WORLD, &status);
//
// //error if receiving information is not sent to me or
// //????
// if ((buffer[0] != node )||(buffer[1] != me)){
// (void)fprintf(stderr, "Hello: %d!=%d or %d!=d%\n", buffer[0], node, buffer[1], me);
// }else{
// //receiving informaton
// printf("Hello from %d to %d\n", me, node);
// }
//
//
//
// fflush(stdout);
// }
// }
//
// }
//接收其他进程的数据
// int main(int argc, char** argv){
// int rank;
// int size;
// int i;
// int buf[1];
//
// MPI_Status status;
// MPI_Init(&argc, &argv);
// MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// MPI_Comm_size(MPI_COMM_WORLD, &size);
//
//
// if (rank == 0){
// for (i = 0; i < 100*(size-1); i++){
// MPI_Recv(buf, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
// printf("Msg=%d from%d with tag%d\n", buf[0],status.MPI_SOURCE, status.MPI_TAG);
// }
// }else{
// for (i=0; i < 100; i++){
// buf[0]=rank+i;
// MPI_Send(buf, 1, MPI_INT, 0, i, MPI_COMM_WORLD);
//
// }
// }
//
// MPI_Finalize();
//}//对等模式的MPI程序设计
// const int totalsize = 16;
// const int mysize = totalsize/4;
// const int steps = 10;
// int aa[2][3]={{1,1,1},{3,3,3}};
// int a[totalsize][mysize + 2];
// int b[totalsize][mysize + 2];
//
// int n, myid, numprocs, i, j, rc;
//
// int main(int argc, char** argv){
// int begin_col;
// int end_col;
// int ierr;
//
// MPI_Status status;
//
// MPI_Init(&argc, &argv);
// MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
//
// //数组初始化
// for (j = 1; j < mysize+2; j++){
// for (i=1; i < totalsize; i++){
// a[i][j] = 0.0;
// }
// }
//
// //
// if (myid == 0){
// for (i = 1; i < totalsize; i++){
// a[i][2] = 8.0;
// }
// }
//
// //
// if (myid == 3){
// for (i = 1; i < totalsize; i++){
// a[i][mysize + 1] = 8.0;
// }
// }
//
// //
// for (i = 1; i < mysize; i++){
// a[1][i] = 8.0;
// a[totalsize][i] = 8.0;
// }
//
//
// //jacobi迭代部分
// for (n = 1; n < steps; n++){
// //从右侧的邻居得到数据
// if (myid < 3){
// MPI_Recv(&a[1][mysize + 2],totalsize, MPI_INT, myid + 1, 10, MPI_COMM_WORLD, &status);
// }
//
// //向左侧的邻居发送数据
// if (myid > 0){
// MPI_Send(&a[1][2], totalsize, MPI_INT, myid, 10, MPI_COMM_WORLD);
// }
//
// //向右侧邻居发送数据
// if (myid < 3){
// MPI_Send(&a[1][mysize+1], totalsize, MPI_INT, myid + 1, 10, MPI_COMM_WORLD);
// }
//
// //向左侧邻居接收数据
// if (myid > 0)
// {
// MPI_Recv(&a[1][1], totalsize, MPI_INT, myid - 1, 10, MPI_COMM_WORLD, &status);
// }
//
// //
// begin_col = 2;
// end_col = mysize + 1;
// //
// if (myid == 0){
// begin_col = 3;
// }
// //
// if (myid == 3){
// end_col = mysize;
// }
//
// //
// for(j = begin_col; j < end_col; j++){
// for (i = 2; i < totalsize - 1; i++){
// b[i][j] = (a[i][j+1] + a[i][j-1] + a[i+1][j] + a[i-1][j])*0.25;
// }
// }
//
// for(j = begin_col; j < end_col; j++){
// for (i = 2; totalsize-1; i++){
// a[i][j]= b[i][j];
//
// }
// }
// }
//
// for (i = 2; i < totalsize; i++){
// //printf()
// }
//
// MPI_Finalize();
// return 0;
//}主从模式的MPI程序设计
void master_io();
void slave_io();
#define MSG_EXIT 1
#define MSG_PRINT_ORDERED 2
#define MSG_PRINT_UNORDERED 3int main(int argc, char** argv){
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0)
{
master_io();
}else{
slave_io();
}MPI_Finalize();
}void master_io(){
int i, j, size, nslave, firstmsg;
char buf[256], buf2[256];
MPI_Status status;
MPI_Comm_size(MPI_COMM_WORLD, &size);
nslave = size -1;
while (nslave > 0){
//从任意进程接收任意标识的消息
MPI_Recv(buf, 256, MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG,MPI_COMM_WORLD, &status);
switch(status.MPI_TAG)
{
case MSG_EXIT: nslave--; break;
case MSG_PRINT_UNORDERED:fputs(buf, stdout);break;
case MSG_PRINT_ORDERED:
firstmsg = status.MPI_SOURCE;
for (i=1; i< size; i++){
if (i == firstmsg){
fputs(buf, stdout);
}else{
//指定源进程和消息标识
MPI_Recv(buf2, 256, MPI_CHAR, i, MSG_PRINT_ORDERED, MPI_COMM_WORLD, &status);
fputs(buf2, stdout);
}
}
break;
}
}
}void slave_io(){
char buf[256];
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, & rank);
sprintf(buf, "Hello from slave&d, ordered print\n", rank);//send ordered msg
MPI_Send(buf, strlen(buf)+1, MPI_CHAR, 0, MSG_PRINT_ORDERED, MPI_COMM_WORLD);sprintf(buf, "Goodbye from slave %d, ordered print\n", rank);
//send unordered msg
MPI_Send(buf, strlen(buf)+1, MPI_CHAR, 0, MSG_PRINT_UNORDERED, MPI_COMM_WORLD);//send exit msg
MPI_Send(buf, 0, MPI_CHAR, 0, MSG_EXIT, MPI_COMM_WORLD);}
-
第1章 并行计算机
1.1并行计算机的分类
指令与数据:SIMD与MIMI SPMD与MPMD
存储方式:共享内存与分布式内存 越来越重要的是分布式共享内存
1.2物理问题在并行机上的求解
串行问题与并行问题
第2章 并行编程模型与并行语言
2.1并行编程模型
数据并行:将相同的操作同时作用于不同的数据,适合SIMD和SPMD 高效的编译器成为它的的一个主要问题。
和消息传递:即各个并行的部分之间通过传递消息来交换信息、协调步伐、控制执行。
2.2并行语言
设计全新的并行语言
扩展原来的串行语言的语法成分,使之支持并行特征
不改变串行语言,仅为串行语言提供可调用的并行库(MPI)
第3章并行算法
3.1并行算法分类
运算的基本对象:数值并行计算和非数值计算(符合计算)
进程之间的依赖关系:同步并行计算和异步并行计算和纯并行计算
并行计算任务的大小:粗粒度并行计算和细粒度并行计算和中粒度并行计算
好的并行计算既要能很好地匹配并行计算机硬件结构,又能反应问题内在的并行性
机群来将尽量减少通信的次数。
第二部分 基本的MPI的并行程序设计
第4章MPI简介
4.1MPI
4.2MPI的目的
4.3MPI的产生
4.4MPI的绑定
4.5目前主要的MPI的实现
第5章 第一个MPI程序
#include "mph.h"
#include <stdio.h>
#include <math.h>
void main()
{
int myid, numprocs;
int namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Init(&argc, &argv);
//得到当前正在运行的进程的标识号放在myid中
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
//得到所有参加运算的进程个个数
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
//得到本进程运行的机器的名称
MPI_Get_processor_name(processor_name, &namelen);fprintf(stderr, "Hello World! process%dof%don%s\n", myid, numprocs, processor_anme);
MPI_Finalize();
}
第6章 六个接口构成的MPI子集
MPI_1 128个调用接口
MPI-2 278个调用接口
6.1子集介绍
6.1.1MPI调用的参数说明
6.1.2MPI初始化 int MPI_Init(int *argc, char ***argv)
6.1.3MPI结束 int MPI_Finalize(void)
6.1.4MPI当前进程标识 int MPI_Comm_rank(MPI_Comm comm, int *rank)
6.1.5MPI通信域包含的进程数 int MPI_Comm_size(MPI_Comm comm, int *size)
6.1.6MPI消息发送 int MPI_Send(void* buf, int count, MPI_Datatype, int dest, int tag, MPI_Comm comm)
6.1.7MPI消息接收 int MPI_Recv(void*buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
6.1.8MPI返回状态 有三个域 MPI_SOURCE, MPI_TAG, MPI_ERROR 对status变量执行MPI_GET_COUNT调用可以得到接收的消息的长度信息
6.2 MPI预定义数据类型
6.3 MPI数据类型匹配和数据转换
两个方面:宿主语言的类型和通信操作所指定的类型匹配;发送方和接收方的类型匹配
类型匹配规则:有类型数据的通信,发送方和接收方均使用相同的数据类型
无类型数据的通信,发送方和接收方均以MPI_BYTE作为数据类型
打包数据的通信,发送方和接收方均使用MPI_PACKED
数据转换: 数据类型的转换;数据表示的转换
***.1MPI消息的组成
信封:<源/目, 标识, 通信域>
数据: <起始地址, 数据个数, 数据类型>
***.2任意源和任意标识
一个接收操作可以接收任何发送者的消息,而一个发送操作,则必须指明一个单独的接收者.
MPI_AMY_SOURCE MPI_ANY_TAG
***.3 MPI通信域
包括:进程组和通信上下文.







