複数のスレッドを使用するために OpenMP ディレクティブを使い始めたところです。ただし、このコードは、シングル スレッド バージョンを使用した場合に最も速く実行されます。私の目には、計算が独立しているため、アルゴリズムは適切にスケーリングされるはずです。ここで何が起こっているのですか?コードを改善するにはどうすればよいですか?
#include <omp.h>
std::vector<Track> interpolateTracks(const std::vector<Track>& tracks, double segmentLength) {
typedef std::vector<Track>::const_iterator iterator;
std::vector<Track> list;
#pragma omp parallel shared(list, tracks, segmentLength)
{
std::vector<Track> local;
iterator myBegin = threadBegin(tracks.begin(), tracks.end());
iterator myEnd = threadEnd(tracks.begin(), tracks.end());
for (iterator i = myBegin; i < myEnd; ++i) {
const Track& t = *i;
TrackInterpolator interpol(t);
const Track& result = interpol.bySegmentLength(segmentLength);
local.push_back(result);
}
#pragma omp critical
{
list.insert(list.end(), local.begin(), local.end());
std::cout << "Done: " << omp_get_thread_num() << std::endl;
}
}
return list;
}
関数beginThread(begin, end)
と関数は、現在のスレッド番号とスレッド数によって定義されendThread(begin,end)
た範囲の小さなチャンクを返します。begin
end
それらの実装は次のとおりです。
#include <omp.h>
template <class I>
I threadBegin(I begin, I end) {
int part = omp_get_thread_num();
int parts = omp_get_num_threads();
double chunk = (end - begin)*1.0/parts;
ptrdiff_t diff = (ptrdiff_t) (chunk*part);
return begin + diff;
}
template <class I>
I threadEnd(I begin, I end) {
//the end of i is the begin of i+1
int part = omp_get_thread_num() + 1;
int parts = omp_get_num_threads();
if (part == parts) {
return end;
} else {
double chunk = (end - begin)*1.0/parts;
ptrdiff_t diff = (ptrdiff_t) (chunk*part);
return begin + diff;
}
}
16 コアの Linux マシンでコードを実行しています。
残念ながら、これが原因である可能性がある場合に備えて、少し古い gcc ((SUSE Linux) 4.5.1 20101208) にしかアクセスできません。
list.push_back(..)
PS 私の最初のバージョンでは、クリティカルセクションで並列 for ループを使用していましたが、ここに投稿されたバリアントよりもさらに低速でした。