OpenMP」の日本語参考訳です。このホワイトペーパーでは、既存のシリアルコードで並列処理の可能性を発見し、最適化された高いパフォーマンスの並列コードに変換します。可能性を見つける際の基本事項について説明します。スレッド化により、複数のスレッドを使用して大きなタスクや主要タスクの大部分を同時に実行することで、アプリケーションのパフォーマンスが大幅に向上します。既存のシリアルコードをスレッド化する場合には特定の課題が伴います。構造化された並列コードの開発は幅広いトピックであり、多数の書籍があります。このホワイトペーパーは、インテルのエンジニアによって実証された方法を基にして、既存のシリアルコードを並列化することを目的としています。つのセクションで構成されています。読んでもかまいません。利用して同時に実行し、一定の時間内により多くのタスクを完了したり、一定のタスクをより短時間で完了することができます。並列実行されるコードは、異なるデータを処理する同一コードの複数のインスタンスであることも、あるいは全く異なるタスクを処理する別々のコードであることもあります。最近のプロセッサー・マイクロアーキテクチャーでは、その利点を活用するために、可能な場合はコードをスレッド化し、同時かつ並列に実行したほうが良いでしょう。並列性と並行性には関連性がありますが、同じものではありません。それぞれのコードへの影響を理解することは重要です。以上のスレッドが同時に進行中の状態のことで、必ずしも同時に実行中でなくてもかまいません。複数のスレッドがパイプラインにあっても、同時にリソースを使用していないため、並列実行と同じリスクや利点はありません。並列性とは、複数の並行スレッドが同時に実行中の状態のことで、並行実行にはない多くの利点とリスクがあります。スレッドを同時に実行することで、パフォーマンスと計算リソースの使用率を向上することができます。複数のスレッドはアプリケーションをより複雑にし、デバッグが困難になります。ような問題の特定に役立つツールもあります)。スレッド化と並列性を効率良く実装することは、アプリケーションのパフォーマンスと計算サイズに応じたスケーリングにおいて、大きなメリットをもたらします。つのタスクを最短時間で完了することです。これは、作業を小さな単位に分割し、それぞれにリソースに割り当てて並列に処理することで実現できます。問題は、作業をどのように分割するかです。その両方か?これらの問いは、コードに内在する並列性の種類を特定するのに役立ちます。これはコードの並列化方法に大きく影響します。機能分割は、作業を機能別に分割します。これは、個別のタスク数に対応して作業量がスケーリングする場合に最良の方法です。機能分割は、タスクベースの並列化とも呼ばれます。人で作業すると完成までにかかる時間は最長となります。作業を行えば、より効率良く短時間で完成することができます。コンクリート技師が基礎を作り、大工が骨組みを組み立て、電気技師が配線を引く間に配管工が配管を取り付け、左官工が壁を塗り、内装業者が内装を行うというように、作業を分割します。個別の作業を並列に行うことで、完成までの時間を短縮できます。自動車の組み立て工程も機能分割の一例です。それぞれの工程で作業員は異なる作業を行い、次の工程へパーツを渡します。台の自動車が完成します。これは、データ量に対応して作業量がスケーリングする場合に最良の方法です。複数の答案用紙を採点する場合、複数の採点者で作業を分担したほうが短時間で採点を完了することができます。地球に落下したスカイラブ宇宙ステーションのパーツの捜索も、データ分割の概念を示す一例です。捜索範囲を分割して、複数の捜索チームが同じ作業を行います。一般的なアプリケーションでは、道行く大勢の人々の写真といった膨大なデータの中から目の色などの特定のデータパターンを探しますが、このような処理はデータを分割し、それぞれのパターンに対して同じ検索を行うことでより迅速に行うことができます。最適に並列化されたコードはパフォーマンスを大幅に向上させますが、結果が正しくなければ、アルゴリズムとコードの本来の目的を果たすことができません。(これは場合によっては可能です)。並列化された乱数生成アルゴリズムやシーケンシャル・アルゴリズムなどは、この判断が難しいでしょう。丸めモードの浮動小数点計算の組み合わせでは、正しい結果になるように注意が必要です。別記事に掲載されています。実行時間を短縮したい場合、達成可能なスピードアップを特定するのにアムダールの法則が役立ちます。達成可能な実行時間の短縮は、並列化するコード中のシリアル領域のサイズと利用可能な計算リソースによって制限されます。実行時間に依存することが明白です。説明スピードアップを最大にするには、コードのシリアル実行時間を最小に抑え、並列処理の可能性を最大限に引き出す必要があります。アルゴリズム中の明らかに並列化可能なコード領域を並列化するだけでなく、場合によってはより効率良く並列に実行できるようにシリアル・アルゴリズム自身の再設計も必要です。通常、並列化されたコードはパフォーマンスが向上しますが、必ずしも最良のソリューションとは限りません。場合によっては、高度に最適化されたシリアルコードのほうが、同じアルゴリズムの並列バージョンよりも高速なこともあります。前のセクションでは、並列化の基本概念を説明しました。ここでは、並列化を実装するためのいくつかの方法を紹介し、潜在的な並列処理の可能性を見つける方法を説明します。並列化の実装方法アプリケーションを並列化するには、いくつかの方法があります。どの方法を採用するかは、個々の要因によって決まります。コードを実行する計算プラットフォーム。コアのワークステーションなど。(粗粒度または細粒度)。通常、これは計算プラットフォームに影響されます。粒度は、各スレッドが行う作業量と似ています。組込み式のロケット制御システムの並列化や、スーパー・コンピューターで実行される薬物のモデリング・アプリケーションの並列化など。主目的はスループットの向上か、あるいは実行時間の短縮か?次に、最も一般的な並列化モデルを説明します。広範な分散処理システムで使用される分散型マルチスレッド・モデルです。明示的なメッセージを使用して、計算システム間で情報の受け渡しを行います。メッセージの送信/応答を行います。は粗粒度の並列化で使用されます。ように、ハイパフォーマンスな通信ネットワークで相互接続されたスタンドアロン・サーバーからなるクラスターが挙げられます。使用する分散型計算プラットフォームでは、ノード間でメッセージとデータの受け渡しを行わなければならないため、ノード間の通信がシステム全体のパフォーマンスに影響します。あるノードで必要なデータが別のノードに保存されている場合があるため、メモリー・アーキテクチャーとパーティショニングもパフォーマンスに大きく影響します。そのため、プログラム全体の設計では、システムで最適なパフォーマンスが得られるように、データモデルと通信の最適化を考慮しなければいけません。スレッド、またはその他のスレッドを使用して、コード内で明示的にスレッドを作成します。スレッド化は開発者によって完全に制御可能なため、開発者のニーズを正確に満たすようにコードをスレッド化できます。明示的なスレッド化はコードを複雑にしますが、開発者はスレッドの生成、使用、破棄の方法とタイミングをより細かく制御することができます。細粒度の並列化でも、粗粒度の並列化でも使用可能で、ほかのスレッド化モデルと組み合わせることもできます。それにより開発者の課題が増え、アプリケーション全体がより複雑になります。使用して、開発者がスレッド化するコード領域を指示します。対応するコンパイラーがその情報に基づきコンパイル時に自動で必要なスレッドを生成します。この方法では、スレッド化に伴う開発者の作業は軽減されますが、スレッドの実装方法を細かく制御することはできません。コンパイラーに指示する並列化は、非常に柔軟で、既存のシリアルコードでも容易に使用することができます。開発者としての経験から、これは並列コードのラピッド・プロトタイピングに最適な方法といえます。そこで、このホワイトペーパーでは、特にこの並列化の実装方法に最適な箇所の特定に注目して説明します。プロセッサーで並列処理を最適化するためのさまざまなライブラリーを提供しています。これらのライブラリーは、特定のアプリケーション・ドメイン向けのアルゴリズムを並列化します。アプリケーション向けに高度に最適化され、広範囲にスレッド化された数学ルーチンを含むライブラリーです。版ではサポートされません)、スパースソルバー、高速フーリエ変換、ベクトル演算などが含まれています。プロセッサー向けにパフォーマンスを最適化します。クロスプラットフォームの互換性が得られます。マルチメディア、データ処理、通信アプリケーション向けに高度に最適化された、ソフトウェア関数を備えたマルチコア対応の広範囲なライブラリーです。使用される基本的なアルゴリズムを含む、最適化された関数を多数提供します。スレッドをタスクに抽象化し、安定性を備えた、移植性とスケーラビリティーに優れた並列アプリケーションの開発を支援します。並列化において高レベルの抽象化を提供します。テンプレートとコーディング方法を使って実装し、下位レベルのスレッド化の詳細をライブラリーに任せることができます。異なるプロセッサー・アーキテクチャーやオペレーティング・システム間で移植可能です。より、プログラミングにかかる時間を短縮し、スケーラブルなパフォーマンスと保守が容易なコードを得られます。可能性を見つけるこれまで並列化の基本といくつかの実装方法について見てきましたが、「どのようにしたら並列処理の可能性を見つけられるのか?」という疑問が残っています。次のセクションでは、並列実行に適した候補を見つけ、それらを並列化する際に直面する一般的な課題の克服方法について見てみましょう。通常、この疑問は、コードをプロファイリングして、プロセッサーが時間を費やしている場所を特定しない限り、判断するのが困難です。ようなパフォーマンス・アナライザーを使ってプロファイリングすると、パフォーマンス・ボトルネックが発生している場所を特定することができます。その結果を基に、並列化やアルゴリズムの最適化の可能性がある場合は、作業すべき場所を特定することができます。既存のシリアルコードで並列化候補を特定するさまざまな方法については、多数の書籍で取り上げられています。開発者として実際に作業を行ってきた経験から、最も単純なアプローチが最適であるといえます。ホットコードを見つけることが重要です。ホットコードとは、アプリケーションにおいてほかよりも多くの時間が費やされている領域のことです。(ただし、常にそうであるとは限りません)。ようなサンプリング・ツールを使用します。データを収集するには、現実的なシナリオでアプリケーションを実行するワークロードが必要です。(これらのツールへのリンクは、「関連情報」セクションを参照してください)。適切なワークロードとデータを収集するツールの準備ができたら、並列化候補の特定は簡単です。時間を費やしているコード領域を探すだけです。その領域に関連した関数別にホットコードを分類する必要があります。ここでも、通常、最適な候補は最も時間がかかったコードになります。見てみると良いでしょう。通常、関連する親関数にそれらのホットコードをマップしたほうが開発は容易になります。関数ブレークダウン・テーブルいくつかの候補が見つかったら、次のステップではそれらが並列化可能かどうか判断します。並列化可能な候補か?シリアルコードを並列化する方法は色々あります。本来ループによる反復処理は、ほかの処理と比べて並列化に適しています。このホワイトペーパーでも取り上げているように、マルチスレッドの実装方法は多数あります。プラグマを使ったサンプルに絞って見ていきましょう。処理が軽く、移植性に優れ、必要に応じてシリアルコード中に簡単に記述できます。)シリアルコードを並列化するのに、ループが最適な候補であることは疑問の余地はありません。構造を適用しやすいためです。ワークシェアリングとは、大きな既存の作業を複数の並列に実行されるスレッド間で分割し、それらのスレッド間で作業を分配することです。データ分割の一般的な例です。ループ次のループについて、並列化可能かどうか考えてみましょう。b[i];ループが並列化に適しているかどうか判断するため、最初にいくつかの項目を確認する必要があります。重要なのは、次の項目です。現在の反復がその前の反復から独立しているか?つまり、ある反復がその前の反復からの値に依存していてはなりません。代入されている反復以外で利用されることはありません。そのため、このコードの並列化を妨げるループの依存性はありません。使用して次のようにコードを変更することで並列化できます。指示句は、このワークシェアリング構造に到達したスレッドのチーム間でループの反復を分配するようにコンパイラーに指示します。対応するコンパイラーでコンパイルすると、次のような動作になります。各スレッドには異なる反復のセットが割り当てられます。つのスレッドになります。この簡単な変更により、実行時間が大幅に短縮されます。倍も性能が向上したことになります。精通していなくても、プラグマベースの並列化はシリアルコードへの統合が非常に容易で、大きな利点が得られることが分かります。複雑なループもう少し複雑なループについて考えてみましょう。このループでは、並列化に伴いいくつかの問題に直面しますが、ここではそれらの問題を克服する手順を見ていきます。値を計算する数値積分の例です。ここでは、基本的な積分を求める一般的なコードを使用します。区間の積分を計算します。微分・積分の授業から、この積分の解を覚えている方もいるかもしれません。