c++ - openmp parallelセクションのベンチマーク

原文 c++ linux parallel-processing openmp

私はopenmpを使用してマージソートの実装をベンチマークしようとしています。以下のコードを書きました。

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <omp.h>
using namespace std;


class Sorter {
private:
    int* data;
    int size;
    bool isSorted;
public:
    Sorter(int* data, int size){
        this->data = data;
        this->size = size;
        this->isSorted = false;
    }

    void sort(){
        vector<int> v(data,data+size);
        vector<int> ans = merge_sort(v);
        copy(ans.begin(),ans.end(),data);
        isSorted = true;
    }
    vector<int> merge_sort(vector<int>& vec){
        if(vec.size() == 1){
            return vec;
        }
        std::vector<int>::iterator middle = vec.begin() + (vec.size() / 2);

        vector<int> left(vec.begin(), middle);
        vector<int> right(middle, vec.end());

        #pragma omp parallel sections
        { 
            #pragma omp section
            {left = merge_sort(left);}
            #pragma omp section
            {right = merge_sort(right);}

        }
        return merge(vec,left, right);
    }

    vector<int> merge(vector<int> &vec,const vector<int>& left, const vector<int>& right){
        vector<int> result;
        unsigned left_it = 0, right_it = 0;

        while(left_it < left.size() && right_it < right.size()) {
            if(left[left_it] < right[right_it]){
                result.push_back(left[left_it]);
                left_it++;
            }else{
                result.push_back(right[right_it]);
                right_it++;
            }
        }

        while(left_it < left.size()){
            result.push_back(left[left_it]);
            left_it++;
        }

        while(right_it < right.size()){
            result.push_back(right[right_it]);
            right_it++;
        }           
        return result;
    }

    int* getSortedData(){
        if(!isSorted){
            sort();
        }
        return data;
    }
};
void printArray(int* array, int size){
    for(int i=0;i<size;i++){
        cout<<array[i]<<", ";
    }
    cout<<endl;
}
bool isSorted(int* array, int size){
    for(int i=0;i<size-1;i++){
        if(array[i] > array[i+1]) {
            cout<<array[i]<<" > "<<array[i+1]<<endl;
            return false;
        }
    }
    return true;
}
int main(int argc, char** argv){
    if(argc<3){
        cout<<"Specify size and threads"<<endl;
        return -1;
    }

    int size = atoi(argv[1]);
    int threads = atoi(argv[2]);
    //omp_set_nested(1);
    omp_set_num_threads(threads);
    cout<<"Merge Sort of "<<size<<" with "<<omp_get_max_threads()<<endl;
    int *array = new int[size];
    srand(time(NULL));
    for(int i=0;i<size;i++){
        array[i] = rand() % 100;
    }
    //printArray(array,size);
    Sorter* s = new Sorter(array, size);
    cout<<"Starting sort"<<endl;
    double start = omp_get_wtime();
    s->sort();
    double stop = omp_get_wtime();
    cout<<"Time: "<<stop-start<<endl;
    int* array2 = s->getSortedData();
    if(size<=10)
        printArray(array2,size);
    cout<<"Array sorted: "<<(isSorted(array2,size)?"yes":"no")<<endl;
    return 0;
}


プログラムは正しく実行されますが、スレッド数を4などに指定すると、プログラムはまだ2つのスレッドしか作成しません。 omp_set_num_threads(threads)の前にomp_set_nested(1)を使用してみましたが、プログラムがクラッシュして「libgomp:スレッドの作成に失敗しました:リソースが一時的に利用できません」と表示されるまで、ターミナル全体が処理されます。それを回避する作業はまだ見つけていません。

編集:
プログラムがクラッシュした後、システムの負荷を確認すると、負荷が1000を超えていることがわかります。
4コアAMD A8 CPUと10GB RAMを持っています
omp_set_nested(1)のコメントを外してプログラムを実行すると

$ ./mergeSort 10000000 4 
Merge Sort of 10000000 with 4
Starting sort

libgomp: Thread creation failed: Resource temporarily unavailable
libgomp: Thread creation failed: Resource temporarily unavailable
$ uptime
 02:14:12 up 1 day, 11:13,  4 users,  load average: 482.21, 522.87, 338.75


プロセスを監視すると、4つのスレッドが起動されていることがわかります。 omp_set_nested(1)をコメント化すると、プログラムは正常に実行されますが、2つのスレッドしか使用しません

編集:
タスクを使用してomp_set_nestedを削除すると、スレッドは正しく起動しますが、スピードアップしません。 1スレッドでの実行は、4スレッドよりも高速になります。セクションを使用すると、高速化されます。ただし、2未満の係数のみ(一度に2つのスレッドしか起動しないため)
答え
私はあなたのコードをテストしましたが、それは4つ以上のスレッドを作成しましたが、あなたが正確に意味するものを取得しませんでした。また、セクションの定義では1つのスレッドのみが特定のセクションを処理し、再帰呼び出しではアイドルスレッドを使用しないため、ompセクションをompタスクに変更することもお勧めします。
関連記事

c++ - C++のかなりのスタックトレース

c++ - strncpyが指定されたサイズを超えてコピーしています

c++ - ゼロパディング付きのインテルMKLを使用した3D FFT

c++ - C++ヘッダーファイルから型のリストを生成する[終了]

c++ - 可変サイズの配列の初期化

c++ - Visual StudioでのLinuxプラットフォーム用のC++コードの記述

c++ - 回転した長方形で画像ROIを抽出する

c++ - プロセス所有者を取得する(Citrix /プロビジョニング)

c++ - SonarQube Visual Studio 2013 C++プラグイン

c++ - Intel GalileoおよびC++ REST SDK