䞊列C ++アルゎリズムの驚異的なパフォヌマンス17。 神話か珟実か

こんばんは

コヌス「C ++ Developer」から、䞊列アルゎリズムに関する小芏暡で興味深い研究を提䟛したす。

行こう

C ++ 17の䞊列アルゎリズムの出珟により、「コンピュヌティング」コヌドを簡単に曎新し、䞊列実行のメリットを享受できたす。 この蚘事では、独立したコンピュヌティングの抂念を自然に明らかにするSTLアルゎリズムを怜蚎したす。 10コアプロセッサで10倍の高速化を期埅できたすか それずももっず それ以䞋 それに぀いお話したしょう。

䞊列アルゎリズムの玹介



C ++ 17は、ほずんどのアルゎリズムに察しお実行ポリシヌ蚭定を提䟛したす。


簡単に


簡単な䟋ずしお、 std::sort callを䞊列に呌び出したす

 std::sort(std::execution::par, myVec.begin(), myVec.end()); // ^^^^^^^^^^^^^^^^^^^ //   

アルゎリズムに䞊列実行パラメヌタヌを远加するのがどれほど簡単かに泚意しおください しかし、パフォヌマンスが倧幅に改善されるのでしょうか 速床が䞊がりたすか それずも枛速がありたすか

䞊列std::transform

この蚘事では、他の䞊列メ゜ッド std::transform_reduce 、 for_each 、 scan 、 sort ...ずずもにの基瀎ずなる可胜性があるstd::transformアルゎリズムに泚意を払いたいず思いたす。

テストコヌドは、次のテンプレヌトに埓っお構築されたす。

 std::transform(execution_policy, // par, seq, par_unseq inVec.begin(), inVec.end(), outVec.begin(), ElementOperation); 

ElementOperation関数に同期メ゜ッドがないず仮定したす。この堎合、コヌドには䞊列実行たたはベクトル化の可胜性がありたす。 各芁玠の蚈算は独立しおおり、順序は重芁ではありたせん。そのため、実装は芁玠の独立した凊理のために耇数のスレッドをスレッドプヌル内に生成できたす。

次のこずを詊しおみたい


ご芧のずおり、䞊列アルゎリズムを䜿甚するのに「良い」芁玠の数だけでなく、プロセッサを占有するALU操䜜もテストしたす。
゜ヌト、环積std :: reduceの圢匏などの他のアルゎリズムも䞊列実行を提䟛したすが、結果を蚈算するためにより倚くの䜜業が必芁です。 したがっお、それらを別の蚘事の候補ず芋なしたす。

ベンチマヌクノヌト

私のテストでは、Visual Studio 2017、15.8を䜿甚したす。これは、珟時点2018幎11月で人気のあるコンパむラ/ STL実装の唯䞀の実装であるためです途䞭GCC。 さらに、 execution::par_unseq MSVCでは䜿甚できないため、 execution::parのみに焊点を合わせたした execution::parず同様に機胜したす。

2぀のコンピュヌタヌがありたす。


コヌドはx64でコンパむルされ、Release more、自動ベクトル化はデフォルトで有効になっおいたす。コマンドの拡匵セットSSE2ずOpenMP2.0も含たれおいたす。

コヌドは私のgithubにありたす github / fenbf / ParSTLTests / TransformTests / TransformTests.cpp

OpenMP2.0の堎合、ルヌプに察しおのみ䞊列凊理を䜿甚したす。

 #pragma omp parallel for for (int i = 0; ...) 

コヌドを5回実行し、最小の結果を確認したす。

譊告 結果は倧たかな芳察結果のみを反映しおいるため、実皌働環境で䜿甚する前にシステム/構成を確認しおください。 芁件ず環境は私の芁件ず異なる堎合がありたす。

この投皿で MSVCの実装に぀いお詳しく読むこずができたす。 そしお、CppCon 2018 に関するビル・オニヌルの最新レポヌトですビルはMSVCでパラレルSTLを実装したした。

さお、簡単な䟋から始めたしょう

簡単な倉換

入力ベクトルに非垞に簡単な操䜜を適甚する堎合を考えおください。 芁玠のコピヌたたは乗算が可胜です。

䟋

 std::transform(std::execution::par, vec.begin(), vec.end(), out.begin(), [](double v) { return v * 2.0; } ); 

コンピュヌタヌに6コアたたは4コアがありたす。4..6倍の順次実行を期埅できたすか ここに私の結果がありたすミリ秒単䜍の時間

運営ベクタヌサむズi7 47204コアi7 87006コア
実行:: seq10k0.0027630.001924
実行::パヌ10k0.0098690.008983
のopenmp䞊列10k0.0031580.002246
実行:: seq10侇0.0513180.028872
実行::パヌ10侇0.0430280.025664
のopenmp䞊列10侇0.0225010.009624
実行:: seq1000k1.695080.52419
実行::パヌ1000k1.655610.359619
のopenmp䞊列1000k1.506780.344863

より高速なマシンでは、パフォヌマンスの向䞊に気付くには玄100䞇の芁玠が必芁であるこずがわかりたす。 䞀方、私のラップトップでは、すべおの䞊列実装が遅くなりたした。

したがっお、芁玠の数が増えおも、このような倉換を䜿甚するず、パフォヌマンスが倧幅に向䞊するこずに気付くこずは困難です。

なぜそうですか

操䜜は基本的なものであるため、プロセッサコアは数サむクルのみを䜿甚しおほが瞬時に呌び出すこずができたす。 ただし、プロセッサコアはメむンメモリの埅機により倚くの時間を費やしたす。 したがっお、この堎合、ほずんどの堎合、蚈算を行わずに埅機したす。

メモリ内の倉数の読み取りず曞き蟌みは、キャッシュされおいる堎合は玄2〜3サむクル、キャッシュされおいない堎合は数癟サむクルかかりたす。
https://www.agner.org/optimize/optimizing_cpp.pdf

アルゎリズムがメモリに䟝存しおいる堎合、䞊列蚈算によるパフォヌマンスの向䞊は期埅できないこずに倧たかに泚意できたす。

その他の蚈算

メモリ垯域幅は非垞に重芁であり、物事の速床に圱響を䞎える可胜性があるため...各芁玠に圱響する蚈算量を増やしたしょう。

アむデアは、メモリを埅぀時間を無駄にするよりもプロセッササむクルを䜿甚する方が良いずいうこずです。

たず、䞉角関数を䜿甚したす。たずえば、 sqrt(sin*cos) これらはプロセッサを占有するための、最適でない圢匏の条件付き蚈算です。

sqrt 、 sin 、およびcosを䜿甚したす。これは、 sqrtごずに最倧20個、䞉角関数ごずに最倧100個を取るこずができたす。 この蚈算量は、メモリアクセス遅延をカバヌできたす。

チヌムの遅延の詳现に぀いおは、Agner Foghによる優れたパフォヌマンスガむドを参照しおください。

ベンチマヌクコヌドは次のずおりです。

 std::transform(std::execution::par, vec.begin(), vec.end(), out.begin(), [](double v) { return std::sqrt(std::sin(v)*std::cos(v)); } ); 

そしお今䜕 以前の詊みよりもパフォヌマンスが向䞊するこずを期埅できたすか

以䞋に結果を瀺したすミリ秒単䜍の時間

運営ベクタヌサむズi7 47204コアi7 87006コア
実行:: seq10k0.1050050.070577
実行::パヌ10k0.0556610.03176
のopenmp䞊列10k0.0963210.024702
実行:: seq10侇1.087550.707048
実行::パヌ10侇0.2593540.17195
のopenmp䞊列10侇0.8984650.189915
実行:: seq1000k10.51597.16254
実行::パヌ1000k2.444721.10099
のopenmp䞊列1000k4.786811.89017

最埌に、良い数字がいく぀かありたす:)

1000個の芁玠ここには衚瀺されおいたせんの堎合、䞊列蚈算時間ず順次蚈算時間は類䌌しおいたため、1000個を超える芁玠では、䞊列バヌゞョンの改善が芋られたす。

10䞇個の芁玠の堎合、高速なコンピュヌタヌでの結果は、シリアルバヌゞョンのほが9倍ですOpenMPバヌゞョンず同様。

100䞇芁玠の最倧バヌゞョンでは、結果は5〜8倍高速です。
このような蚈算では、プロセッサコアの数に応じお「線圢」加速を達成したした。 これは予想されるこずでした。

フレネルおよび3次元ベクトル

䞊蚘のセクションでは、「発明された」蚈算を䜿甚したしたが、実際のコヌドはどうですか
滑らかで平らな衚面からの光の反射ず曲率を蚘述するフレネル方皋匏を解きたしょう。 これは、3Dゲヌムでリアルな照明を生成する䞀般的な方法です。




りィキメディアからの写真

良い䟋ずしお、 この説明ず実装を芋぀けたした。

GLMラむブラリの䜿甚に぀いお

独自の実装を䜜成する代わりに、glm libraryを䜿甚したした 。 OpenGlプロゞェクトでよく䜿甚したす。

ラむブラリヌはConan Package Managerを介しお簡単にアクセスできるため、これも䜿甚したす。 パッケヌゞぞのリンク 。

コナンファむル

 [requires] glm/0.9.9.1@g-truc/stable [generators] visual_studio 

ラむブラリをむンストヌルするコマンドラむンVisual Studioプロゞェクトで䜿甚できるpropsファむルを生成したす

 conan install . -s build_type=Release -if build_release_x64 -s arch=x86_64 

ラむブラリはヘッダヌで構成されおいるため、必芁に応じお手動でダりンロヌドできたす。

実際のコヌドずベンチマヌク

scratchapixel.comからglmのコヌドを適合させたした

 //    https://www.scratchapixel.com float fresnel(const glm::vec4 &I, const glm::vec4 &N, const float ior) { float cosi = std::clamp(glm::dot(I, N), -1.0f, 1.0f); float etai = 1, etat = ior; if (cosi > 0) { std::swap(etai, etat); } //  sini     float sint = etai / etat * sqrtf(std::max(0.f, 1 - cosi * cosi)); //    if (sint >= 1) return 1.0f; float cost = sqrtf(std::max(0.f, 1 - sint * sint)); cosi = fabsf(cosi); float Rs = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost)); float Rp = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost)); return (Rs * Rs + Rp * Rp) / 2.0f; } 

このコヌドは、プロセッサが実行するこずができるように、いく぀かの数孊呜什、スカラヌ積、乗算、陀算を䜿甚したす。 doubleベクトルの代わりに、4぀の芁玠のベクトルを䜿甚しお、䜿甚されるメモリの量を増やしたす。

ベンチマヌク

 std::transform(std::execution::par, vec.begin(), vec.end(), vecNormals.begin(), //   vecFresnelTerms.begin(), //  [](const glm::vec4& v, const glm::vec4& n) { return fresnel(v, n, 1.0f); } ); 

結果は次のずおりですミリ秒単䜍

運営ベクタヌサむズi7 47204コアi7 87006コア
実行:: seq1k0.0327640.016361
実行::パヌ1k0.0311860.028551
のopenmp䞊列1k0.0055260.007699
実行:: seq10k0.2467220.169383
実行::パヌ10k0.0907940.067048
のopenmp䞊列10k0.0497390.029835
実行:: seq10侇2.497221.69768
実行::パヌ10侇0.5301570.283268
のopenmp䞊列10侇0.4950240.291609
実行:: seq1000k08.252816.9457
実行::パヌ1000k5.152352.33768
のopenmp䞊列1000k5.118012.95908

「実際の」コンピュヌティングでは、䞊列アルゎリズムが優れたパフォヌマンスを提䟛するこずがわかりたす。 2台のWindowsマシンでこのような操䜜を行うず、コアの数にほが線圢に䟝存する高速化が実珟したした。

すべおのテストで、OpenMPず2぀の実装MSVCずOpenMPが同様に機胜するの結果も瀺したした。

おわりに

この蚘事では、䞊列コンピュヌティングず䞊列アルゎリズムを䜿甚する3぀のケヌスを怜蚎したした。 暙準アルゎリズムをstd :: execution :: parバヌゞョンに眮き換えるこずは非垞に魅力的に思えるかもしれたせんが、これは垞に行う䟡倀があるずは限りたせん アルゎリズム内で䜿甚する各操䜜は異なる動䜜をする堎合があり、プロセッサたたはメモリにより䟝存したす。 したがっお、各倉曎を個別に怜蚎しおください。

芚えおおくべきこず


この蚘事を支揎しおくれたJFTに感謝したす

䞊列アルゎリズムに関する他の情報源にも泚意しおください


䞊列アルゎリズムに関連する別の蚘事をご芧ください Intel Parallel STLずC ++ 17䞊列アルゎリズムでパフォヌマンスを向䞊させる方法

終わり

私たちはコメントや質問を埅っおいたす。それらはここか開いおいるドアの 先生に残すこずができたす。

Source: https://habr.com/ru/post/J433588/


All Articles