一. 实验目的
1. 学会编写简单的OpenMP程序;
2. 掌握for编译制导语句;
3. 对并行程序进行简单的性能分析;
二. 实验环境
1. 硬件环境:64核CPU、128GB内存的SMP并行计算平台;
2 软件环境:Microsoft Visual Studio 2013;
3. 登录方式:通过远程桌面(mstsc)连接172.31.226.180或hpc.szu.edu.cn:805,用户名和初始密码都是自己的学号。
三. 实验内容
1. 用OpenMP编写两个n阶方阵a和b的并行相乘程序,结果存放在方阵c中,其中矩阵乘法部分用for编译制导语句实现并行化操作。为了验证计算结果的正确性,将矩阵乘法的串行计算结果存放在方阵d中,并比较是否与c相等。在下面写出完整的程序代码,并添加必要的注释。
#include <omp.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;
const int n = 1000;
double a[n][n], b[n][n], c[n][n], d[n][n];
double chuanxing[5], bingxing[5];//记录串行执行时间与并行执行时间
void main()
{
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
a[i][j] = rand() * 1.0 / RAND_MAX;
b[i][j] = rand() * 1.0 / RAND_MAX;
}
int hthreads=1;//线程数变量
for (int pi = 0;pi < 7;pi++) {//每次线程数*2,循环七次
printf("线程数为%d时:\n", hthreads);
for (int h = 0;h < 5;h++) {//每次循环五次
clock_t start1 = clock();//记录串行执行时间起始
for (int i = 0;i < n;i++) {//串行矩阵运算
for (int j = 0;j < n;j++) {
for (int k = 0;k < n;k++)
d[i][j] += a[i][k] * b[k][j];
}
}
clock_t end1 = clock();
omp_set_num_threads(hthreads);//设置并行线程数
clock_t start = clock();//记录并行执行起始时间
int i, j, k;
//以下是并行域,共享变量为a,b,c数组,私有变量是i,j,k
#pragma omp parallel shared(a,b,c) private(i,j,k)
{
#pragma omp for //对以下for循环进行并行线程分配
for (i = 0;i < n;i++) {
for (j = 0;j < n;j++) {
for (k = 0;k < n;k++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
}
clock_t end = clock();
//打印结果,并计算所记录的时间、加速比
printf("---------------------第%d次:----------------------\n", h+1);
bingxing[h] = (end - start) / 1000.0;
chuanxing[h] = (end1 - start1) / 1000.0;
printf("串行消耗时间为:%f秒\n", chuanxing[h]);
printf("并行消耗时间为:%f秒\n", bingxing[h]);
printf("加速比为%f\n", chuanxing[h] / bingxing[h]);
//遍历查看是否有不一致计算结果
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
if (c[i][j] != d[i][j])
{
printf("c[%d][%d]=%f,d[%d][%d]=%f ", i, j, c[i][j], i, j, d[i][j]);
printf("不相同\n");
exit(0);
}
}
}
}
//线程数*2
hthreads *= 2;
//遍历并计算串行、并行执行时间以及加速比的平均值
double average[2] = { 0,0 };
for (int i = 0;i < 5;i++) {
average[0] += chuanxing[i];
average[1] += bingxing[i];
}
average[0] /= 5.0;
average[1] /= 5.0;
printf("-------------------------------------------------\n");
printf("串行平均时间为:%f秒\n", average[0]);
printf("并行平均时间为:%f秒\n", average[1]);
printf("平均加速比为%f\n", average[0] / average[1]);
printf("-------------------------------------------------\n");
}
}
2. 测试并行程序在不同线程数下的执行时间和加速比(串行执行时间/并行执行时间),并分析实验结果。其中,n固定为1000,线程数分别取1、2、4、8、16、32、64时,为减少误差,每项实验进行5次,取平均值作为实验结果。
表1 并行程序在不同线程数下的执行时间(秒)和加速比
线程数 执行时间 |
1 |
2 |
4 |
8 |
16 |
32 |
64 |
第1次 |
4.438 |
2.609 |
2.472 |
2.333 |
2.281 |
2.269 |
2.331 |
第2次 |
4.420 |
2.718 |
2.408 |
2.326 |
2.306 |
2.288 |
2.270 |
第3次 |
4.393 |
3.095 |
2.410 |
2.326 |
2.293 |
2.271 |
2.259 |
第4次 |
4.448 |
2.703 |
2.355 |
2.286 |
2.293 |
2.305 |
2.260 |
第5次 |
4.431 |
2.727 |
2.447 |
2.341 |
2.303 |
2.262 |
2.264 |
平均值 |
4.426 |
2.770 |
2.418 |
2.322 |
2.295 |
2.279 |
2.276 |
加速比 |
0.852 |
1.332 |
1.523 |
1.580 |
1.650 |
1.609 |
1.616 |