[英]Why OpenMP is slower than a sequential program for a simple reduction?
我正在嘗試在數組中查找元素的總和,如下所示。 但是,令人驚訝的是,OpenMP實現比順序實現慢。 我嘗試了堆分配和堆棧分配的數組,並得到了相似的結果。 任何幫助是極大的贊賞。
#include <iostream>
#include <omp.h>
int main() {
int N = 10000;
int * ary = new int[N];
for (int i = 0; i < N; i++) { input_file >> ary[i]; }
int sum = 0;
clock_t begin = clock();
for (int i = 0; i < N; i++) { sum += ary[i]; }
clock_t end = clock();
cout << sum;
double elapsed_time = double(end - begin) / CLOCKS_PER_SEC;
sum = 0;
begin = clock();
#pragma omp parallel
{
int thread_id = omp_get_thread_num();
int total_threads = omp_get_num_threads();
int elem_per_thread = N / total_threads;
int base = thread_id * elem_per_thread;
int internal_sum = 0;
for (int i = base; i < (base + elem_per_thread); i++) {
internal_sum += ary[i];
}
#pragma omp critical
{
sum += internal_sum;
}
}
end = clock();
cout << sum;
elapsed_time = double(end - begin) / CLOCKS_PER_SEC;
}
順序程序需要5e-06
(s)才能完成,而並行程序則需要0.001733
(s)。 我正在使用g++ -std=c++11 main.cpp -fopenmp -O3 && ./a.out
在Ubuntu 16.04上進行編譯
順序程序可以優化為無所事事。 這是因為唯一副作用是價值sum
,和值sum
是不是在你的程序觀察。
使用OpenMP時,復雜的線程處理使編譯器無法意識到您沒有做任何事情。
避免這種情況的一種簡單方法是增加return sum;
現在,它顯示為可觀察到的退出代碼,因此無法優化計算。
現在,編譯器仍然可以自由地從不分配ary
,因為它可以證明ary[i]==i
代表所有i
,並將讀取的ary[i]
替換為i
,然后在編譯時計算出i
的總和1
到10000
是50005000
,消除整個循環並使其sum=50005000
仍需要零時間。
事先說明:
我相信處理“手動”划分循環的方式會適得其反(除非您想了解OpenMP的工作原理)。 這就是為什么我首先建議您對reduction
操作使用更標准的方法。 您始終可以檢查它是否在性能方面得到相同的結果。
另一個omp_
是,在整個代碼中使用omp_
函數將無法在沒有-openmp
選項的情況下對其進行編譯。
替補
因此,我使用了以下代碼:
標頭
#include <iostream>
#include <fstream>
#include <omp.h>
#include <cmath>
#include <chrono>
#include <iomanip>
。 一個非常簡單的添加操作即可測試功能
void test_simple(long long int N, int * ary, double & sum, long long int & elapsed_milli)
{
std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
start = std::chrono::system_clock::now();
double local_sum = 0.0;
#pragma omp parallel
{
#pragma omp for reduction(+:local_sum)
for (long long int i = 0; i < N; i++) {
local_sum += ary[i];
}
}
sum = local_sum;
end = std::chrono::system_clock::now();
elapsed_milli = std::chrono::duration_cast<std::chrono::microseconds>
(end-start).count();
}
。 具有復雜的CPU密集型操作符號的測試函數(x)atan(sqrt(cos(x)^ 2 + sin(0.5x)^ 2)
void test_intensive(long long int N, int * ary, double & sum, long long int & elapsed_milli)
{
std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
start = std::chrono::system_clock::now();
double local_sum = 0.0;
#pragma omp parallel
{
double c, s;
#pragma omp for reduction(+:local_sum)
for (long long int i = 0; i < N; i++) {
c = cos(double(ary[i]));
s = sin(double(ary[i])*0.5);
local_sum += atan(sqrt(c*c+s*s));
}
}
sum = local_sum;
end = std::chrono::system_clock::now();
elapsed_milli = std::chrono::duration_cast<std::chrono::microseconds>
(end-start).count();
}
。 主功能
using namespace std;
int main() {
long long int N = 1073741825,i;
int * ary = new int[N];
srand (0);
for (i = 0; i < N; i++) { ary[i] = rand()-RAND_MAX/2; }
double sum = 0.0;
sum = 0.0;
long long int elapsed_milli;
cout <<"#"<<setw(19)<<"N"<<setw(20)<<"µs"<< endl;
for(i=128; i<N; i=i*2)
{
test_intensive(i, ary, sum, elapsed_milli);
//test_simple(i, ary, sum, elapsed_milli);
cout << setw(20)<<i<<setw(20)<<elapsed_milli << setw(20)<<sum<<endl;
}
}
編譯(使用icpc)
順序(無OpenMP)版本使用以下命令進行編譯:
icpc test_omp.cpp -O3 --std=c++0x
OpenMP(OpenMP)版本使用以下命令進行編譯:
icpc test_omp.cpp -O3 --std=c++0x -openmp
測量
時間測量與完成chrono
使用high_precision_clock
和我的機器上的極限精度為微秒,因此使用std::chrono::microseconds
(無點尋找更高的精度)
得出結論
#pragma omp
越過),因為必須將池線程設置在適當的位置。 test_
函數(i = 128)時仔細研究“密集型案例”,則在OpenMP案例中的時間成本要比在No OpenMP案例中的時間成本高得多。 在第二次調用中(i = 256),我們沒有看到使用OpenMP的好處,但是時間安排是一致的。 我們可以看到,使用少量樣本就不會觀察到可伸縮性。 在簡單的測試案例中,這一點更加清楚。 換句話說,並行部分中的操作量必須足夠高,以使線程池管理所需的時間可以忽略 。 否則,將操作分為線程是沒有意義的。
在這種情況下(使用我使用的處理器),最小樣本數大約為100000。但是,如果我使用256個線程,則肯定大約為6000000。
摘要
#pragma omp for
應該始終位於最外層的“可能”循環中的原因。 正如Max Langhof和user463035818所建議的那樣,該程序受內存限制。 我更改了程序,以完成除累積以外的其他操作。 也就是說,我將sum += ary[i]
更改為sum += (pow(ary[i], 1.1) + pow(ary[i], 1.2)) / 100000000.0
並在並行程序中執行了相同的更改並測量時間。 並行程序的速度提高了2倍。 如果該程序受IO限制,我想我不能做很多事情來使它與OpenMP一起更快。 否則,請告訴我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.