LLVM/Clang で OpenMP* 4.0 機能を試してみる

インテル® DPC++/C++ コンパイラー

この記事は、インテル® デベロッパー・ゾーンに掲載されている「Testing Out OpenMP 4.0 Features in LLVM/Clang」 (http://goparallel.sourceforge.net/testing-openmp-4-0-features-llvmclang/) の日本語参考訳です。


LLVM ツールに含まれる Clang コンパイラーには、OpenMP* サポートを追加する特別なブランチがあります。この記事では、Clang の OpenMP* 4.0 機能を試し、その結果について見てみます。

早速、Clang で OpenMP* 4.0 機能を試してみましょう。実際の作業に入る前に、Clang コンパイラーの OpenMP* バージョンをビルドするためのポイントについて説明します。http://goparallel.sourceforge.net/building-openmp-branch-llvmclang/ のビデオ (英語) も参考になります。まず、大きなメモリー容量が必要です。ここでは、8GB のサーバーを使用しました。2GB のサーバーも試しましたが、失敗しました。リンカーが正しく動作せず、次のようなエラーメッセージが出力されました。

collect2: error: ld terminated with signal 9 [Killed] (ld がシグナル 9 で終了しました)

仮想マシンのメモリーを増やすことでこの問題は解決しました。(スワップ領域を増やすことでも解決できるようですが、試しませんでした。)

このエラーが発生し、メモリーを増やした場合、次のような別のエラーが出力される可能性があります。

libclang.so: file not recognized: File format not recognized (ファイルを認識できません: ファイル形式を認識できません)

この 2 つ目のエラーは、最初のビルドでリンカーが失敗し、ファイルの一部のみがビルドされたことが原因です。そのため、メモリーを増やした後、既存の libclang.so ファイルを削除する必要があります。このファイルは、build/Debug+Asserts/lib ディレクトリーにあります。

削除後、再度 make コマンドでビルドを行います。(このほかにも、コンパイラー・ターゲットの推測に関するエラーが出力されることがあります。その場合は、build/Debug+Asserts/bin ディレクトリー以下の Clang 実行ファイルを削除しなければならないことがあります。ファイルサイズを確認し、0 の場合はファイルを削除してから、再度 make を実行してみてください。)

コンパイラーのビルドが完了したら、いくつかの OpenMP* 4.0 機能を使用してみましょう。ここでは、4.0 の新機能のみテストします。新機能の一覧は、クイック・リファレンス・カード (英語) で確認できます。4.0 の新機能は、機能名の横に 4.0 と表記されています。

ヒント: 機能が存在しない、あるいはプラグマ名が正しくない場合は直ぐに分かります。-fopenmp コンパイラー・オプションで OpenMP* 機能を有効にした場合、Clang コンパイラーは認識できない OpenMP* プラグマを検出するとエラーを出力します。以下はその一例です。

test1.cpp:6:13: error: expected an OpenMP directive (エラー: OpenMP* 宣言子を指定してください)

SIMD 操作のテスト

以下は、SIMD 宣言子の動作を確認するためのサンプルプログラムです。このプログラムは、この機能が動作するのを確認するためのものであって、(特に cout はスレッドセーフでないため) 有効な 処理は何も行いません。

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

int main() {
    #pragma omp simd
    for (int i=0; i<10; i++) {
        cout << i << endl;
    }
}

このコードは、問題なくビルドすることができます。SIMD 宣言子の後に for ループ以外のコードを配置すると、次のようなメッセージが出力されます。

test1.cpp:7:5: error: only for-loops are allowed for ‘#pragma omp simd’ (エラー: for ループのみ ‘#pragma omp simd’ で許可されています。)

for ループの SIMD 宣言子を次のように少し変更してみます。

#pragma omp for simd

この場合も、問題なくビルドし、実行することができます。次に、SIMD 関数宣言が動作するか確認します。

#pragma omp declare simd
int test(int x, int y) {
    return x * y;
}

このコードは問題なくビルドし、実行することができます。distribute 節を使用してみます。

#pragma omp distribute simd

これも、そして以下の節も問題なく動作します。

#pragma omp parallel for simd

SIMD 操作はすべて 問題なく動作することが分かりました。

カスタム・リダクション

OpenMP* 4.0 のもう 1 つの重要な機能は、独自のリダクションを宣言できることです。この機能については 2010 年頃から議論されてきました。結論から言うと、機能は実装されていますが、まだ実用レベルではありません。カスタム・リダクションに関する以前のブログ (http://goparallel.sourceforge.net/the-future-of-reducers-in-openmp/) で使用したテストプログラムをビルドしてみたところ、ビルドエラーになり、llvm.org へのバグレポートの送信に関する多量のメッセージが出力されました。reduction 節までは問題なくビルドできますが、reduction 節でコンパイラーがクラッシュします。私のコードに問題がある可能性もありますが、仮にそうであったとしても、コンパイラーはクラッシュせずにエラーを出力すべきでしょう。この件に関して新しい情報が入りましたら、皆さんにお知らせします。

まとめ

ここでは、OpenMP* 4.0 の新機能のうち重要なものを取り上げました。このほかにも、簡単に試すことができる機能があります。Clang の OpenMP* 4.0 への対応はほぼ整ったと言えるでしょう。コンパイラーがクラッシュする件については、今後新しい情報が入り次第、皆さんにお知らせします。target teams や cancellation など、クイック・リファレンス・カードに記載されているいくつかの機能を試してみると良いでしょう。何か大きな発見があった場合は、是非情報を共有してください。

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