一. 实验目的
1. 学会编写简单的OpenMP程序;
2. 掌握for编译制导语句;
3. 对并行程序进行简单的性能分析。
二. 实验环境
1. 硬件环境:64核CPU、128GB内存的SMP并行计算平台;
2 软件环境:Microsoft Visual Studio 2013;
三. 实验内容
1. 用OpenMP语言编写程序,求小于等于n的所有完数(一个数恰好等于它的因子之和),并存放在数组a中,调节for编译制导语句中schedule的参数,使得执行时间最短。为了验证计算结果的正确性,将串行计算结果存放在数组b中,并比较是否与c相等。在下面写出完整的程序代码,并添加必要的注释。
#include <omp.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;
const int n = 5000000;
int b[5];
int number = 0, number2 = 0;
int c1, c2;
double chuanxing, bingxing[5];
bool judge(int p) {
//判断变量 k
int k = 1;
//边界变量 max_p
int max_p = (int)(sqrt(double(p)) + 1);
for (int i = 2;i < max_p;i++) {
if (p % i == 0) {
k += i+p/i;
}
}
if (k == p) {
return true;
}
else
return false;
}
int main() {
cout << "--------------------------------------串行计算---------------------------------" << endl;
clock_t start1 = clock();
for (int p = 2;p <= n;p++) {
if (judge(p)) {
b[number] = p;
number++;
//cout << p << endl;
}
}
clock_t end1 = clock();
chuanxing = (end1 - start1) / 1000.0;
cout << "串行消耗时间为:" << chuanxing << "秒" << endl;
int hthreads = 1;//线程数变量
for (int pi = 0;pi < 7;pi++) {//每次线程数*2,循环七次
cout << "+++++++++++++++++++++++++++++++线程数为" << hthreads << "时:++++++++++++++++++++++++" << endl;
for (int h = 0;h < 5;h++) {//每次循环五次
int a[5];
cout << "---------------------第" << h + 1 << "次并行计算:----------------------" << endl;
omp_set_num_threads(hthreads);//设置并行线程数
clock_t start = clock();//记录并行执行起始时间
int i, j = 1, k = 0, p;
//以下是并行域,共享变量为a,b数组,私有变量是i,j,p shared(b,a) private(i,p,j)
#pragma omp parallel shared(b,a) private(i,p,j)
{
#pragma omp for schedule(static,100) //对以下for循环进行并行线程分配 调度任务块大小为100
for (p = 2;p <= n;p++) {
int max_p = (int)(sqrt(double(p)) + 1);
for (i = 2;i < max_p;i++) {
if (p % i == 0)
j += i + p / i;
}
if (j == p) {
a[number2] = p;
//原子操作防止写入错误
#pragma omp atomic
number2++;
j = 1;
}
else
j = 1;
}
}
clock_t end = clock();
//打印结果,并计算所记录的时间、加速比
bingxing[h] = (end - start) / 1000.0;
cout << "并行消耗时间为:" << bingxing[h] << "秒" << endl;
cout << "加速比为" << chuanxing / bingxing[h] << endl;
//遍历查看是否有不一致计算结果
for (int i = 0, j = 0;i < number, j < number2;i++, j++) {
c1 += a[i];
c2 += b[i];
}
if (c1!=c2)
{
cout << "number=" << number << " number2=" << number2 << endl;
cout << "c1="<<c1<<" c2="<<c2 << endl;
cout << "不相同" << endl;
exit(0);
}
number2 = 0;
}
//线程数*2
hthreads *= 2;
//遍历并计算串行、并行执行时间以及加速比的平均值
double average = { 0 };
for (int i = 0;i < 5;i++) {
average += bingxing[i];
}
average /= 5.0;
cout << "-----------------------------------------" << endl;
cout << "并行平均时间为:" << average << "秒" << endl;
cout << "平均加速比为" << chuanxing / average << endl;
cout << "-----------------------------------------" << endl;
}
}
2. 测试并行程序在不同线程数下的执行时间和加速比(串行执行时间/并行执行时间),并分析实验结果。其中,n固定为5000000,线程数分别取1、2、4、8、16、32、64时,为减少误差,每项实验进行5次,取平均值作为实验结果。
表1 并行程序在不同线程数下的执行时间(秒)和加速比
线程数 执行时间 |
1 |
2 |
4 |
8 |
16 |
32 |
64 |
第1次 |
27.646 |
16.545 |
16.906 |
12.552 |
11.953 |
11.427 |
11.4 |
第2次 |
27.724 |
16.517 |
16.581 |
12.345 |
11.973 |
11.402 |
11.278 |
第3次 |
27.698 |
17.019 |
16.589 |
12.339 |
11.91 |
11.906 |
11.449 |
第4次 |
27.798 |
17.391 |
17.228 |
12.646 |
12.064 |
12.019 |
11.577 |
第5次 |
27.657 |
19.385 |
14.939 |
12.523 |
11.977 |
11.628 |
10.898 |
平均值 |
27.705 |
17.371 |
16.449 |
12.481 |
11.976 |
11.676 |
11.320 |
加速比 |
0.913 |
1.456 |
1.538 |
2.03 |
2.113 |
2.167 |
2.235 |


