現在と将来の OpenMP* API 仕様

HPC

この記事は、インテルの The Parallel Universe Magazine 27 号に収録されている、OpenMP* 5.0 の機能を初めて紹介した章を抜粋翻訳したものです。

OpenMP* API には 20 年の歴史があります。その登場以来、ハードウェアとソフトウェアの進歩とともに、新しいハードウェアのプログラミングに対応するさまざまな機能が追加されてきました。2013 年にリリースされたバージョン 4.0 から、OpenMP* 言語はヘテロジニアス・プログラミングと SIMD プログラミングをサポートしました。同様に、2008 年には、タスク構文の追加により、不規則な並列処理を含むプログラムのサポートが向上しました。OpenMP* Technical Report 4: Version 5.0 Preview 1 (略称 TR4) は、OpenMP* 言語の進化における次のステップです。タスク・リダクションの追加、SIMD 並列処理の拡張が行われ、ヘテロジニアス・プログラミングの生産性が大幅に向上します。この記事では、既存の OpenMP* 機能を確認した後、TR4 をサポートする実装で追加される機能を紹介します。

タスクベースのプログラミング: タスクで表現する

タスクベースのプログラミングは、不規則な並列処理 (再帰アルゴリズム、グラフのトラバース、非構造化データを操作するアルゴリズムなど) が必要なアプリケーションにとって重要な概念です。OpenMP* バージョン 3.0 から、OpenMP* ランタイムシステムのスケジューラーに渡される小さな単位のワークの並列実行を容易に表現する方法として、タスク構文が提供されました。

void taskloop_example() {
#pragma omp taskgroup
    {
#pragma omp task
        long_running_task()  // 同時に実行可能

#pragma omp taskloop collapse(2) grainsize(500) nogroup
        for (int i = 0; i < N; i++)
            for (int j = 0; j < M; j++)
                loop_body();

図 1. 新しい taskloop 構文で OpenMP* タスクを利用する例

図 1 は、long_running_task 関数を実行する OpenMP* タスクを生成し、その後 taskloop 構文を使用してループを並列化する例を示しています。この構文は OpenMP* 4.5 で追加されたもので、プログラマーが OpenMP* タスクを使用してループを簡単に並列化できる糖衣構文を提供します。この構文は、ループの反復空間をチャンクに分割し、それぞれのチャンクに対して 1 つのタスクを生成します。細かい制御ができるように、いくつかの節 (例えば、タスクあたりのワークの量を制御する grainsize や i ループと j ループを 1 つのループにまとめる collapse) をサポートしています。TR4 では、taskgroup、task、taskloop 構文に生成されたタスク間でリダクションを行う新しい節を定義することにより、OpenMP* タスクの表現が拡張されます。

図 2 は、リンクリストを処理してリストの全要素の最小値を調べるタスクの例を示しています。parallel 構文は、ワーカースレッドがタスク実行で利用できるように並列領域を作成します。single 構文は、リンクリストのトラバースを 1 つのスレッドの実行に制限し、omp タスクにより各リスト項目に 1 つのタスクを生成します。これは OpenMP* で生産と消費パターンを実装する一般的な方法です。 TR4 のタスク・リダクションは、OpenMP* バージョン 4.0 で追加された taskgroup 構文を使用します。この構文は、タスクを論理的にグループ化し、グループのすべてのタスクの完了を待機する方法を提供します。TR4 では、図 2 に示すように、task_reduction 節によりリダクションを行うように、taskgroup 構文が拡張されます。この節が構文に追加されると、taskgroup 領域の最後で個々のタスクにより収集された部分結果がすべて集計され、最終的な結果が生成されます。リダクション操作に関係するタスクには、taskgroup の reduction 節と一致する in_reduction 節が必要です。

TR4 から、taskloop 構文はタスク・リダクション・セマンティクスによる reduction 節および in_reduction 節をサポートします。reduction 節が taskloop 構文に含まれていると、ループの最後で要求されたリダクション操作を実行する、暗黙的なタスクグループが作成されます。in_reduction 節が追加されると、taskloop 構文により生成されたタスクは外側の taskgroup 領域のリダクションに関係します。

int find_minimum(list_t * list) {
    int minimum = INT_MAX;
    list_t * ptr = list;
#pragma omp parallel 
#pragma omp single
#pragma omp taskgroup task_reduction(min:minimum)
    {
        for (ptr = list; ptr ; ptr = ptr->next) {
#pragma omp task firstprivate(ptr) in_reduction(min:minimum)
            {
                int element = ptr->element;
                minimum = (element < minimum) ? element : minimum;
            }
        }
    }
    return minimum;
}

図 2. タスク・リダクションを使用したリンクリストのトラバースと最小値の計算

タイトルとURLをコピーしました