この記事は、インテル® デベロッパー・ゾーンに公開されている「Challenges, tips, and known issues when debugging heterogenous programs using DPC++ or OpenMP offload」の日本語参考訳です。
2020 年 11 月 17 日
クロスアーキテクチャー・プログラミングの概要
インテル® oneAPI ツールキットを使用してプログラムでクロスアーキテクチャーのサポートを有効にする方法はいくつかあります。1 つの方法は、提供されるライブラリーを使用することです。これは、API ベースのプログラミング・モデルとも呼ばれます。もう 1 つの方法は、OpenMP* オフロード・ディレクティブまたはデータ並列 C++ (DPC++) を使用したダイレクト・プログラミング・モデルです。この記事では、OpenMP* オフロード・ディレクティブまたはデータ並列 C++ (DPC++) を使用する方法を取り上げます。
oneAPI を使用してヘテロジニアス・プログラムを作成するとき、サポートしているすべてのターゲットでプログラムを正しく動作させるための作業の一環として、デバッグとテストを行う必要があります。ヘテロジニアス・プログラムのデバッグは、従来の CPU プログラムのデバッグよりも複雑です。まず、CPU デバイスでコードをテストおよびデバッグして、プログラムがアルゴリズム的に正しいことを確認してから、インテル® GPU (Gen 9 以降) などの異なるターゲットに切り替える方法を推奨します。
GDB 向けインテル® ディストリビューションはインテル® oneAPI ベース・ツールキットの一部です。使用方法は、Linux* (英語) または Windows* (英語) の入門ガイドを参照してください。大きなカーネルのオフロードのデバッグには課題がつきものです。この後の説明を参照してください。
大きなカーネルを持つアプリケーションをデバッグするときの課題
通常、DPC++ または OpenMP* オフロード・ディレクティブを使用してアプリケーションをビルドした後、カーネルコードをインテル® DPC++/C++ コンパイラーでコンパイルして SPIR*-V 形式のバイトコードにします。アプリケーションをターゲットデバイスで実行すると、JIT コンパイルが行われ、コードがデバイスコードに変換されます。JIT コンパイルは、アプリケーションを異なるデバイスターゲットで実行するたびに行われます。これはデバッグでも同じです。デバッガーの内部でプログラムを再実行するたびに、JIT コンパイルが再度行われます。そのため、大きなカーネルを持つプログラムでは、デバッガーの内部で大幅に速度が低下します。
この動作を高速化する方法は、Ahead Of Time (AOT) コンパイルを使用することです。詳細は、「インテル® oneAPI DPC++/C++ コンパイラー・デベロッパー・ガイドおよびリファレンス- Ahead of Time Compilation (AOT コンパイル)」 (英語) を参照してください。OpenMP* オフロードでの AOT サポートは、将来のアップデートで利用可能になる予定です。
クロスアーキテクチャー・プログラムをデバッグする際のヒント
- CPU ターゲットで開始してプログラムの正当性を確認する
ターゲットデバイスを CPU に設定する方法はいくつかあります。- default_selector を使用する場合は、SYCL_DEVICE_TYPE=CPU を使用します。
- あるいは、コードで直接 cpu_selector を使用します。
- printf を挿入する
printf を使用するとデバッグに役立つことがあります。printf は、カーネルコードでも名前空間 sycl::ONEAPI::experimental でサポートされています。 - 詳細なログ情報を制御する環境変数
DPC++ プログラム環境変数 値 注 SYCL_DEVICE_TYPE CPU|GPU|HOST|ACC SYCL_BE PI_OPENCL|PI_LEVEL0 レベル 0 と OpenCL* 間でバックエンドを変更します。 ZE_DEBUG 1 レベル 0 のトレース情報を出力します。 SYCL_PI_TRACE [1|2|-1] - 1 – DPC++ ランタイムプラグインの基本トレースログを出力します。
- 2 – DPC++ ランタイムプラグインのすべての API トレースを出力します。
- -1 – 「2」に加えて詳細なデバッグメッセージを出力します。
OpenMP* オフロードプログラム
環境変数 値 注 LIBOMPTARGET_DEVICETYPE CPU|GPU|HOST LIBOMPTARGET_DEBUG 1 詳細なデバッグ情報を出力します。
-
Ahead Of Time (AOT) コンパイルを使用して JIT コンパイルの問題を AOT コンパイルの問題にする
AOT の詳細は、「インテル® oneAPI DPC++/C++ コンパイラー・デベロッパー・ガイドおよびリファレンス- Ahead of Time Compilation (AOT コンパイル)」 (英語) を参照してください。AOT を使用すると、JIT コンパイルが行われないため、実行時間を短縮できます。
デバッグに関連する既知の問題と回避策
- DPC++ 拡張「サブグループ」は CPU 上では -O0 (Linux*) または /Od (Windows*) をサポートしていない
この機能はまだ作業中で、将来のアップデートでサポートされる予定です。
現在は、「サブグループ」が含まれているプログラムを -O0 オプションを使用してビルドすると、CPU 上で実行したときにセグメンテーション違反またはコアダンプが発生します。同じプログラムは GPU 上では動作します。
これは -O0 オプションを使用して CPU 上で実行した場合にのみ発生する問題です。-O2 オプションを使用して CPU 上で実行した場合には発生しません。回避策: この問題の回避策はありません。
- -g (Linux*) または /Zi (Windows*) でのバリアサポートがまだ完全に実装されていない
バリアサポート (ワークグループ・バリア、cl::sycl::nd item::barrier) にはバリアのコードが生成されないという既知の問題があります。そのため、コードをデバッグするときに、バリア行にブレークポイントを設定することはできません。
この問題は、将来のアップデートで修正される予定です。回避策: ブレークポイントを前後の行に設定するか、バリアの後にダミー行を追加します。または、上記のデバッグのヒントを使用します。
- -O2 -g (Linux*) または /O2 /Zi (Windows*) でのカーネルコードのデバッグ情報生成のサポートが非常に制限されている
GPU 上で最適化されたコードをデバッグする場合、この制限が大きな課題となります。
現在、-O2 -g でのカーネルコードのデバッグ情報はまだ完全に実装されていないため、oneapi-gdb などのデバッガーでのデバッグは推奨しません。回避策: これらの問題は CPU 上では発生しないため、CPU 上でプログラムをデバッグして機能が正しいかどうかを確認します。または、上記のデバッグのヒントを使用します。
- GPU 上で -O0 -g (Linux*) または /Od /Zi (Windows*) を使用すると JIT コンパイルに時間がかかる
GPU で -O0 -g を使用して JIT コンパイルを行うと、プログラムがハングしたと思われるほど時間がかかることがあります。
回避策: この問題は CPU 上では発生しないため、CPU 上でプログラムをデバッグして機能が正しいかどうかを確認します。または、-g や /Zi を使用しないで、ほかのデバッグのヒントを使用します。
製品とパフォーマンス情報
1実際の性能は利用法、構成、その他の要因によって異なります。詳細は、www.Intel.com/PerformanceIndex (英語) を参照してください。