并行计算-实验二-矩阵乘法的OpenMP实现及性能分析

合集下载

华科并行实验报告

华科并行实验报告

一、实验模块计算机科学与技术二、实验标题并行计算实验三、实验目的1. 了解并行计算的基本概念和原理;2. 掌握并行编程的基本方法;3. 通过实验加深对并行计算的理解。

四、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 并行计算平台:OpenMP五、实验步骤1. 准备实验环境首先,在计算机上安装OpenMP库,并配置环境变量。

2. 编写并行计算程序编写一个简单的并行计算程序,实现以下功能:(1)计算斐波那契数列的第n项;(2)计算素数的个数;(3)计算矩阵乘法。

以下为斐波那契数列的并行计算程序示例:```cpp#include <omp.h>#include <iostream>using namespace std;int main() {int n = 30;int fib[31] = {0};fib[0] = 0;fib[1] = 1;#pragma omp parallel forfor (int i = 2; i <= n; i++) {fib[i] = fib[i - 1] + fib[i - 2];}cout << "斐波那契数列的第" << n << "项为:" << fib[n] << endl; return 0;}```3. 编译程序使用g++编译器编译程序,并添加OpenMP库支持。

```bashg++ -fopenmp -o fib fib.cpp```4. 运行程序在命令行中运行编译后的程序,观察结果。

5. 分析结果通过对比串行计算和并行计算的结果,分析并行计算的优势。

六、实验过程1. 准备实验环境,安装OpenMP库并配置环境变量;2. 编写并行计算程序,实现斐波那契数列的并行计算;3. 编译程序,并添加OpenMP库支持;4. 运行程序,观察结果;5. 分析结果,对比串行计算和并行计算的性能。

并行程序设计实验报告-OpenMP 进阶实验

并行程序设计实验报告-OpenMP 进阶实验

实验2:OpenMP 进阶实验1、实验目的掌握生产者-消费者模型,具备运用OpenMP相关知识进行综合分析,可实现实际工程背景下生产者-消费者模型的线程级负责均衡规划和调优。

2、实验要求1)single与master语句制导语句single 和master 都是指定相关的并行区域只由一个线程执行,区别在于使用master 则由主线程(0 号线程)执行,使用single 则由运行时的具体情况决定。

两者还有一个区别是single 在结束处隐含栅栏同步,而master 没有。

在没有特殊需求时,建议使用single 语句。

程序代码见程序2-12)barrier语句在多线程编程中必须考虑到不同的线程对同一个变量进行读写访问引起的数据竞争问题。

如果线程间没有互斥机制,则不同线程对同一变量的访问顺序是不确定的,有可能导致错误的执行结果。

OpenMP中有两种不同类型的线程同步机制,一种是互斥机制,一种是事件同步机制。

其中事件同步机制的设计思路是控制线程的执行顺序,可以通过设置barrier同步路障实现。

3)atomic、critical与锁通过critical 临界区实现的线程同步机制也可以通过原子(atomic)和锁实现。

后两者功能更具特点,并且使用更为灵活。

程序代码见程序2-2、2-3、2-44)schedule语句在使用parallel 语句进行累加计算时是通过编写代码来划分任务,再将划分后的任务分配给不同的线程去执行。

后来使用paralle for 语句实现是基于OpenMP 的自动划分,如果有n 次循环迭代k 个线程,大致会为每一个线程分配[n/k]各迭代。

由于n/k 不一定是整数,所以存在轻微的负载均衡问题。

我们可以通过子句schedule 来对影响负载的调度划分方式进行设置。

5)循环依赖性检查以对π 的数值估计的方法为例子来探讨OpenMP 中的循环依赖问题。

圆周率π(Pi)是数学中最重要和最奇妙的数字之一,对它的计算方法也是多种多样,其中适合采用计算机编程来计算并且精确度较高的方法是通过使用无穷级数来计算π 值。

矩阵乘法的并行化实验报告

矩阵乘法的并行化实验报告

北京科技大学计算机与通信工程学院实验报告实验名称:学生姓名:专业:班级:学号:指导教师:实验成绩:________________________________实验地点:实验时间:2015年05月一、实验目的与实验要求1、实验目的1对比矩阵乘法的串行和并行算法,查看运行时间,得出相应的结论;2观察并行算法不同进程数运行结果,分析得出结论;2、实验要求1编写矩阵乘法的串行程序,多次运行得到结果汇总;2编写基于MPI,分别实现矩阵乘法的并行化。

对实现的并行程序进行正确性测试和性能测试,并对测试结果进行分析。

二、实验设备(环境)及要求《VS2013》C++语言MPICH2三、实验内容与步骤实验1,矩阵乘法的串行实验(1)实验内容编写串行程序,运行汇总结果。

(2)主要步骤按照正常的矩阵乘法计算方法,在《VS2013》上编写矩阵乘法的串行程序,编译后多次运行,得到结果汇总。

实验2矩阵乘法的并行化实验3个总进程5个总进程7个总进程9个进程16个进程四:实验结果与分析(一)矩阵乘法并行化矩阵并行化算法分析:并行策略:1间隔行带划分法算法描述:将C=A*B中的A矩阵按行划分,从进程分得其中的几行后同时进行计算,最后通信将从进程的结果合并的主进程的C矩阵中对于矩阵A*B如图:进程1:矩阵A第一行进程2:矩阵A第二行进程3:矩阵A第三行进程1:矩阵A第四行时间复杂度分析:f(n) =6+2+8+k*n+k*n+k*n+3+10+n+k*n+k*n+n+2(k为从进程分到的行数)因此O(n)=(n);空间复杂度分析:从进程的存储空间不共用,f(n)=n;因此O(n)=(n);2间隔行带划分法算法描述:将C=A*B中的A矩阵按行划分,从进程分得其中的几行后同时进行计算,最后通信将从进程的结果合并的主进程的C矩阵中对于矩阵A*B如图:进程1:矩阵A第一行进程2:矩阵A第二行进程3:矩阵A第三行进程3:矩阵A第四行时间复杂度分析:f(n) =6+2+8+k*n+k*n+k*n+3+10+n+k*n+k*n+n+2(k为从进程分到的行数)因此O(n)=(n);空间复杂度分析:从进程的存储空间不共用,f(n)=n;因此T(n)=O(n);测试环境简介:《VS2013》Win7旗舰版正确性测试结果:并行结果:串行结果:通过比较发现两者相同,因此可以确定运算结果正确。

并行计算系统中的矩阵乘算法及其MPI实现

并行计算系统中的矩阵乘算法及其MPI实现


要 : 绍 了 MP 并 行 机 群 环 境 以及按 行 划 分矩 阵乘 算 法 和 按 行 列 划 分 矩 阵 乘 算 法 2种 算 法 , 析 了这 2种 矩 介 I 分
阵乘划分算法时间开销 的长短 , 并通过 MP 编程在 M I I P 并行机 群环境 下得 到 了实现 , 通过 实验得 到: 50X 0 在 0 0 5 规模的矩阵乘运算 中, 按行划分矩阵乘算法的 时问开销对矩阵乘并行计 算效 率的影响要 大于按 行列划分矩 阵乘 算
群 系统 的搭 建 需 要 使 用 相 应 的并 行 编程 环 境 。 目 前 并行编 程环 境 主 要 有并 行 虚拟 计 算 机 P M(a— V pr a e vta m cie , 息 传 递 接 口 MP ( sae ll iul ahn ) 消 l r I mesg
p si t fc ) E pesP Zpo e等 , 中 P M as gi e ae ,x rs,4,icd n nr 其 V
本文 以 MP 并行 机 群环 境 为基 础 , I 首先 介 绍 按
设 备 和操作 系统 , 它 们 工 作 时就 像 一个 统 一 的整 但 体, 各个 工作站 在并行 环境 下协调 工作 J 。
行划 分矩 阵乘算法 和按行 列划 分矩 阵乘算法 2种算
法, 然后分 析按行 划 分矩 阵乘 算 法 和按 行列 划 分 矩
成 为一种 单 一 的计 算 资源 来 使 用 的 系 统 。并 行 机
计算 机体 系结构 , 随着 微 处理 器 技 术 和计 算 机互 是 连 网络技术 的迅 速发 展 而 出现 的 , 实 现并 行 计算 是
的一 种新 主流技术 , 属于 分 布式 存 储 的并 行 计算 机 结构 , 型的机 群 系统结 构如 图 1 示 。机 群 系统 典 所

OpenMP的应用与实现

OpenMP的应用与实现

OpenMP的应用与实现OpenMP的应用与实现随着计算机技术的不断发展,程序员们需要在更短的时间内开发出更高效、更快速的程序,以满足现代科学和工程领域对计算的需求。

在多核处理器和集群系统的背景下,一种新的编程技术——OpenMP,应运而生。

OpenMP为C、C++和Fortran等语言提供了一种简单而有效的方式来并行化应用程序,可显著加速程序的执行速度。

本文将介绍OpenMP的应用与实现。

一、OpenMP的基本概念OpenMP是一种可移植、可扩展的共享内存并行编程技术,被广泛用于高性能计算应用中。

它可以在现有的串行代码中添加共享内存并行性,从而提高程序的效率。

OpenMP采用指令集合作,程序员可以通过在应用程序中添加特定的OpenMP指令,来控制并行执行的细节。

这些指令将告诉编译器如何将串行代码并行化。

OpenMP的并行模型是基于线程的共享内存模型。

线程是程序执行的最小单元,可以实现不同的计算任务同时运行。

OpenMP使用共享内存模型,即多个线程可以访问同一块内存,从而实现数据的共享。

为了保证数据的安全性,OpenMP提供了同步机制,可以保证共享资源的一致性和正确性。

二、OpenMP指令OpenMP定义了一系列指令,用于控制多线程的创建、同步和运行。

下面是一些常用的OpenMP指令:1. #pragma omp parallel该指令用于创建一个并行区域。

在这个区域内所有指令都会被多个线程执行。

当线程遇到这个指令时,会创建一个线程队列,然后每个线程会执行这个指令块内的内容。

2. #pragma omp for该指令用于循环并行化。

在多核处理器或者集群系统中,循环的迭代次数可以分配给不同的线程来并行执行,从而加速程序的执行速度。

3. #pragma omp sections该指令用于将代码分成多个段,每个段可以由不同的线程执行。

4. #pragma omp critical该指令用于保证在同一时间只有一个线程可以执行指定的代码块。

并行处理实验:矩阵乘法的加速比性能分析,用MPI实现源代码

并行处理实验:矩阵乘法的加速比性能分析,用MPI实现源代码

DenseMulMatrixMPI.c#include <stdio.h>#include <stdlib.h>#include <mpi.h>#include <time.h>//#include <windows.h>#define Length 1000int *A,*B,*C;//A、B、C一维数组分别记录矩阵A、B、C,以行优先的方式存储int *buffer,*ans;int temp;//临时变量,存储乘法过程中的中间值double startTime,endTime,totalTime;//startTime endTime totalTime分别表示矩阵乘之前的时间、之后的时间,以及矩阵乘所花费的时间int procsID,procsNum;//进程标识、进程个数int i,j,k;int line;//每个进程可以分配的矩阵行数//初始化矩阵/*void InitMatrix(int *M,int len){//产生0到49之间的随机数//int count=0;srand((unsigned)time( NULL));for(i=0; i < len; i++){for(j = 0; j < len; j ++){M[i * len + j] = rand() % 50;//if (M[i * len + j] < 20 )// M[i * len + j] = 0;}}//统计矩阵中非元素的个数,占的个数达总个数的50%以上的话即可认为是稠密矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]!=0)// count++;//}//printf("%d\n",count);}*/void InitMatrix(int *M,int len){//int count=0;srand((unsigned)time( NULL));for(i=0; i < len*len; i++){M[i] = rand() % 2;}//统计矩阵中非0元素的个数,占的个数达总个数的50%以上的话即可认为是稠密矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]!=0)// count++;//}//printf("%d\n",count);}int main(int argc,char *argv[]){MPI_Status status;MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD,&procsID);//获得当前进程号MPI_Comm_size(MPI_COMM_WORLD,&procsNum);//获得进程个数line = Length/procsNum;//将数据分为(进程数)个块,主进程也要处理数据A = (int*)malloc(sizeof(int)*Length*Length);B = (int*)malloc(sizeof(int)*Length*Length);C = (int*)malloc(sizeof(int)*Length*Length);//缓存大小大于等于要处理的数据大小,大于时只需关注实际数据那部分buffer = (int*)malloc(sizeof(int)*Length*line);//数据分组大小ans = (int*)malloc(sizeof(int)*Length*line);//保存数据块结算的结果//主进程对矩阵赋初值,并将矩阵B广播到各进程,将矩阵A分组广播到各进程if (procsID==0){//矩阵赋初值InitMatrix(A,Length);//Sleep(1000);//停顿1s,使得矩阵A和B产生的随机元素不一样(但是在命令窗口不识别它的头文件windows.h)InitMatrix(B,Length);startTime = MPI_Wtime();//将矩阵B发送给其他从进程for (i=1;i<procsNum;i++){MPI_Send(B,Length*Length,MPI_INT,i,0,MPI_COMM_WORLD);}//依次将A的各行发送给各从进程for (i=1;i<procsNum;i++){MPI_Send(A+(i-1)*line*Length,Length*line,MPI_INT,i,1,MPI_COMM_WORLD);}//接收从进程计算的结果for (k=1;k<procsNum;k++){MPI_Recv(ans,line*Length,MPI_INT,k,3,MPI_COMM_WORLD,&status);//将结果传递给数组Cfor (i=0;i<line;i++){for (j=0;j<Length;j++){C[((k-1)*line+i)*Length+j]=ans[i*Length+j];}}}//计算A剩下的数据for (i=(procsNum-1)*line;i<Length;i++){for (j=0;j<Length;j++){temp=0;for (k=0;k<Length;k++)temp += A[i*Length+k]*B[k*Length+j];C[i*Length+j]=temp;}}endTime = MPI_Wtime();totalTime=endTime-startTime;printf("并行稠密矩阵乘法过程总共花的时间:%.4fs\n",totalTime);}//其他进程接收数据,计算结果后,发送给主进程else{//接收广播的数据(矩阵N)MPI_Recv(B,Length*Length,MPI_INT,0,0,MPI_COMM_WORLD,&status);MPI_Recv(buffer,Length*line,MPI_INT,0,1,MPI_COMM_WORLD,&status);//计算乘积结果,并将结果发送给主进程for (i=0;i<line;i++){for (j=0;j<Length;j++){temp=0;for(k=0;k<Length;k++)temp += buffer[i*Length+k]*B[k*Length+j];ans[i*Length+j]=temp;}}//将计算结果传送给主进程MPI_Send(ans,line*Length,MPI_INT,0,3,MPI_COMM_WORLD);}MPI_Finalize();//结束return 0;}DenseMulMatrixSerial.c#include <stdio.h>#include <stdlib.h>#include <time.h>//#include <windows.h>#define Length 1000int *A,*B,*C;//A、B、C一维数组分别记录矩阵A、B、C,以行优先的方式存储int i,j,k;clock_t startTime, endTime;double totalTime;//初始化矩阵/*void InitMatrix(int *M,int len){//产生0到49之间的随机数//int count=0;srand((unsigned)time( NULL));for(i=0; i < len; i++){for(j = 0; j < len; j ++){M[i * len + j] = rand() % 50;//if (M[i * len + j] < 20 )// M[i * len + j] = 0;}}//统计矩阵中非元素的个数,占的个数达总个数的50%以上的话即可认为是稠密矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]!=0)// count++;//}//printf("%d\n",count);}*/void InitMatrix(int *M,int len){//int count=0;srand((unsigned)time( NULL));for(i=0; i < len*len; i++){M[i] = rand() % 2;}//统计矩阵中非0元素的个数,占的个数达总个数的50%以上的话即可认为是稠密矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]!=0)// count++;//}//printf("%d\n",count);}int main(){//矩阵A乘以矩阵B,结果为矩阵C,A、B、C均用一维的数组存储,有Length*Length个单元//动态为矩阵分配空间A = (int *)malloc(sizeof(int)*Length*Length);B = (int *)malloc(sizeof(int)*Length*Length);C = (int *)malloc(sizeof(int)*Length*Length);//初始化矩阵A BInitMatrix(A,Length);//Sleep(1000);//停顿1s,使得矩阵A和B中随机产生的元素不一样InitMatrix(B,Length);startTime = clock();//矩阵乘法过程for(i = 0; i < Length; i ++){for(j = 0; j < Length; j ++){C[i * Length + j] = 0;for (k = 0; k < Length; ++k){C[i * Length + j] += A[i * Length + k] * B[k * Length + j];}}}endTime = clock();//串行矩阵乘法总共用的时间totalTime = (double)(endTime - startTime) / CLOCKS_PER_SEC;printf("串行稠密矩阵乘法过程总共花的时间:%.4fs\n",totalTime);return 0;}SparseMulMatrixMPI.c#include <stdio.h>#include <stdlib.h>#include <mpi.h>#include <time.h>//#include <windows.h>#define Length 1000int *A,*B,*C;//A、B、C一维数组分别记录矩阵A、B、C,以行优先的方式存储int *buffer,*ans;int temp;//临时变量,存储乘法过程中的中间值double startTime,endTime,totalTime;//startTime endTime totalTime分别表示矩阵乘之前的时间、之后的时间,以及矩阵乘所花费的时间int procsID,procsNum;//进程标识、进程个数int i,j,k;int m,n;//统计矩阵中1时用int line;//每个进程可以分配的矩阵行数//初始化矩阵/*void InitMatrix(int *M,int len){//产生0 48 49 三个数//int count=0;srand((unsigned)time( NULL));for(i=0; i < len; i++){for(j = 0; j < len; j ++){M[i * len + j] = rand() % 50;if (M[i * len + j] < 48 )M[i * len + j] = 0;}}//统计矩阵中0元素的个数,占的个数小于总个数的5%的话即为稀疏矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]==0)// count++;//}//printf("%d\n",count);}*/void InitMatrix(int *M,int len){//根据稀疏矩阵非0元素少于总元素个数的5%的原则设置下面的程序,随机产生元素位置,令其位置上的元素为1,其余为0//int count=0;for(i=0;i<len*len;i++)M[i]=0;srand((unsigned)time( NULL));for(m=0;m<224;m++){for(n=0;n<224;n++){i=rand()%1000;j=rand()%1000;M[i*len+j]=1;}}//统计矩阵中0元素的个数,占的个数小于总个数的5%的话即为稀疏矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]==0)// count++;//}//printf("%d\n",count);}int main(int argc,char *argv[]){MPI_Status status;MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD,&procsID);//获得当前进程号MPI_Comm_size(MPI_COMM_WORLD,&procsNum);//获得进程个数line = Length/procsNum;//将数据分为(进程数)个块,主进程也要处理数据A = (int*)malloc(sizeof(int)*Length*Length);B = (int*)malloc(sizeof(int)*Length*Length);C = (int*)malloc(sizeof(int)*Length*Length);//缓存大小大于等于要处理的数据大小,大于时只需关注实际数据那部分buffer = (int*)malloc(sizeof(int)*Length*line);//数据分组大小ans = (int*)malloc(sizeof(int)*Length*line);//保存数据块结算的结果//主进程对矩阵赋初值,并将矩阵B广播到各进程,将矩阵A分组广播到各进程if (procsID==0){//矩阵赋初值InitMatrix(A,Length);//Sleep(1000);//停顿1s,使得矩阵A和B产生的随机元素不一样(但是在命令窗口不识别它的头文件windows.h)InitMatrix(B,Length);startTime = MPI_Wtime();//将矩阵B发送给其他从进程for (i=1;i<procsNum;i++){MPI_Send(B,Length*Length,MPI_INT,i,0,MPI_COMM_WORLD);}//依次将A的各行发送给各从进程for (i=1;i<procsNum;i++){MPI_Send(A+(i-1)*line*Length,Length*line,MPI_INT,i,1,MPI_COMM_WORLD);}//接收从进程计算的结果for (k=1;k<procsNum;k++){MPI_Recv(ans,line*Length,MPI_INT,k,3,MPI_COMM_WORLD,&status);//将结果传递给数组Cfor (i=0;i<line;i++){for (j=0;j<Length;j++){C[((k-1)*line+i)*Length+j]=ans[i*Length+j];}}}//计算A剩下的数据for (i=(procsNum-1)*line;i<Length;i++){for (j=0;j<Length;j++){temp=0;for (k=0;k<Length;k++)temp += A[i*Length+k]*B[k*Length+j];C[i*Length+j]=temp;}}endTime = MPI_Wtime();totalTime=endTime-startTime;printf("并行稀疏矩阵乘法过程总共花的时间:%.4fs\n",totalTime);}//其他进程接收数据,计算结果后,发送给主进程else{//接收广播的数据(矩阵N)MPI_Recv(B,Length*Length,MPI_INT,0,0,MPI_COMM_WORLD,&status);MPI_Recv(buffer,Length*line,MPI_INT,0,1,MPI_COMM_WORLD,&status);//计算乘积结果,并将结果发送给主进程for (i=0;i<line;i++){for (j=0;j<Length;j++){temp=0;for(k=0;k<Length;k++)temp += buffer[i*Length+k]*B[k*Length+j];ans[i*Length+j]=temp;}}//将计算结果传送给主进程MPI_Send(ans,line*Length,MPI_INT,0,3,MPI_COMM_WORLD);}MPI_Finalize();//结束return 0;}SparseMulMatrixSerial.c#include <stdio.h>#include <stdlib.h>#include <time.h>//#include <windows.h>#define Length 1000int *A,*B,*C;//A、B、C一维数组分别记录矩阵A、B、C,以行优先的方式存储int i,j,k;int m,n;//统计矩阵中1时用clock_t startTime, endTime;double totalTime;//初始化矩阵/*void InitMatrix(int *M,int len){//产生0 48 49 三个数//int count=0;srand((unsigned)time( NULL));for(i=0; i < len; i++){for(j = 0; j < len; j ++){M[i * len + j] = rand() % 50;if (M[i * len + j] < 48 )M[i * len + j] = 0;}}//统计矩阵中0元素的个数,占的个数小于总个数的5%的话即为稀疏矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]==0)// count++;//}//printf("%d\n",count);}*/void InitMatrix(int *M,int len){//根据稀疏矩阵非0元素少于总元素个数的5%的原则设置下面的程序,随机产生元素位置,令其位置上的元素为1,其余为0//int count=0;for(i=0;i<len*len;i++)M[i]=0;srand((unsigned)time( NULL));for(m=0;m<224;m++){for(n=0;n<224;n++){i=rand()%1000;j=rand()%1000;M[i*len+j]=1;}}//统计矩阵中0元素的个数,占的个数小于总个数的5%的话即为稀疏矩阵,因为矩阵元素是随机产生的所以只是大概估计//for(i=0; i < len*len; i++){// if(M[i]==0)// count++;//}//printf("%d\n",count);}int main(){//矩阵A乘以矩阵B,结果为矩阵C,A、B、C均用一维的数组存储,有Length*Length个单元//动态为矩阵分配空间A = (int *)malloc(sizeof(int)*Length*Length);B = (int *)malloc(sizeof(int)*Length*Length);C = (int *)malloc(sizeof(int)*Length*Length);//初始化矩阵A BInitMatrix(A,Length);//Sleep(1000);//停顿1s,使得矩阵A和B中随机产生的元素不一样InitMatrix(B,Length);startTime = clock();//矩阵乘法过程for(i = 0; i < Length; i ++){for(j = 0; j < Length; j ++){C[i * Length + j] = 0;for (k = 0; k < Length; ++k){C[i * Length + j] += A[i * Length + k] * B[k * Length + j];}}}endTime = clock();//串行矩阵乘法总共用的时间totalTime = (double)(endTime - startTime) / CLOCKS_PER_SEC;printf("串行稀疏矩阵乘法过程总共花的时间:%.4fs\n",totalTime);return 0;}附:另一种矩阵初始化的办法//稠密矩阵的生成方法void InitMatrix(int *M,int *N,int len){srand((unsigned)time( NULL));for(i=0; i < len*len; i++){M[i] = rand() % 2;}for(i=0;i<len;i++){for(j=0;j<len;j++){N[i*len+j]=M[j*len+i];}}}//稀疏矩阵的生成方法void InitMatrix(int *M, int *N, int len){for(i=0;i<len*len;i++)M[i]=0;srand((unsigned)time( NULL));for(m=0;m<224;m++){for(n=0;n<224;n++){i=rand()%len;j=rand()%len;M[i*len+j]=1;}}for(i=0;i<len;i++){for(j=0;j<len;j++){N[i*len+j]=M[j*len+i];}}}。

并行计算实验报告(高性能计算与网格技术)

并行计算实验报告(高性能计算与网格技术)

并行计算实验报告(高性能计算与网格技术)高性能计算和网格技术实验报告实验题目OpenMP和MPI编程姓名学号专业计算机系统结构指导教师助教所在学院计算机科学与工程学院论文提交日期一、实验目的本实验的目的是通过练习掌握OpenMP 和MPI 并行编程的知识和技巧。

1、熟悉OpenMP 和MPI 编程环境和工具的使用;2、掌握并行程序编写的基本步骤;3、了解并行程序调试和调优的技巧。

二、实验要求1、独立完成实验内容;2、了解并行算法的设计基础;3、熟悉OpenMP和MPI的编程环境以及运行环境;4、理解不同线程数,进程数对于加速比的影响。

三、实验内容3.1、矩阵LU分解算法的设计:参考文档sy6.doc所使用的并行算法:在LU分解的过程中,主要的计算是利用主行i对其余各行j,(j>i)作初等行变换,各行计算之间没有数据相关关系,因此可以对矩阵A 按行划分来实现并行计算。

考虑到在计算过程中处理器之间的负载均衡,对A采用行交叉划分:设处理器个数为p,矩阵A的阶数为n,??p=,对矩阵A行交叉划分后,编号为i(i=0,1,…,p-1)的处理器存有m/nA的第i, i+p,…, i+(m-1)p行。

然后依次以第0,1,…,n-1行作为主行,将其广播给所有处理器,各处理器利用主行对其部分行向量做行变换,这实际上是各处理器轮流选出主行并广播。

若以编号为my_rank 的处理器的第i行元素作为主行,并将它广播给所有处理器,则编号大于等于my_rank的处理器利用主行元素对其第i+1,…,m-1行数据做行变换,其它处理器利用主行元素对其第i,…,m-1行数据做行变换。

根据上述算法原理用代码表示如下(关键代码):for(k = 0;k<n;k++)< p="">{for (i = 0; i < THREADS_NUM; i++) {thread_data_arrray[i].thread_id = i;thread_data_arrray[i].K_number = k;thread_data_arrray[i].chushu = a[k][k];//创建线程rc = pthread_create(&pid[i], NULL, work,(void*)&thread_data_arrray[i]);…}for (i = 0; i < THREADS_NUM; i++){//等待线程同步rc = pthread_join(pid[i], &ret); …}}void *work(void *arg){struct thread_data *my_data;my_data = (struct thread_data*)arg;int myid = my_data->thread_id; //线程IDint myk = my_data->K_number; //外层循环计数Kfloat mychushu = my_data->chushu; //对角线的值int s, e;int i, j;s = (N-myk-1) * myid / THREADS_NUM; //确定起始循环的行数的相对位置e = (N-myk-1) * (myid + 1) / THREADS_NUM;//确定终止循环的行数的相对位置for (i = s+myk+1; i < e+myk+1; i++) //由于矩阵规模在缩小,找到偏移位置 { a[i][myk]=a[i][myk]/mychushu; for (j = myk+1; j < N; j++) a[i][j]=a[i][j]-a[i][myk]*a[myk][j]; }//printMatrix(a); return NULL;}第一部分为入口函数,其创建指定的线程数,并根据不同的线程id 按行划分矩阵,将矩阵的不同部分作为参数传递给线程,在多处理器电脑上,不同的线程并行执行,实现并行计算LU 分解。

并行计算实验报告

并行计算实验报告

分析 :这样的加速比 , 是符合预测 , 很好的 . 附 :(实验 源码 ) 1 pi.cpp #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cmath> #include <ctime> #include <cassert>
#include <climits> #include <iostream> #include <iomanip> #include <string> #include <vector> #include <set> #include <map> #include <queue> #include <deque> #include <bitset> #include <algorithm> #include <omp.h> #define MST(a, b) memset(a, b, sizeof(a)) #define REP(i, a) for (int i = 0; i < int(a); i++) #define REPP(i, a, b) for (int i = int(a); i <= int(b); i++) #define NUM_THREADS 4 using namespace std; const int N = 1e6; double sum[N]; int main() { ios :: sync_with_stdio(0); clock_t st, ed; double pi = 0, x; //串行 st = clock(); double step = 1.0 / N; REP(i, N) { x = (i + 0.5) * step; pi += 4.0 / (1.0 + x * x); } pi /= N; ed = clock(); cout << fixed << setprecision(10) << "Pi: " << pi << endl; cout << fixed << setprecision(10) << "串行用时: " << 1.0 * (ed - st) / CLOCKS_PER_SEC << endl; //并行域并行化 pi = 0; omp_set_num_threads(NUM_THREADS); st = clock(); int i; #pragma omp parallel private(i) { double x; int id; id = omp_get_thread_num();
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

深圳大学
实验报告
课程名称:并行计算
实验名称:矩阵乘法的OpenMP实现及性能分析姓名:
学号:
班级:
实验日期:2011年10月21日、11月4日
一. 实验目的
1) 用OpenMP 实现最基本的数值算法“矩阵乘法” 2) 掌握for 编译制导语句 3) 对并行程序进行简单的性能
二. 实验环境
1) 硬件环境:32核CPU 、32G 存计算机;
2) 软件环境:Linux 、Win2003、GCC 、MPICH 、VS2008;
4) Windows 登录方式:通过远程桌面连接192.168.150.197,用户名和初始密码都是自己的学号。

三. 实验容
1. 用OpenMP 编写两个n 阶的方阵a 和b 的相乘程序,结果存放在方阵c 中,其中乘法用for 编译制导语句实现并行化操作,并调节for 编译制导中schedule 的参数,使得执行时间最短,写出代码。

方阵a 和b 的初始值如下:
⎥⎥⎥⎥⎥⎥⎥⎥⎦

⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡-++++=12,...,2,1,..2,...,5,4,31,...,4,3,2,...,3,2,1n n n n n n n a ⎥⎥⎥⎥⎥⎥⎥⎥

⎤⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡=
1,...,1,1,1..1,...,1,1,11,...,1,1,11,...,
1,1,1b 输入:
方阵的阶n 、并行域的线程数 输出:
c 中所有元素之和、程序的执行时间 提示:
a,b,c 的元素定义为int 型,c 中所有元素之各定义为long long 型。

Windows 计时:
用<time.h>中的clock_t clock( void )函数得到当前程序执行的时间 Linux 计时:
#include <sys/time.h>
timeval start,end;
gettimeofday(&start,NULL);
gettimeofday(&end,NULL);
cout<<"execution time:"<< (__sec)+(double)(__usec)/
1000000<<"seconds" <<endl;
答:
在windows下使用Microsofe Visual Studio编程,源代码如下:
#include<omp.h>
#include<stdio.h>
#include<time.h>
#define NN 2000
int a[NN][NN], b[NN][NN];
long long c[NN][NN];
void solve(int n, int num_thread)
{
int i, j, t, k, time;
clock_t startTime, endTime;
long long sum;
omp_set_num_threads(num_thread);
for(i=0;i<n;i++)//对矩阵a和矩阵b进行初始化
{
t=i+1;
for(j=0;j<n;j++)
{
a[i][j]=t++;
b[i][j]=1;
}
}
startTime=clock();
sum=0;
#pragma omp parallel shared(a,b,c) private(i,j,k)
{
#pragma omp for schedule(dynamic)
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
c[i][j]=0;
for(k=0;k<n;k++)
{
c[i][j]+=a[i][k]*b[k][j];
}
}
}
}
for(i=0;i<n;i++)for(j=0;j<n;j++) sum+=c[i][j];
endTime=clock();
time=endTime-startTime;
printf("sum=%lld time=%dms\n",sum,time);
}
int main()
{
int n, num_thread;
while(scanf("%d%d",&n,&num_thread)!=EOF)
{
solve(n,num_thread);
}
return 0;
}
2.分析矩阵相乘程序的执行时间、加速比和效率:方阵阶固定为1000,节点数分别取1、2、4、8、16和32时,为减少误差,每项实验进行5次,取平均值作为实验结果。

答:串行执行时程序的执行时间为:T = 15.062s
加速比=顺序执行时间/并行执行时间
效率=加速比/节点数
表1 不同节点数下程序的执行时间(秒)
节点数
1 2 4 8 16 32
实验结果
第1次16.640 8.172 4.078 2.125 1.093 0.594
第2次16.422 8.156 4.172 2.141 1.078 0.578
第3次16.406 8.266 4.078 2.125 1.094 0.563
第4次16.781 8.172 4.079 2.109 1.094 0.563
第5次16.422 8.171 4.078 2.125 1.093 0.578
平均值16.5342 8.1874 4.0970 2.1250 1.0904 0.5752 Array
图1 不同节点数下程序的执行时间
图2 不同节点数下程序的加速比
图3 不同节点数下程序的效率
执行时间的分析:
随着节点数的增加,程序的执行时间减少,大概可以从结果中得出,随着节点书的增加一倍,执行时间减少一半
加速比的分析:
随着节点数的增加,程序的加速比增加,大概可以从结果中得出,随着节点书的增加一倍,加速相应的增加接近一倍
效率的分析:
随着节点数的增加,程序的效率逐渐减少
3.分析矩阵相乘程序的问题规模与效率的关系:固定节点数为4,让方阵阶从200到1600之间变化,每隔100取一个值。

(为了减少时间,每项实验可只执行1次)
答:
表2 相同节点数下不同问题规模程序的执行时间与效率
方阵阶数并行执
行时间
串行执
行时间
效率
200 0.015 0.047 0.783333 300 0.016 0.109 1.703125 400 0.063 0.297 1.178571 500 0.156 0.657 1.052885 600 0.406 1.64 1.009852 700 0.907 3.578 0.986218 800 1.609 6.36 0.988191 900 2.578 10.109 0.980314 1000 3.812 14.891 0.976587 1100 5.39 21.032 0.97551 1200 7.344 28.734 0.978145 1300 9.688 37.937 0.978969 1400 12.422 48.64 0.978908 1500 15.656 60.938 0.973077 1600 19.234 74.829 0.972614
图3.1 不同问题规模下程序的效率
问题规模与效率的关系分析:
随着问题规模的增加,程序的效率趋于稳定,但是略微有点下降。

相关文档
最新文档