我正在使用OpenMP来获得具有接近线性加速的算法。 不幸的是我注意到我无法获得所需的加速。
因此,为了理解我的代码中的错误,我编写了另一个代码,一个简单的代码,只是为了仔细检查加速是否原则上可以在我的硬件上获得。
这是我写的玩具示例:
#include <omp.h>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <algorithm>
#include "mkl.h"
int main () {
int number_of_threads = 1;
int n = 600;
int m = 50;
int N = n/number_of_threads;
int time_limit = 600;
double total_clock = omp_get_wtime();
int time_flag = 0;
#pragma omp parallel num_threads(number_of_threads)
{
int thread_id = omp_get_thread_num();
int iteration_number_local = 0;
double *C = new double[n]; std::fill(C, C+n, 3.0);
double *D = new double[n]; std::fill(D, D+n, 3.0);
double *CD = new double[n]; std::fill(CD, CD+n, 0.0);
while (time_flag == 0){
for (int i = 0; i < N; i++)
for(int z = 0; z < m; z++)
for(int x = 0; x < n; x++)
for(int c = 0; c < n; c++){
CD[c] = C[z]*D[x];
C[z] = CD[c] + D[x];
}
iteration_number_local++;
if ((omp_get_wtime() - total_clock) >= time_limit)
time_flag = 1;
}
#pragma omp critical
std::cout<<"I am "<<thread_id<<" and I got" <<iteration_number_local<<"iterations."<<std::endl;
}
}
我想再次强调,这段代码只是一个试图看到加速的玩具示例:当并行线程数增加时(由于N减少),第一个for-cycle变得更短。
但是,当我从1到2-4个线程时,迭代次数会按预期加倍;但是当我使用8-10-20个线程时情况并非如此:迭代次数不随线程数线性增加。
你可以帮我解决这个问题吗?代码是否正确?我应该期待接近线性的加速吗?结果
运行上面的代码我得到了以下结果。
1个帖子:23个迭代。
20个线程:每个线程397-401次迭代(而不是420-460)。
答案 0 :(得分:1)
您的测量方法是错误的。特别是对于少量的迭代。
1个线程:3次迭代。
3报告的迭代实际上意味着 2次迭代在不到120秒内完成。第三个花了更长的时间。 1次迭代的时间在40到60秒之间。
2个线程:每个线程5次迭代(而不是6次)。
4次迭代在不到120秒内完成。 1次迭代的时间在24到30秒之间。
20个线程:每个线程40-44次迭代(而不是60次)。
40次迭代在不到120秒内完成。 1次迭代的时间在2.9到3秒之间。
正如您所看到的,您的结果实际上并不与线性加速相矛盾。
简单地执行和计时一个外部循环会更加简单和准确,您可能会看到几乎完美的线性加速。
为什么你没有看到线性加速的一些原因(非详尽无遗)是:
n = 1000
的玩具示例中并非如此。更一般地说:争用共享资源(主内存,缓存,I / O)。从您的玩具示例中,我会说您可以通过更好地使用高级抽象来改进您的OpenMP方法,例如: for
。
对于此格式,更广泛的建议过于宽泛,需要有关非玩具示例的更具体信息。
答案 1 :(得分:0)
你在并行区域内做了一些声明,这意味着你将分配记忆并填写number_of_threads次。相反,我建议你:
double *C = new double[n]; std::fill(C, C+n, 3.0);
double *D = new double[n]; std::fill(D, D+n, 3.0);
double *CD = new double[n]; std::fill(CD, CD+n, 0.0);
#pragma omp parallel firstprivate(C,D,CD) num_threads(number_of_threads)
{
int thread_id = omp_get_thread_num();
int iteration_number_local = 0;
}
您的硬件的线程数量有限,这取决于处理器的核心数量。你可能有2或4个核心。
并行区域不会加快代码速度。使用open openMP,您应该使用#omp parallel来加速循环或
#pragma omp parallel
{
#pragma omp for
{
}
}
这种表示法相当于#pragma omp parallel for。它将使用多个线程(取决于您的硬件)来更快地继续for循环。 小心
#pragma omp parallel
{
for
{
}
}
将为每个线程创建整个for循环,这不会加速你的程序。
答案 2 :(得分:0)
你应该试试
#pragma omp parallel num_threads(number_of_threads)
{
int thread_id = omp_get_thread_num();
int iteration_number_local = 0;
double *C = new double[n]; std::fill(C, C+n, 3.0);
double *D = new double[n]; std::fill(D, D+n, 3.0);
double *CD = new double[n]; std::fill(CD, CD+n, 0.0);
while (time_flag == 0){
#pragma omp for
for (int i = 0; i < N; i++)
for(int z = 0; z < m; z++)
for(int x = 0; x < n; x++)
for(int c = 0; c < n; c++)
CD[c] = C[z]*D[x];
iteration_number_local++;
if ((omp_get_wtime() - total_clock) >= time_limit)
time_flag = 1;
}
if(thread_id == 0)
iteration_number = iteration_number_local;
}
std::cout<<"Iterations= "<<iteration_number<<std::endl;
}