国科大-高性能计算考试
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
考试比较难,课程比较繁琐.
高性能计算2022加粗样式考试
1. 启动MPI程序时系统生成的是1维程序···
-
写出一个子程序或函数生成行和列通讯子
思路
首先进行参数合法性的检查然后将通信子对应的进程组进行划分再将通信子对应的进程组进行列划分最后将通信子中的进程编号使用MPI_Comm_rank进行分发int getComm(int myid, int np, int p, int q, int myrow,int mycol, MPI_Comm *rowComm,MPI_Comm *colComm){ if(np < p * q) return 1; int key, color; if(myid < p * q) col = myid / q; else color = MPI_UNDEEFINED key = myid; MPI_Comm_split(MPI_COMM_WORLD, color, key, rowComm); if(myid < p*q) color = myid % q; else col = MPI_UNDEEFINED; key = myid; MPI_Comm_split(MPI_COMM_WORLD, color,key,colComm); if(myid < p*q){ MPI_Comm_rank(colComm, &myrow); MPI_Comm_rank(rowComm, &mycol); } return 0; }
-
卷帘方式计算值
使用卷帘存储方式即对于一般的m*n 矩阵和一般的处理器阵列p*q矩阵元素 a i j a_{ij} aij存放在处理器 P k l P_{kl} Pkl中其中k=i mod p, l=j mod q。用一个8行8列的矩阵在3*2的处理器阵列进行处理可知对于 a i j = a s t k l a_{ij} = a^{kl}_{st} aij=astkl有 k = i m o d p , l = j m o d q , s = i / p , t = j / q k=i\space{mod}\space p, l = j \space mod \space q,s = i/p, t = j/q k=i mod p,l=j mod q,s=i/p,t=j/q
-
广播进程的实现
思路
现在第0行的行进程中广播 p 00 p_{00} p00上的数据A此时整行都有该数据然后再各个列通讯子中广播到整列int broadcastRowCol(int myid, int np, int myrow, int mycol, float *a, int count, MPI_Comm rowComm,MPI_Comm colComm){ if(myrow == 0) MPI_Bcast(a, count, MPI_FLOAT, 0, rowComm); MPI_Bcast(a, count, MPI_FLOAT, 0, colComm); }
2. 分块矩阵
-
一次性发送和接收 A 00 A_{00} A00和 A 20 A_{20} A20
思路
使用MPI_Type_vector 函数构建一个vector 的类型命名为submat然后使其extent 即延伸尺寸正好可以覆盖第一行和第二行矩阵块然后我们如果使用两个submat 变量第一个submat 变量传输的内容是 A 00 A_{00} A00 但其延伸尺寸覆盖过了第一行其他矩阵块和第二行矩阵块第二个submat 的起点正好是 A 20 A_{20} A20 可以传输 A 20 A_{20} A20 矩阵块。
/* 假设整个矩阵式n*n大小矩阵按行优先存储数据类型以float为例子 */ MPI_Datatype submat_base, submat; MPI_Type_vector(m, m, n, MPI_FLOAT, &submat_base); int array_of_blocklens[2] = {1,1}; int array_of_disps[2] = {0,2*m*n*sizeof(float)}; MPI_Datatype array_of_types[2] = {submat_base, MPI_UB}; MPI_Type_struct(2, array_of_blocklens, array_of_disps, array_of_types, &submat); MPI_Type_commit(&submat);
-
只传输 A 00 A_{00} A00和 A 20 A_{20} A20
思路
以直接利用MPI_Type_indexed 将所需的内容索引到数据类型里就行了。沿用第1 问中的假设条件先进行赋值块大小和块间隔然后更正第二个矩阵块的间隔最后提交结果MPI_Datatype submat; int *array_of_blocklens = new int[2 * m]; int *array_of_disps = new int[2 * m]; for(int i=0; i<2*m; i++){ array_of_blocklens[i] = m; array_of_disps[i] = i * n; } for(int i=m; i<2*m; i++) array_of_disps[i] = (i + 2 * m) * n; MPI_Type_indexed(2*m, array_of_blocklens, array_of_disps, MPI_FLOAT, &submat); MPI_Type_commit(&submat);
3. 自定义数据结构的分发
思路
采用MPI_Type_struct 方法将需要传输的内容整合成一个MPI 结构体进行传输。首先初始化进程环境然后获取通信子的进程编号和进程个数再使用MPI的进行自定义数据类型和打包
#include <stdio.h>
#include <mpi.h>
typedef struct{
int m[3];
float a[2];
char c[5];
}dataType;
int main(int argc, char**argv)
{
MPI_Init(&argc, &argv);
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Datatype newType;
int blocks[3] = {3, 2, 5};
MPI_Aint disps[3] = {0, 12, 20};
MPI_Datatype types[3] = {MPI_INT, MPI_FLOAT, MPI_CHAR};
MPI_Type_struct(3, blocks, disps, types, &newType);
MPI_Type_commit(&newType);
dataType t1 = {{1, 2, 3}, {4.0, 5.0}, {'a', 'b', 'c', 'd', '\0'}};
dataType t2;
if (rank == 0)
MPI_Send(&t1, 1, newType, 1, 0, MPI_COMM_WORLD);
else{
MPI_Recv(&t2, 1, newType, 0, 0, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
printf("%d %d %d %f %f %s\n", t2.m[0], t2.m[1], t2.m[2], t2.a[0], t2.a[1],
t2.c);
}
MPI_Type_free(&newType);
MPI_Finalize();
}
4. MPI_Allgather的实现
-
一个如何实现的详细并行方法
思路
MPI_Alltoall 的功能是全交换即各个进程都在向所有进程发送对应的分段同时从所以进程接收发来的分段。这里给出一种简单的实现方式即每个进程使用一个循环向其他进程发送分段同时循环中接受其他进程发来的分段而自己发给自己的部分直接使用memcpy 拷贝 -
MPI_Allgather子程序的实现
int myAlltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm) { int rank, size; int type_size; MPI_Type_size(sendtype, &type_size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); for (int i = 0; i < size; ++i){ if (i == rank){ memcpy(sendbuf + i * sendcount * type_size, recvbuf + i * recvcount *type_size, sendcount * type_size); continue; } MPI_Send(sendbuf + i * sendcount * type_size, sendcount, sendtype, i, 0, MPI_COMM_WORLD); MPI_Recv(recvbuf + i * recvcount * type_size, recvcount, recvtype, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } return 0; }