课程名称: 高性能计算 学 院 计算机学院 专业班级 软件3班 学 号 姓 名 联系方式 任课教师
2015 年 12 月 18 日
《高性能计算》实验课
(一) Windows系统下搭建MPI(并行计算)环境
MPI的全称是Message Passing Interface即标准消息传递界面,可以用于并行计算。MPI的具体实现一般采用MPICH。 (1)安装MPI的SDK——MPICH2
mpich2-1.4.1p1-win-ia32安装程序的下载地址:
http://www.mcs.anl.gov/research/projects/mpich2/downloads/tarballs/1.4.1p1/mpich2-1.4.1p1-win-ia32.msi
本实验以设置安装在C:\\Program Files\\MPICH2目录下为例。下载完成后,点击MPICH2安装程序进行安装。
安装完成后需要测试所安装的MPICH2,测试前首先需要注册一
个用户,具体操作:“开始”按钮——》所有程序——》MPICH2——》wmpiregister.exe。输入用户名、密码。注意:该用户名必须为有效的操作系统管理员账户,密码对应为系统登录密码。如图所示:
配置环境变量,打开系统—》高级系统设置—》高级—》环境变量—》系统变量—》点击PATH—》编辑—》在最后面加上C:\\Program Files \\MPICH2\\bin—》点击确定完成。
接下来选择开始——》所有程序——》MPICH2——》wmpiexec.exe;选择Application为C:\\Program files\\MPICH2\\examples\\cpi.exe(MPI里面自带的一个计算圆周率的例子程序,可以用来进行测试)。在Number of processes的数量选择2表示用二个进程来协同完成。选中“run in separate window”选项,点击Excute。然后在控制台窗口提示输入number of intervals,随便输入个大点的数字(50000,5000000)就可以看到求的圆周率值,结果如图所示:
注意:在Show Command中的字符串,可以在控制台下(cmd)输入该字符串得到一样的结果(同学们可以测试一下)。 (二) 在VC6.0中添加MPICH2 (1) 在VC6中添加MPICH2
首先在VC6.0中加入MPI的include和lib。点击VC6.0程序菜单中“Tools”—》“Optains”—》“Directories”然后添加,如图所示:
(2) 在VC6.0上运行第一个MPI程序
新建Win32 Console Application工程,加入如下代码: #define MPICH_SKIP_MPICXX #include #pragma comment (lib,\"mpi.lib\") int main (int argc, char* argv[]) { int myid, numprocs; int namelen; char processor_name[MPI_MAX_PROCESSOR_NAME]; MPI_Init(&argc, &argv); //用MPI_Comm_rank获得进程的rank,该rank值为0到p-1间的整数,相当于进程的ID MPI_Comm_rank(MPI_COMM_WORLD, &myid); //用MPI_Comm_size获得进程个数 MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Get_processor_name(processor_name,&namelen); printf(\"Hello World! By MoreWindows\\nPorcess %d of %d on %s\\n\myid, numprocs, processor_name); MPI_Finalize(); if (myid==1) { printf(\"\\nPress a key and exit. \\n\"); getch(); } return 0; } (三) 多台电脑上协同运行MPI 只有多台电脑集群后才能更好的发挥并行计算的威力,由于MPI的帮助,这个工作将变得异常简单,下面以二台PC机协同运行计算圆周率cpi.exe为例进行说明。 (1) 多台电脑运行MPI的条件 参加并行计算的机器必须注册一个相同的账户,如两台PC机上都应该注册一个MPI账号。 创建JOB目录。每台机器上需要有一个路径相同的目录,用于存放待执行的JOB(即exe程序),如创建的目录是d:\\MPI\\,再将测试用的可执行文件复制到二台PC机的该目录下。 (2) 联机执行命令解释 在控制台输入联机执行命令:“C:\\Program Files\\MPICH2\\bin\\mpiexec.exe”-host n Node_1 Node_2 … Node_n -noprompt ExePath “-hosts”表示要联机运行,n表示有n台机器参加运算,Node_1(及Node_2…)为各机器的计算机名或IP。ExePath为exe的文件路径如d:\\MPI\\cpi.exe (四) 实现矩阵乘法运算(简单的并行运算) /* 矩阵并行计算 C=A*B --- C(i,j)等于A的第i行乘以第j列 */ #include 生成n*n矩阵 */ void GenerateMatrix(float *m, int n); void PrintMatrix(float *p, int n); void GeneralMul(float *A, float *B, float *C, int n); void ClearMatrix(float *m, int n); /* 矩阵并行计算 */ void ParallelCacul(float *A, float *B, float *C, int n, int thread_num); /* 两个矩阵的误差 */ float diff(float *C1, float *C0, int n); struct ARG { float *A; float *B; float *C; int cx, cy; //第一个元素的坐标 int m; //当前线程要计算的C的元素个数 int n; }; int main(int argc, char **argv) { if (argc != 3) { printf(\"Usage: %s N thread_num\\n\ return 0; } int n=atoi(argv[1]); int thread_num = atoi(argv[2]); float *A = new float[n*n]; float *B = new float[n*n]; float *C = new float[n*n]; float *C0 = new float[n*n]; GenerateMatrix(A, n); GenerateMatrix(B, n); clock_t start; float time_used; ClearMatrix(C0, n); start=clock(); GeneralMul(A, B, C0, n); time_used = static_cast start)/CLOCKS_PER_SEC*1000; printf(\"General: time = %f\\n\ ClearMatrix(C, n); start=clock(); ParallelCacul(A, B, C, n, thread_num); time_used = static_cast start)/CLOCKS_PER_SEC*1000; printf(\"Block: time = %f\\n\ printf(\"Difference of two result: %f\\n\ - - delete [] A; delete [] B; delete [] C; delete [] C0; return 0; } void ClearMatrix(float *m, int n) { for (int i=0; i void GeneralMul(float *A, float *B, float *C, int n) { for (int i=0; i DWORD WINAPI Mul_Fun(LPVOID arg) { struct ARG *p = (struct ARG *)arg; float *A = p->A; float *B = p->B; float *C = p->C; int m = p->m; int n = p->n; for (int i=p->cx; i return 0; } void ParallelCacul(float *A, float *B, float *C, int n, int thread_num) { int m = n*n/thread_num; //每个线程需要计算的元素个数,不考虑不能整除的情况 struct ARG *args = new struct ARG[thread_num]; HANDLE *h = new HANDLE[thread_num]; int i; for (i = 0; i for (i=0; i args[i].cx = i*m/n; args[i].cy = i*m%n; h[i] = CreateThread(NULL, 0, Mul_Fun, (LPVOID)(&args[i]), 0, 0 ); } for (i=0; i } } void GenerateMatrix(float *p, int n) { srand(time(NULL)+rand()); for (int i=0; i static_cast (static_cast p++; } } float diff(float *C1, float *C0, int n) { float rst=0.0; float t; for (int i=0; i void PrintMatrix(float *p, int n) { for (int i=0; i printf(\"\\n\"); } printf(\"\\n\"); } 输入数据: (五) 实现矩阵乘法运算(Cannon算法) #define MPICH_SKIP_MPICXX #include #include #pragma comment (lib,\"mpi.lib\") MPI_Status status; double **A, **B, **C; //C=A*B double *a,*b,*c; //各个进程的缓冲区 int n; //矩阵的行列数 int np; //每个进程控制的小矩阵的行列数 int p,rank; //进程个个数、当前进程的编号,笛卡尔进程编号 double *tempa, *tempb; void ProduceABC(); //在根处理器中生成矩阵AB,初始化矩阵C void PrintABC();//输出结果 void ScatterAB();// 分发矩阵AB中的元素到各个进程中 void MainProcess(); //cannon算法的主过程 void collectC(); //收集结果矩阵C void Mutiply(); //矩阵相乘 void Printab(); void Printc(); int main(int argc, char *argv[]) { int i; double starttime,endtime; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &p); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if(rank == 0) { } MPI_Bcast(&n, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); // n = atoi(argv[1]); np = n/(int)sqrt(p); a = (double*)malloc(np*np*sizeof(double)); b = (double*)malloc(np*np*sizeof(double)); c = (double*)malloc(np*np*sizeof(double)); memset(c, 0, np*np*sizeof(double)); tempa = (double*)malloc(np*np*sizeof(double)); tempb = (double*)malloc(np*np*sizeof(double)); if(rank == 0) { //在根处理器中为矩阵ABC分配空间 printf(\"请输入矩阵的行列数n= \"); fflush(stdout); scanf(\"%d\printf(\"\\n\"); 阵C } A = (double**)malloc(n*sizeof(double*)); B = (double**)malloc(n*sizeof(double*)); C = (double**)malloc(n*sizeof(double*)); for(i = 0; i < n; i++) { } ProduceABC(); //在根处理器中随机生成矩阵AB,初始化矩A[i] = (double*)malloc(n*sizeof(double)); B[i] = (double*)malloc(n*sizeof(double)); C[i] = (double*)malloc(n*sizeof(double)); ScatterAB();// 分发矩阵AB中的元素到各个进程中 else { &status); &status); } starttime=MPI_Wtime(); //开始时间 MPI_Recv(b, np*np, MPI_DOUBLE, 0, 2, MPI_COMM_WORLD, MPI_Recv(a, np*np, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD, MainProcess(); //cannon算法的主过程 if(rank == 0) { collectC(); //收集结果矩阵C PrintABC(); //输出结果 endtime=MPI_Wtime(); printf(\"time used: %lf\\n\ for(i = 0; i < n; i++) { free(A[i]); free(B[i]); free(C[i]); } free(A); free(B); free(C); } else { MPI_Send(c, np*np, MPI_DOUBLE, MPI_COMM_WORLD); } 0, 1, free(a); free(b); free(c); free(tempa); free(tempb); MPI_Finalize(); return 0; } void ProduceABC()//在根处理器中生成矩阵AB { int i,j; for(i=0; i printf(\"A[0][0]=%f\\nB[0][0]=%f\\nC[0][0]=%f\\n\ for(j=0; j 0][0]); } void ScatterAB()// 分发矩阵AB中的元素到各个进程中 { int imin,imax,jmin,jmax; int sp; int i,j,k,m; for(k=0; k sp = (int)sqrt(p); imin = (k / sp) * np; imax = imin + np - 1; jmin = (k % sp) * np; jmax = jmin + np -1; /*rank=0的处理器将A,B中的相应块拷至tempa,tempb,准/*计算相应处理器所分得的矩阵块在总矩阵中的坐标范围 备向其他处理器发送*/ m = 0; for(i=imin; i<=imax; i++) { for(j=jmin; j<=jmax; j++) } { } tempa[m] = A[i][j]; tempb[m] = B[j][i]; //矩阵B按列优先存储 m++; /*根处理器将自己对应的矩阵块从tempa,tempb拷至a,b*/ if(k==0) { } else /*根处理器向其他处理器发送tempa,tempb中相memcpy(a, tempa, np*np*sizeof(double)); memcpy(b, tempb, np*np*sizeof(double)); 关的矩阵块*/ { MPI_Send(tempa, np*np, MPI_DOUBLE, k, 1, MPI_COMM_WORLD); MPI_Send(tempb, np*np, MPI_DOUBLE, k, 2, MPI_COMM_WORLD); } } } void MainProcess() //cannon算法的主过程 { MPI_Comm comm; //笛卡尔结构通讯器 int crank; int dims[2],periods[2], coords[2]; int source, dest, up, down, right, left; int i; dims[0] = dims[1] = (int)sqrt(p); periods[0] = periods[1] = 1; MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, 1, &comm); MPI_Comm_rank(comm, &crank); MPI_Cart_coords(comm, crank, 2, coords); MPI_Cart_shift(comm, 1, -1, &right, &left); MPI_Cart_shift(comm, 0, -1, &down, &up); MPI_Cart_shift(comm, 1, -coords[0], &source, &dest); MPI_Sendrecv_replace(a, np*np, MPI_DOUBLE, dest, 1, source, 1, comm, &status); MPI_Cart_shift(comm, 0, -coords[1], &source, &dest); MPI_Sendrecv_replace(b, np*np, MPI_DOUBLE, dest, 1, source, 1, comm, &status); Mutiply(); //矩阵相乘 for(i = 1; i < dims[0]; i++) { MPI_Sendrecv_replace(a, np*np, MPI_DOUBLE, left, 1, right, 1, comm, &status); MPI_Sendrecv_replace(b, np*np, MPI_DOUBLE, up, 1, down, 1, comm, &status); } MPI_Comm_free(&comm); } void collectC() //收集结果矩阵C { int i,j,k,s,m; int imin,imax,jmin,jmax; int sp= (int)sqrt(p); /* 根处理器中的c赋给总矩阵C */ for (i=0;i } } void Mutiply() //矩阵相乘 { int i,j,k; /*将接收到的c拷至C中的相应位置,从而构造出C*/ for(i=imin,m=0; i<=imax; i++,m++) { } for(j=jmin,s=0; j<=jmax; j++,s++) C[i][j]=c[m*np+s]; //printf(\"rank = %d\\n\imin = (k / sp) * np; imax = imin + np - 1; jmin = (k % sp) * np; jmax = jmin + np -1; /*根处理器从其他处理器接收相应的分块c*/ MPI_Recv(c, np*np, MPI_DOUBLE, k, 1, MPI_COMM_WORLD, for(i=0; i for(k=0; k
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo7.cn 版权所有 湘ICP备2022005869号-9
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务