Параллельный цикл в openmp
Я пытаюсь распараллелить очень простой for-loop, но это моя первая попытка использовать openMP за долгое время. Меня поражает время работы. Вот мой код:
#include <vector>
#include <algorithm>
using namespace std;
int main ()
{
int n=400000, m=1000;
double x=0,y=0;
double s=0;
vector< double > shifts(n,0);
#pragma omp parallel for
for (int j=0; j<n; j++) {
double r=0.0;
for (int i=0; i < m; i++){
double rand_g1 = cos(i/double(m));
double rand_g2 = sin(i/double(m));
x += rand_g1;
y += rand_g2;
r += sqrt(rand_g1*rand_g1 + rand_g2*rand_g2);
}
shifts[j] = r / m;
}
cout << *std::max_element( shifts.begin(), shifts.end() ) << endl;
}
Я скомпилирую его с помощью
g++ -O3 testMP.cc -o testMP -I /opt/boost_1_48_0/include
то есть "-fopenmp", и я получаю эти тайминги:
real 0m18.417s
user 0m18.357s
sys 0m0.004s
когда я использую "-fopenmp",
g++ -O3 -fopenmp testMP.cc -o testMP -I /opt/boost_1_48_0/include
Я получаю эти числа за время:
real 0m6.853s
user 0m52.007s
sys 0m0.008s
что для меня не имеет смысла. Как использование восьми ядер может привести только к 3-кратным
повышение производительности? Я правильно кодирую цикл?
Ответы
Ответ 1
Вы должны использовать предложение OpenMP reduction
для x
и y
:
#pragma omp parallel for reduction(+:x,y)
for (int j=0; j<n; j++) {
double r=0.0;
for (int i=0; i < m; i++){
double rand_g1 = cos(i/double(m));
double rand_g2 = sin(i/double(m));
x += rand_g1;
y += rand_g2;
r += sqrt(rand_g1*rand_g1 + rand_g2*rand_g2);
}
shifts[j] = r / m;
}
При reduction
каждый поток накапливает свою собственную частичную сумму в x
и y
, и в конце все частичные значения суммируются вместе, чтобы получить окончательные значения.
Serial version:
25.05s user 0.01s system 99% cpu 25.059 total
OpenMP version w/ OMP_NUM_THREADS=16:
24.76s user 0.02s system 1590% cpu 1.559 total
См. - сверхлинейное ускорение:)
Ответ 2
попытайтесь понять, как распараллеливать простой цикл, используя OpenMP
#pragma omp parallel
#pragma omp for
for(i = 1; i < 13; i++)
{
c[i] = a[i] + b[i];
}
предположим, что у нас есть 3
доступные потоки, вот что произойдет
![введите описание изображения здесь]()
во-первых
- В потоках назначается независимый набор итераций
и, наконец,
- Потоки должны подождать в конце конструкции совместного использования.
Ответ 3
То, что вы можете достичь максимум (!), - это линейное ускорение.
Теперь я не помню, какой из них имеет время от linux, но я бы предложил вам использовать time.h или (в С++ 11) "chrono" и измерить время выполнения непосредственно из программы. Лучше всего поместить весь код в цикл, запустите его 10 раз и усредним, чтобы получить прогр. Время выполнения.
Кроме того, у вас есть проблема с x, y - которые не придерживаются парадигмы локальности данных в параллельном программировании.