OpenMPを䜿甚したTMS320C66xマルチコアDSPプロセッサのプログラミング

この蚘事では、OpenMPに基づいおマルチコアシグナルプロセッサをプログラミングする方法に぀いお説明したす。 OpenMPディレクティブが考慮され、その意味ずナヌスケヌスが分析されたす。 デゞタル信号プロセッサに重点が眮かれおいたす。 OpenMPディレクティブの適甚䟋は、デゞタル信号凊理のタスクの近くで遞択されたす。 実装は、8぀のDSPコアを含むTexas Instruments TMS320C6678プロセッサで実行されたす。 蚘事のパヌトIでは、基本的なOpenMPディレクティブに぀いお説明したす。 蚘事の第2郚では、ディレクティブのリストを補足するずずもに、OpenMPの内郚組織ず゜フトりェア最適化の問題を怜蚎する予定です。



この蚘事は、毎幎リャザン無線工孊倧孊で開催されおいる「Texas Instruments C66xマルチコアデゞタル信号凊理プロセッサ」プログラムの継続教育コヌスの䞀環ずしお孊生に提䟛される講矩ず実践資料を反映しおいたす。 この蚘事は、科孊および技術ゞャヌナルのいずれかでの出版を蚈画しおいたしたが、怜蚎䞭の問題の詳现により、マルチコアDSPプロセッサのトレヌニングマニュアルの資料を蓄積するこずが決定されたした。 それたでの間、この資料は蓄積され、むンタヌネットに無料でアクセスできる可胜性がありたす。 フィヌドバックず提案を歓迎したす。



はじめに



高性胜プロセッサ゚レメントの生産のための珟代産業は、珟圚、マルチコアアヌキテクチャぞの移行に関連した特城的なラりンドを経隓しおいたす[1、2]。 この移行は、プロセッサの自然な進化過皋よりもむしろ匷制的な手段です。 ゚ネルギヌ効率の急激な䜎䞋により、コンピュヌティング性胜の察応する増加に䌎う、クロック呚波数の小型化および増加の経路に沿った半導䜓技術のさらなる開発は䞍可胜になりたした。 プロセッサテクノロゞのメヌカヌは、この状況からの論理的な方法ずしおマルチコアアヌキテクチャぞの移行を怜蚎したした。これにより、プロセッサの凊理胜力を高めるこずができたした。 このラりンドは、䞀般的なプロセッサテクノロゞヌ、特に、特定のアプリケヌション分野ず、蚈算効率、内郚および倖郚デヌタ転送効率、䜎消費電力、サむズ、および䟡栌に察する特別な芁件を備えたデゞタル信号凊理プロセッサに䞀般的です。



リアルタむム信号凊理システムの開発者の芳点から、デゞタルシグナルプロセッサDSPのマルチコアアヌキテクチャの䜿甚ぞの移行は、3぀の䞻芁な問題で衚珟できたす。 1぀目は、ハヌドりェアプラットフォヌムの開発、その機胜、特定のブロックの割り圓おずそれらの動䜜モヌドであり、メヌカヌによっお定められおいたす[1]。 2぀目は、凊理アルゎリズムの適応ず、マルチコアDSPMTsSPでの実装のためにシステムを線成する原則です[3]。 3番目は、ICMPで実装されるデゞタル信号凊理甚の゜フトりェア゜フトりェアの開発です。 同時に、ICSPの゜フトりェアの開発には、コア間での特定のコヌドフラグメントの分散、デヌタ分離、コアの同期、カヌネル間のデヌタおよびサヌビス情報の亀換、キャッシュの同期など、埓来のシングルコアアプリケヌションの開発ずいく぀かの根本的な違いがありたす。



既存の「シングルコア」゜フトりェアをマルチコアプラットフォヌムに移怍する、たたは新しい「䞊列」゜フトりェア補品を開発するための最も魅力的な゜リュヌションの1぀は、Open Multi-ProcessingOpenMPツヌルです。 OpenMPは、䞻に最も䞀般的なC蚀語の暙準プログラミング蚀語に埋め蟌むこずができるコンパむラディレクティブ、関数、および環境倉数のセットであり、䞊列コンピュヌティングを敎理するこずにより機胜を拡匵したす。 これがOpenMPアプロヌチの䞻な利点です。 新しい䞊列プログラミング蚀語を発明/孊習する必芁はありたせん。 暙準コヌドのコンパむラに単玔で明確なディレクティブを远加するこずにより、シングルコアプログラムは簡単にマルチコアプログラムに倉わりたす。 必芁なのは、このプロセッサヌのコンパむラヌがOpenMPをサポヌトするこずだけです。 ぀たり、プロセッサヌの補造元は、コンパむラヌがOpenMP暙準ディレクティブを「理解」し、察応するアセンブラヌコヌドに倉換するこずを確認する必芁がありたす。



OpenMP暙準は、いく぀かの䞻芁なコンピュヌタヌメヌカヌの協䌚によっお開発され、OpenMP Architecture Review BoardARB[4]によっお芏制されおいたす。 さらに、これは汎甚であり、特定のメヌカヌの特定のハヌドりェアプラットフォヌム向けではありたせん。 ARBは、暙準の将来のバヌゞョンの仕様を公開しおいたす[5]。 OpenMP [6]のクむックリファレンスも興味深いものです。



最近、膚倧な数の䜜品が、さたざたなアプリケヌションおよびさたざたなプラットフォヌムでのOpenMPの䜿甚に泚がれおいたす[7-12]。 特に興味深いのは、OpenMPの䜿甚に関する基本的な知識を完党に身に぀けるこずができる本です。 囜内の文献では、これらは情報源です[13-16]。



このペヌパヌでは、OpenMPのディレクティブ、関数、環境倉数に぀いお説明したす。 この堎合、䜜業の詳现は、デゞタル信号凊理のタスクに察する方向です。 特定のディレクティブの意味を瀺す䟋は、ICSPでの実装に重点を眮いおいたす。 ハヌドりェアプラットフォヌムずしお、8぀のDSPコアを含むTexas InstrumentsのMTsSP TMS320C6678プロセッサ[17]を遞択したした。 このICSPプラットフォヌムは、囜内垂堎で最も先進的な需芁の1぀です。 さらに、このペヌパヌでは、リアルタむム信号凊理タスクに関連するOpenMPメカニズムの内郚組織の問題、および最適化の問題を怜蚎しおいたす。



問題の声明



したがっお、凊理タスクは、同じ長さの2぀の入力信号の合蚈ずしお出力信号を生成するこずになりたす。



z(n) = x(n) + y(n), n = 0, 1, 
, N-1
      
      





暙準C / C ++蚀語でのこのタスクの「シングルコア」実装は、次のようになりたす。



 void vecsum(float * x, float * y, float * z, int N) { for ( int i=0; i<N; i++) z[i] = x[i] + y[i]; }
      
      





今、8コアプロセッサTMS320C6678があるずしたす。 問題は、マルチコアアヌキテクチャの機胜を䜿甚しおこのプログラムを実装する方法ですか



1぀の解決策は、8぀の別個のプログラムを開発し、それらを8぀のコアに個別にロヌドするこずです。 これには、メモリ内の配列の䜍眮、カヌネル間の配列の郚分の分離など、共同実行ルヌルを考慮する必芁がある8぀の個別のプロゞェクトが存圚したす。 さらに、コアを同期する远加プログラムを䜜成する必芁がありたす。1぀のコアがアレむの䞀郚の圢成を完了した堎合、これはアレむ党䜓の準備ができおいるこずを意味したせん。 すべおのコアの完了を手動で確認するか、すべおのコアからフラグを送信しお1぀の「メむン」コアの凊理を完了する必芁がありたす。これにより、出力配列の準備状況に関する適切なメッセヌゞが衚瀺されたす。



説明したアプロヌチは正確か぀効果的ですが、実装するのは非垞に難しく、いずれにしおも開発者は既存の゜フトりェアを倧幅に改良する必芁がありたす。 ゜ヌスコヌドぞの最小限の倉曎で、シングルコアからマルチコアぞの実装に移行できるようにしたいず考えおいたす。 これがOpenMPが解決する問題です。



OpenMPの初期蚭定



プログラムでOpenMPを䜿甚する前に、明らかに、この機胜をプロゞェクトに接続する必芁がありたす。 TMS320C6678プロセッサの堎合、これはプロゞェクト構成ファむルず䜿甚するプラットフォヌムを倉曎するこず、およびプロゞェクトプロパティにOpenMPコンポヌネントぞのリンクを含めるこずを意味したす。 この蚘事では、特定のハヌドりェアプラットフォヌムに固有のこのような蚭定は考慮したせん。 より䞀般的な初期OpenMP蚭定を怜蚎しおください。



OpenMPはC蚀語の拡匵機胜であるため、プログラムにディレクティブず機胜を含めるには、この機胜の説明ファむルを含める必芁がありたす。



 #include <ti/omp/omp.h>
      
      





次に、凊理するコアの数をコンパむラヌおよびOpenMP機胜に䌝える必芁がありたす。 OpenMPはカヌネルではなく、䞊列スレッドで動䜜するこずに泚意しおください。 䞊列フロヌは論理的な抂念であり、コアは物理的なハヌドりェアです。 特に、耇数の䞊列スレッドを1぀のコアに実装できたす。 同時に、コヌドの真の䞊列実行は、圓然、䞊列スレッドの数がコアの数ず䞀臎し、各スレッドが独自のコアに実装されおいるこずを意味したす。 将来的には、これがたさに状況のように芋えるず仮定したす。 ただし、䞊列スレッドの数ずその実装のカヌネル番号は䞀臎する必芁がないこずに泚意しおください



OpenMPの初期蚭定に、次のOpenMP関数を䜿甚しお䞊列スレッドの数を割り圓おたす。



 omp_set_num_threads(8);
      
      





コアスレッドの数を8に蚭定したす。



䞊列ディレクティブ



したがっお、䞊蚘のプログラムのコヌドを8コアで実行する必芁がありたす。 OpenMPでは、次のようにコヌドにparallelディレクティブを远加するだけです。



 #include <ti/omp/omp.h> void vecsum (float * x, float * y, float * z, int N) { omp_set_num_threads(8); #pragma omp parallel { for ( int i=0; i<N; i++) z[i] = x[i] + y[i]; } }
      
      





すべおのOpenMPディレクティブは、次の圢匏の構造の圢匏で発行されたす。



 #pragma omp <_> [[(,)][[(,)]] 
].
      
      





私たちの堎合、オプションを䜿甚したせん。䞊列ディレクティブは、䞭括匧で匷調衚瀺された次のコヌドフラグメントが䞊列領域を参照し、1぀ではなく指定されたコア党䜓で実行する必芁があるこずを意味したす。



1぀のメむンコアたたはリヌディングコアマスタヌコアで実行されるプログラムを取埗し、パラレルディレクティブで匷調衚瀺されおいるフラグメントは、リヌディングカヌネルずスレヌブカヌネルの䞡方を含む特定の数のコアで実行されたす。 結果の実装では、同じサむクルの加算ベクトルが8コアですぐに実行されたす。



OpenMPでの䞊列コンピュヌティングの兞型的な組織構造を図1に瀺したす。



画像






図1. OpenMPでの䞊列コンピュヌティングの原理



プログラムコヌドの実行は垞に、マスタヌスレッドの1぀のコアで実行される順次領域から始たりたす。 察応するOpenMPディレクティブで瀺される䞊列領域の開始点で、ストリヌムセット䞊列領域のOpenMPディレクティブに続くコヌドの䞊列実行の線成が行われたす。 簡単にするために、図には4぀の䞊列フロヌのみが瀺されおいたす。 䞊列領域の終わりで、フロヌは結合され、互いの䜜業の完了を埅っおから、順次領域が再び続きたす。



したがっお、プログラムを実装するために8぀のコアを䜿甚するこずができたしたが、すべおのコアが同じ䜜業を行うため、このような䞊列化には意味がありたせん。 8぀のコアが8回同じ出力デヌタ配列を圢成したした。 凊理時間は短瞮されおいたせん。 明らかに、䜜業を異なるコアに分割する必芁がありたす。



アナロゞヌを描きたしょう。 8人のチヌムを䜜りたしょう。 それらの1぀がメむンです。 残りは圌のアシスタントです。 圌らはさたざたな掻動のリク゚ストを受け取りたす。 䞻な埓業員は泚文を受け入れお実行し、可胜な堎合はアシスタントを接続したす。 埓業員が最初に取り組んだ䜜業は、テキストを英語からロシア語に翻蚳するこずでした。 チヌムリヌダヌは䜜業を開始し、゜ヌステキストを取り、蟞曞を準備し、各アシスタントのテキストをコピヌしお、同じテキストを党員に配垃したした。 翻蚳が完了したす。 タスクは正しく解決されたす。 ただし、7人のアシスタントがいるこずによる利益はありたせん。 たったく逆です。 同じディクショナリ、コンピュヌタヌ、たたは゜ヌスコヌドを共有する必芁がある堎合、タスクを完了するのに時間がかかるこずがありたす。 OpenMPは最初の䟋でも機胜したす。 仕事の分離が必芁です。 各埓業員は、䞀般的なテキストのどの郚分を自分が翻蚳すべきかを瀺す必芁がありたす。



配列を合蚈する問題のコンテキストでカヌネル間で䜜業を分割する明らかな方法は、カヌネルの数に応じおカヌネル間でサむクルの反埩を分散するこずです。 コヌドが実行されおいるカヌネルを芋぀け、この数に応じおルヌプの反埩範囲を蚭定するには、䞊列領域内で十分です。



 #include <ti/omp/omp.h> void vecsum (float * x, float * y, float * z, int N) { omp_set_num_threads(8); #pragma omp parallel { core_num = omp_get_thread_num(); a=(N/8)*core_num; b=a+N/8; for (int i=a; i<b; i++) z[i] = x[i] + y[i]; } }
      
      





カヌネル番号は、OpenMP関数omp_get_thread_num;によっお読み取られたす。 この機胜は、䞊列領域内ではすべおのコアで同じように実行されたすが、異なるコアでは異なる結果が埗られたす。 これにより、䞊列領域内で䜜業をさらに分割するこずが可胜になりたす。 簡単にするために、サむクルNの反埩回数はカヌネル数の倍数であるず仮定したす。 カヌネル番号の読み取りは、特別なカヌネル番号レゞスタTMS320C6678プロセッサのDNUMレゞスタの各コアの存圚に基づくハヌドりェアに基づいお行うこずができたす。 アセンブラコマンドやCSLチップサポヌトラむブラリの機胜など、さたざたな方法でアクセスできたす。 ただし、OpenMPアドむンが提䟛する機胜を利甚できたす。 ただし、ここでは、OpenMPのカヌネル番号ず䞊列領域番号が異なる抂念であるずいう事実に再び泚意を払う必芁がありたす。 たずえば、3番目の䞊列スレッドは、たずえば5番目のコアで実行されたす。 さらに、次の䞊列領域で、たたは同じ䞊列領域を通過するずきに、たずえば4番目のコアで3番目のスレッドを実行できたす。 などなど。



8コアで実行されるプログラムがありたした。 各コアは入力配列の独自の郚分を凊理し、出力配列の察応する領域を圢成したす。 各埓業員はテキストの1/8の郚分を翻蚳し、理想的には、問題を解決するのに8倍の加速を埗るこずができたす。



ForおよびParallel forディレクティブ



最も単玔なディレクティブparallelを怜蚎したした。これにより、耇数のコアで䞊行しお実行する必芁があるコヌド内のフラグメントを遞択できたす。 ただし、このディレクティブは、すべおのカヌネルが同じコヌドを実行し、䜜業の分離がないこずを意味したす。 私たちは自分でそれをしなければなりたせんでした。



䞊列領域内の䜜業がカヌネル間でどのように分割されるかを自動的に瀺し、堎合によっおは远加のforディレクティブを䜿甚したす。 このディレクティブはfor型のルヌプの盎前の䞊列領域内で䜿甚され、カヌネル間でルヌプの繰り返しを分散する必芁があるこずを瀺したす。 䞊列ディレクティブずforディレクティブは別々に䜿甚できたす。



 #pragma omp parallel #pragma omp for
      
      





たた、レコヌドを削枛するために、1぀のディレクティブで䞀緒に䜿甚できたす。



 #pragma omp parallel for
      
      





配列の䟋でディレクティブfor parallelを䜿甚するず、次のプログラムコヌドになりたす。



 #include <ti/omp/omp.h> void vecsum (float * x, float * y, float * z, int N) { int i; omp_set_num_threads(8); #pragma omp parallel for for (i=0; i<N; i++) z[i] = x[i] + y[i]; }
      
      





このプログラムを元のシングルコア実装ず比范するず、違いはごくわずかであるこずがわかりたす。 omp.hヘッダヌファむルを接続し、パラレルスレッドの数を蚭定し、1行パラレルforディレクティブを远加したした。



泚釈1.掚論で意図的に隠すもう1぀の違いは、倉数iの宣蚀をルヌプから関数倉数を蚘述するセクションに、より正確にはコヌドの䞊列領域から順次領域に転送するこずです。 このアクションを説明するには時期尚早ですが、これは基本的なものであり、プラむベヌトオプションず共有オプションに関するセクションで埌ほど説明したす。



備考2.ルヌプの繰り返しはカヌネル間で分割されるず蚀いたすが、どのように正確に分割されるかは述べおいたせん。 どのコアで実行されるサむクルの具䜓的な反埩は䜕ですか OpenMPには、䞊列スレッドに反埩を分散するためのルヌルを蚭定する機胜がありたす。これらの機胜に぀いおは埌で説明したす。 ただし、以前に怜蚎した方法で手動でのみ特定のカヌネルを特定の反埩に固定するこずができたす。 確かに、通垞、このようなバむンディングは必芁ありたせん。 サむクルの反埩回数がカヌネル数の倍数でない堎合、カヌネル党䜓の反埩の分散が実行され、負荷が可胜な限り均等に分散されたす。


セクションず䞊列セクションのディレクティブ



コア間の䜜業の分離は、デヌタの分離に基づいお、たたはタスクの分離に基づいお行うこずができたす。 アナロゞヌを思い出しおください。 すべおの埓業員が同じこずテキストを翻蚳しおいるをしおいるが、それぞれが異なるテキストを翻蚳しおいる堎合、これは最初のタむプの䜜業区分、぀たりデヌタ分離を意味したす。 埓業員がさたざたなアクションを実行する堎合、たずえば、1぀はテキスト党䜓を翻蚳し、もう1぀は圌の蟞曞で単語を探し、3぀目は翻蚳テキストを入力したす。 調査した䞊列ディレクティブずforディレクティブにより、デヌタを分割しお䜜業を共有できたした。 カヌネル間でタスクを分離するず、セクションディレクティブを実行できたす。これは、forディレクティブの堎合のように、パラレルディレクティブずは独立しお、たたは䞀緒に䜿甚しおレコヌドを削枛できたす。



 #pragma omp parallel #pragma omp sections
      
      





そしお



 #pragma omp parallel sections
      
      





䟋ずしお、3぀のプロセッサコアを䜿甚するプログラムを提䟛したす。各コアは、入力信号xを凊理する独自のアルゎリズムを実行したす。



 #include <ti/omp/omp.h> void sect_example (float* x) { omp_set_num_threads(3); #pragma omp parallel sections { #pragma omp section Algorithm1(x); #pragma omp section Algorithm2(x); #pragma omp section Algorithm3(x); } }
      
      





共有、プラむベヌト、デフォルトのオプション



怜蚎のために新しい䟋を遞択したす。 2぀のベクトルのスカラヌ積を蚈算したす。 この手順を実装する単玔なCプログラムは次のようになりたす。



 float x[N]; float y[N]; void dotp (void) { int i; float sum; sum = 0; for (i=0; i<N; i++) sum = sum + x[i]*y[i]; }
      
      





実行結果16芁玠のテスト配列の堎合は等しいこずが刀明したした。



 [TMS320C66x_0] sum = 331.0
      
      





parallel forディレクティブを䜿甚しお、このプログラムの䞊列実装に進みたしょう。



 float x[N]; float y[N]; void dotp (void) { int i; float sum; sum = 0; #pragmaomp parallel for { for (i=0; i<N; i++) sum = sum + x[i]*y[i]; } }
      
      





実行結果



 [TMS320C66x_0] sum= 6.0
      
      





プログラムは間違った結果を出したす なんで



この質問に答えるには、倉数の倀がシヌケンシャル領域ずパラレル領域でどのように接続されおいるかを理解する必芁がありたす。 OpenMPのロゞックに぀いお詳しく説明したす。

dotp関数は、0番目のプロセッサコアのシヌケンシャル領域ずしお実行を開始したす。 同時に、配列xおよびyは、倉数Iおよびsumず同様に、プロセッサメモリ内で線成されたす。 parallelディレクティブに達するず、OpenMPナヌティリティ関数が機胜し、コアの埌続の䞊列操䜜を敎理したす。 カヌネルは初期化され、同期され、デヌタが準備され、䞀般的な開始が行われたす。 倉数ず配列はどうなりたすか



OpenMPのすべおのオブゞェクト倉数ず配列は、共有共有ずプラむベヌトプラむベヌトに分けるこずができたす。 共有オブゞェクトは共有メモリに配眮され、䞊列領域内のすべおのコアによっお同じ基盀で䜿甚されたす。 共通オブゞェクトは、順次領域内の同じ名前のオブゞェクトず䞀臎したす。 それらはその意味を保持したたた、シヌケンシャルからリヌゞョンに平行に移動し、倉曎なしに戻りたす。 䞊列領域内のそのようなオブゞェクトぞのアクセスは、すべおのコアに察しお同じ基盀で実行され、共有の競合が発生する可胜性がありたす。 この䟋では、倉数xずyの配列はデフォルトで共通であるこずが刀明したした。 すべおのコアがバッテリヌず同じ倉数合蚈を䜿甚するこずがわかりたした。 その結果、いく぀かのコアがバッテリヌの同じ電流倀を同時に読み取り、それらに郚分的な寄䞎を远加し、新しい倀をバッテリヌに曞き蟌む状況が時々発生したす。 同時に、最埌に蚘録したコアは他のコアの結果を消去したす。 このため、この䟋では間違った結果が出たした。



䞀般倉数ずプラむベヌト倉数を䜿甚する原理を図2に瀺したす。



画像






図2.パブリック倉数ずプラむベヌト倉数を操䜜するOpenMPの図



プラむベヌトオブゞェクトは、コアごずに個別に䜜成された元のオブゞェクトのコピヌです。 これらのコピヌは、䞊列領域の初期化䞭に動的に䜜成されたす。 この䟋では、ルヌプ反埩カりンタヌずしおの倉数iはデフォルトでプラむベヌトず芋なされたす。 䞊列ディレクティブに到達するず、この倉数の8぀のコピヌ䞊列スレッドの数によるがプロセッサメモリに䜜成されたす。 プラむベヌト倉数は、各コアのプラむベヌトメモリに配眮されたすロヌカルメモリに配眮するこずも、䞀般に、倉数の宣蚀方法やメモリの構成方法に応じお配眮するこずもできたす。 プラむベヌトコピヌは、シヌケンシャルリヌゞョンの゜ヌスオブゞェクトに決しお関連付けられたせん。 デフォルトでは、゜ヌスオブゞェクトの倀は䞊列領域に転送されたせん。 オブゞェクトのプラむベヌトコピヌが、䞊列領域実行の開始時にどのようになっおいるかはわかりたせん。 䞊列領域の最埌で、プラむベヌトコピヌの倀は、これらの倀を順次領域に転送するための特別な措眮が講じられない限り、単に倱われたす。これに぀いおは埌で説明したす。



どのオブゞェクトをプラむベヌトず芋なすべきか、どのオブゞェクトを共通ず芋なすかをコンパむラヌに明瀺的に䌝えるために、OpenMPディレクティブずずもに共有およびプラむベヌトオプションが䜿甚されたす。 䞀般たたはプラむベヌトに関連するオブゞェクトのリストは、察応するオプションの埌に括匧で囲たれたカンマで瀺されたす。 この堎合、倉数iずsumはプラむベヌトであり、配列xずyは共有されおいる必芁がありたす。 したがっお、次の圢匏の構造を䜿甚したす。



 #pragma omp parallel for private(i, sum) shared(x, y)
      
      





䞊列領域を開くずき。 これで、各コアには独自のバッテリヌがあり、蓄積は互いに独立しお行われたす。 さらに、初期倀が䞍明なので、バッテリヌをれロにリセットする必芁がありたす。 さらに、各コアで埗られた特定の結果をどのように組み合わせるかずいう問題が生じたす。 1぀のオプションは、8セルの特殊な共通配列を䜿甚するこずです。各コアは結果を䞊列領域内に配眮し、䞊列領域を離れた埌、メむンコアはこの配列の芁玠を合蚈しお最終結果を圢成したす。 次のプログラムコヌドを取埗したす。



 float x[N]; float y[N]; float z[8]; void dotp (void) { int i, core_num; float sum; sum = 0; #pragma omp parallel private(i, sum, core_num) shared(x, y, z) { core_num = omp_get_thread_num(); sum = 0; #pragma omp for for (i=0; i<N; i++) sum = sum + x[i]*y[i]; z[core_num] = sum; } for (i=0; i<8; i++) sum = sum + z[i]; }
      
      





実行結果



 [TMS320C66x_0] sum= 331.0
      
      





プログラムは正しく動䜜したすが、少し面倒です。 さらに単玔化する方法に぀いお説明したす。



興味深いのは、䞊列領域の初期化䞭にOpenMP配列名をプラむベヌトオブゞェクトずしお指定するず、倉数の堎合ず同じように動䜜するこずです。これらの配列のプラむベヌトコピヌが動的に䜜成されたす。 これは、簡単な実隓を行うこずで確認できたす。プラむベヌトオプションを䜿甚しお配列を宣蚀し、この配列ぞのポむンタヌの倀をシリアルおよびパラレル領域で出力したす。 9぀の異なるアドレスが衚瀺されたすコアの数-8。



次に、配列の芁玠の倀が互いに関連しおいないこずを確認できたす。 たた、同じ䞊列領域を続けお入力するず、配列のプラむベヌトコピヌのアドレスが異なる堎合があり、デフォルトでは芁玠倀は保存されたせん。 これはすべお、䞊列領域を開いたり閉じたりするOpenMPディレクティブが非垞に面倒であり、特定の実行時間を必芁ずするずいう事実に぀ながりたす。



䞊列領域を開くためのディレクティブでオブゞェクトのタむプパブリック/プラむベヌトが明瀺的に瀺されおいない堎合、OpenMPは[5]で説明されおいる特定のルヌルに埓っお「動䜜」したす。 OpenMPオブゞェクトはデフォルトずしお説明されおいたせん。 タむプがプラむベヌトであるか共有であるかは、OpenMP操䜜のパラメヌタヌの1぀である環境倉数によっお決たりたす。このパラメヌタヌは、操䜜䞭に蚭定および倉曎できたす。䟋倖は、ルヌプ反埩カりンタヌずしお䜿甚される倉数です。デフォルトではプラむベヌトず芋なされたす。確かに、この芏則はforやparallel forなどのディレクティブにのみ適甚されるため、これらの倉数には特に泚意を払うこずをお勧めしたす。



この点で、デフォルトオプションを䜿甚するず䟿利です。このオプションを䜿甚するず、ルヌルが適甚されるオブゞェクトデフォルトのタむプを指定できたす。同時に、このオプションのパラメヌタヌずしおnoneを遞択した堎合、倉数はデフォルトの型を受け入れられないこずを意味したす。぀たり、䞊列領域で発生したすべおのオブゞェクトの型の必須の明瀺的な指瀺が必芁です。



 #pragma omp parallel private(sum, core_num) shared(x, y, z) default(i)
      
      





たたは



 #pragma omp parallel private(i, sum, core_num) shared(x, y, z) default(none)
      
      





削枛オプション



8぀のコアにスカラヌ積を実装する考慮された䟋では、1぀の欠点に泚意したした。コアの郚分的な結果を結合するにはコヌドを倧幅に倉曎する必芁があり、面倒で䞍䟿です。同時に、openMPの抂念は、シングルコアからマルチコアぞの実装、たたはその逆ぞの移行における最倧の透明性を意味したす。前のセクションで説明したプログラムを簡玠化するために、削枛オプションを䜿甚できたす。



削枛オプションを䜿甚するず、カヌネルの結果を結合する必芁があるこずをコンパむラヌに䌝えるこずができ、そのような結合の芏則を蚭定できたす。削枛オプションは、倚くの最も䞀般的な状況に察応しおいたす。オプションの構文は次のずおりです。



 reduction ( :  )
      
      





identifier-プラむベヌトな結果を結合するどの操䜜を実行するかを決定したす。特定の結果を衚す倉数の初期倀を蚭定したす。

オブゞェクトのリスト—カヌネルの操䜜の特定の結果を定匏化するために䜿甚される倉数の名前


珟圚OpenMP暙準で提䟛されおいる削枛オプションを䜿甚するためのすべおの可胜なオプションを衚1に瀺したす。



可胜な操䜜識別子+、*、-、、|、^、&&、||、max、min



察応する倉数の初期倀0、 1、0、0、0、0、1、0、このタむプの最小倀、このタむプの最倧倀。



スカラヌ補品プログラムでは、sum倉数に識別子「+」を指定した瞮玄オプションを䜿甚したす。



 float x[N]; float y[N]; void dotp (void) { int i; float sum; #pragma omp parallel for private(i) shared(x, y) reduction(+:sum) for (i=0; i<N; i++) sum += x[i]*y[i]; }
      
      





実行結果



 [TMS320C66x_0] sum= 331.0
      
      





プログラムは正しい結果を提䟛するず同時に、非垞にコンパクトに芋え、元の「シヌケンシャル」コヌドずの最小限の違いのみを含みたす



OpenMP Sync



マルチコアプロセッサで発生する䞻な問題の1぀は、コアの同期の問題です。耇数のコアが1぀の䞀般的な問題を同時に解決する堎合、原則ずしお、アクションを調敎する必芁がありたす。あるコアが別のコアよりも早くいく぀かの機胜を実行し始めるず、䞀般的な䜜業の結果が䞍正確になるこずがありたす。すべおのカヌネルが1぀の共通倉数で動䜜するようにしたずきに、すでにこの問題に郚分的に遭遇したした。矛盟は間違った結果をもたらしたした。



䞀般的な堎合、カヌネルの同期は、プログラムコヌドの特定のポむントですべおのカヌネルたたはその必芁な郚分が䜜業を停止し、特定のポむント同期ポむントに到達するこずを他のカヌネルに通知し、他のすべおのカヌネルがこのポむントに到達するたで䜜業を続行しないずいう事実から成りたす同期。 1぀の䞊列フラグメントを完了するず、ニュヌクリアスは互いに埅機し、次のフラグメントに移動しお䜜業を調敎したす。コアたたは䞊列スレッドの同期は、実行可胜なプログラムコヌドによる同期だけでなく、デヌタによる同期も意味するこずに泚意するこずが重芁です。キャッシュの同期がありたすキャッシュで倉曎されたデヌタのメむンメモリぞの戻り。これは非垞に重芁なポむントです。OpenMPコンセプトのカヌネルは䞻に共有メモリで動䜜し、そのフラグメントは各コアのロヌカルメモリにキャッシュされたす。その結果、最初のコアのキャッシュず共有メむンメモリの非同期化により、1぀のコアによっお倉曎された共有倉数の倀が他のコアによっお正しく読み取られない堎合がありたす。



OpenMPには、暗黙的ず明瀺的の2皮類の同期がありたす。暗黙的な同期は、䞊列領域の終わり、およびomp for、ompセクションなどを含む䞊列領域内に適甚できるいく぀かのディレクティブの終わりで自動的に発生したす。この堎合、キャッシュの同期も自動的に行われたす。



問題を解決するためのアルゎリズムが、自動同期が提䟛されない䞊列領域内のプログラムのそれらのポむントでカヌネルを同期する必芁がある堎合、開発者は明瀺的な同期を䜿甚できたす-特別なディレクティブを䜿甚しおOpenMPコンパむラに、プログラムのこのポむントで同期が必芁であるこずを明瀺的に瀺したす これらのディレクティブのメむンを怜蚎しおください。



バリア指什



バリアディレクティブは次のように蚘述されたす。



 #pragma omp barrier
      
      





䞊列領域内の䞊列OpenMPストリヌムの同期ポむントを明瀺的に蚭定したす。以䞋は、ディレクティブの䜿甚䟋です。



 #define CORE_NUM 8 float z[CORE_NUM]; void arr_proc(void) { omp_set_num_threads(CORE_NUM); int i, core_num; float sum; #pragma omp parallel private(core_num, i, sum) { core_num=omp_get_thread_num(); z[core_num]=core_num; #pragma omp barrier sum = 0; for(i=0;i<CORE_NUM;i++) sum=sum+z[i]; #pragma omp barrier z[core_num]=sum; } for(i=0;i<CORE_NUM;i++) printf("z[%d] = %f\n", i, z[i]); }
      
      





このプログラムでは、次の状況をシミュレヌトしたした。信号の凊理に、z配列でデヌタを生成するステップ、z配列でデヌタを凊理するステップ、z配列で凊理結果を蚘録するステップを含めたす。プログラムの堎合、最初の段階で、各コアは共有メモリにあるz配列の察応するセルにその番号を曞き蟌みたす。さらに、すべおのコアは入力配列の同じ凊理を実行したす。぀たり、芁玠の合蚈を芋぀けたす。次に、すべおのカヌネルが、カヌネル番号に察応するz配列のセルに結果を曞き蟌みたす。結果ずしお、配列内のすべおのセルは同じでなければなりたせん。ただし、これはバリアディレクティブがなければ発生したせん。配列zのすべおのセルは異なり、䞀般的には任意です。第1段階から第2段階に移行するず、カヌネルはお互いを埅たずに、ただ準備ができおいないデヌタの凊理を開始したす。2番目の段階から3番目の段階に移行するず、カヌネルは結果をz配列に曞き蟌み始めたすが、他のカヌネルはこの配列の倀を読み取っお凊理に䜿甚できたす。䞡方のバリアディレクティブの存圚のみが、プログラムの正しい実行ず、z配列のすべおの芁玠での同じ蚈算結果の蚘録を保蚌したす。実行可胜コヌドによる同期は、デヌタの同期-キャッシュ同期も意味したす。



重芁な指什



重芁なディレクティブは次のように曞かれおいたす。



 #pragma omp critical [ ]
      
      





たた、䞀床に1぀のコアのみが実行できる䞊列領域内のコヌドを遞択したす。



, . . , , , , . , . , . , , : , , ; .



信号凊理の堎合、状況は同様です。特定のコヌドフラグメントを耇数のコアで同時に実行できないこずを凊理アルゎリズムが瀺唆しおいる堎合、そのようなフラグメントはcriticalディレクティブによっお区別できたす。このディレクティブの適甚䟋は次のようになりたす。



 #define CORE_NUM 8 #define N 1000 #define M 80 void crit_ex(void) { int i, j; int A[N]; int Z[N] = {0}; omp_set_num_threads(CORE_NUM); #pragma omp parallel for private (A) for (i = 0; i < M; i++) { poc_A(A, N); #pragma omp critical for (j=0; j<N; j++) Z[j] = Z[j] + A[j]; } }
      
      





このプログラムでは、配列Aの凊理配列ず配列Zの凊理結果の蓄積が1サむクルでM回繰り返され、マルチコア実装に移行するず、凊理サむクルの反埩が8コアに分散されたす。この堎合、配列Aはプラむベヌト配列ずしお、぀たり各コアで独立しお凊理されたす。これらの手順には䟝存関係がないため、凊理はすべおのコアで䞊行しお実行できたす。蓄積するず、すべおのコアの䜜業結果が共通のZ配列に結合されたす。コアを同期するための特別な措眮が取られない堎合、䞊列スレッドは1぀の共通リ゜ヌスにアクセスし、互いの䜜業に゚ラヌを導入したす。゚ラヌを防ぐために、この堎所で䞊列スレッドが実行されるのを防ぐこずができたす。リ゜ヌスこの堎合はコヌドの䞀郚を匕き継ぐ最初のコアが完党にそれを所有し、すべおのステップを完了するたで。残りのコアは、コヌドのクリティカルセクションの開始時にリ゜ヌスが解攟されるのを埅ちたす。実際、䞊列領域内の順次凊理に移行しおいたす。



コヌドでは、クリティカルセクションを次の構造に眮き換えたす。



  #pragma omp critical (Z1add) for (j=0; j<N; j++) Z1[j] = Z1[j] + A[j]; #pragma omp critical (Z2mult) for (j=0; j<N; j++) Z2[j] = Z2[j] * A[j];
      
      





珟圚、2぀の重芁なセクションがありたす。1぀は、栞の仕事の結果を合蚈するこずによっお組み合わせるこずです。もう1぀は、乗算です。䞡方のセクションは1぀のコアでのみ同時に実行できたすが、異なるセクションは異なるコアで同時に実行できたす。領域名がクリティカルディレクティブデザむンに远加された堎合、別のカヌネルがこの領域で動䜜する堎合のみ、カヌネルはコヌドぞのアクセスを拒吊されたす。リヌゞョンに名前が割り圓おられおいない堎合、他のカヌネルがどのリヌゞョンでも接続されおいなくおも、他のカヌネルがそれらのリヌゞョンのいずれかで動䜜する堎合、カヌネルはクリティカルリヌゞョンを入力できたせん。



アトミックディレクティブ



アトミックディレクティブは次のように蚘述されたす。



 #pragma omp atomic [read | write | update | capture]
      
      





前の䟋では、異なるコアが同じ領域から同時にコヌドを実行するこずは犁止されおいたした。しかし、これは綿密な調査では合理的に思えないかもしれたせん。結局のずころ、共有リ゜ヌスぞのアクセスの競合は、異なるカヌネルが同じメモリセルに同時にアクセスできるずいう事実にありたす。 1぀のコヌドのフレヌムワヌク内で、異なるメモリセルにアクセスしおも、結果が歪むこずはありたせん。 atomicディレクティブを䜿甚するず、カヌネルの同期をメモリ芁玠にバむンドできたす。圌女は次の行でメモリ操䜜はアトミックである-䞍可解であるこずを指摘したすカヌネルが䜕らかのメモリセルで操䜜を開始するず、最初のコアが動䜜を終了するたで他のすべおのカヌネルに察しおこのメ​​モリセルぞのアクセスが閉じられたす圌女。アトミックディレクティブには、オプションを瀺すメモリで実行される操䜜の皮類読み取り/曞き蟌み/倉曎/キャプチャ。䞊蚘の䟋は、atomicディレクティブを䜿甚するず、次のようになりたす。



 #define CORE_NUM 8 #define N 1000 #define M 80 void crit_ex(void) { int i, j; int A[N]; int Z[N] = {0}; omp_set_num_threads(CORE_NUM); #pragma omp parallel for private (A) for (i = 0; i < M; i++) { poc_A(A, N); for (j=0; j<N; j++) { #pragma omp atomic update Z[j] = Z[j] + A[j]; } }
      
      





理論的には、アトミックディレクティブを䜿甚するず、サむクルの完党な順次実行から、芁求された配列芁玠の数が異なるコアで䞀臎する堎合に個々のメモリアクセス操䜜のみの順次実行に進むため、凊理時間が倧幅に短瞮されたす。ただし、実際には、このアむデアの有効性は、その実装方法によっお異なりたす。たずえば、アトミックディレクティブを䜿甚したカヌネル同期が、ルヌプの各反埩で共有メモリにあるフラグの読み取りに枛るず、ルヌプの実行時間が倧幅に増加する可胜性がありたす。蚀い換えるず、クリティカルディレクティブの堎合、サむクル実行時間はMxT1プロセッササむクルになりたす。ここで、Mはコアの数、T1は1぀のコアのサむクル時間です。アトミックディレクティブの堎合、サむクルタむムはT2プロセッササむクルになりたす。この堎合、アトミックディレクティブを含むサむクルには远加の同期コヌドが含たれ、時間T2は時間T1のM倍以䞊になるこずがありたす。





この蚘事では、OpenMPの䞻芁な構成芁玠である、マルチコアプロセッサに実装するための゜フトりェアのコンパむラによる自動䞊列化に䜿甚される高レベルプログラミング蚀語C / C ++の拡匵機胜に぀いお説明したした。この蚘事の特城は、デゞタル信号凊理システムのオリ゚ンテヌションず、Texas Instrumentsの8コアDSP TMS320C6678でのサンプルプログラムの実行の説明です。 OpenMPの䞻な利点は、シングルコアからマルチコア実装ぞの移行が容易なこずです。デヌタ亀換や同期を含むすべおのコアむンタラクションタスクは、コンパむル段階で接続される暙準OpenMP関数によっお実行されたす。ただし、開発の利䟿性は、通垞、結果の゜リュヌションの効率の䜎䞋に぀ながりたす。この蚘事では、OpenMPのツヌリングコストに぀いおは説明したせん。これに別の仕事を捧げるこずが蚈画されおいたす。



それにも関わらず、OpenMPディレクティブのコストは非垞に高く、単䜍ず数䞇クロックサむクルで枬定されたす。したがっお、䞊列化は比范的高いレベルでのみ意味がありたす。䞊列領域内で蚈算負荷が倧きく、ほずんどの堎合、カヌネルは盞互䜜甚せずにタスクを凊理したす。



OpenMP暙準は共通のむデオロギヌを芏定しおいるこずにも泚意する必芁がありたす。OpenMPの有効性は、特定のプロセッサプラットフォヌム甚のOpenMP関数の実装に䟝存したす。そのため、プロセッサTMS320C6678甚にTexas Instrumentsが開発したOpenMP 1および2のバヌゞョンは倧きく異なりたす。2番目のバヌゞョンは、倚数のハヌドりェアメカニズムを䜿甚しおニュヌクリアスの盞互䜜甚を加速し、最初のバヌゞョンよりもはるかに効果的です。その埌の䜜業では、OpenMP機胜を実装するための䞻芁なメカニズムを明らかにする予定です。これらの機胜に関連するコストを分析したす。OpenMPディレクティブの実装のテスト時間の芋積もりを生成したす。このメカニズムの䜿甚効率を改善するためのアドバむスを䜜成したす。



文孊
1. G. Blake, RG Dreslinski, T. Mudge, «A survey of multicore processors,» Signal Processing Magazine, vol. 26, no. 6, pp. 26-37, Nov. 2009.

2. LJ Karam, I. AlKamal, A. Gatherer, GA Frantz, «Trends in multicore DSP platforms,» Signal Processing Magazine, vol. 26, no. 6, pp. 38-49, 2009.

3. A. Jain, R. Shankar. Software Decomposition for Multicore Architectures, Dept. of Computer Science and Engineering, Florida Atlantic University, Boca Raton, FL, 33431.

4. Web- OpenMP Architecture Review Board (ARB): openmp.org .

5. OpenMP Application Programming Interface. Version 4.5 November 2015. OpenMP Architecture Review Board. P. 368.

6. OpenMP 4.5 API C/C++ Syntax Reference Guide. OpenMP Architecture Review Board. 2015幎。

7. J. Diaz, C. Muñoz-Caro, A. Niño. A Survey of Parallel Programming Models and Tools in the Multi and Many-Core Era. IEEE Transactions on Parallel and Distributed Systems. – 2012. – Vol. 23, Is. 8, pp. 1369 – 1386.

8. A. Cilardo, L. Gallo, A. Mazzeo, N. Mazzocca. Efficient and scalable OpenMP-based system-level design. Design, Automation & Test in Europe Conference & Exhibition (DATE). – 2013, pp. 988 – 991.

9. M. Chavarrías, F. Pescador, M. Garrido, A. Sanchez, C. Sanz. Design of multicore HEVC decoders using actor-based dataflow models and OpenMP. IEEE Transactions on Consumer Electronics. – 2016. – Vol. 62. – Is. 3, pp. 325 – 333.

10. M. Sever, E. Çavus. Parallelizing LDPC Decoding Using OpenMP on Multicore Digital Signal Processors. 45th International Conference on Parallel Processing Workshops (ICPPW). – 2016, pp. 46 – 51.

11. A. Kharin, S. Vityazev, V. Vityazev, N. Dahnoun. Parallel FFT implementation on TMS320c66x multicore DSP. 6th European Embedded Design in Education and Research Conference (EDERC). – 2014, pp. 46 – 49.

12. D. Wang, M. Ali, ―Synthetic Aperture Radar on Low Power Multi-Core Digital Signal Processor,‖ High Performance Extreme Computing (HPEC), IEEE Conference on, pp. 1 – 6, 2012.

13. . . , . . . - . ., 2007, 138 .

14. . . . . . , 2006, 90 .

15. .. . OpenMP. . 2009 , 78 .

16. .. . OpenMP. .: 2012, 121 .

17. TMS320C6678 Multicore Fixed and Floating-Point Digital Signal Processor, Datasheet, SPRS691E, Texas Instruments, p. 248, 2014.



All Articles