よくある問い合わせ#

一般情報

移行のトラブルシューティング

一般情報#

Linux* や Windows* で C++11 以降の C++ 標準機能を使用しているソースファイルを移行するにはどうすればいいですか?#

Linux* では、インテル® DPC++ 互換性ツールのパーサーは、デフォルトで C++98 と一部の C++11 機能をサポートします。インテル® DPC++ 互換性ツールでほかの C++11 以降の機能を有効にするには、--extra-arg="-std=<value>" オプションをコマンドラインに追加します。value に設定可能な値は以下のとおりです。

  • c++11

  • c++14

  • c++17

Windows* では、インテル® DPC++ 互換性ツールのパーサーは、デフォルトで C++14 をサポートします。インテル® DPC++ 互換性ツールで C++17 の機能を有効にするには、--extra-arg="-std=c++17" オプションをコマンドラインに追加します。

CMake プロジェクトを使用している場合、Windows* 上でファイルを移行するにはどうすればいいですか?#

Windows* 上の CMake プロジェクトでは、CMake を使用して Microsoft* Visual Studio* プロジェクト・ファイル (vcxproj) を生成できます。その後、以下のいずれかのオプションを選択します。

  • インテル® DPC++ 互換性ツールの --vcxprojfile オプションを使用して、コマンドラインでソースファイルを移行します。

  • インテル® DPC++ 互換性ツールの Microsoft* Visual Studio* プラグインを使用して、Microsoft* Visual Studio* でプロジェクト全体を移行します。

移行されたコードのフォーマットはどうなっていますか?#

インテル® DPC++ 互換性ツールは、移行したコードのフォーマットを制御するため--format-range--format-style オプションを提供しています。

入力ソースコードが適切にフォーマットされている場合、インテル® DPC++ 互換性ツールはデフォルトのオプション設定である --format-range--format-style を使用して結果コードをフォーマットします。

入力ソースコードが適切にフォーマットされていない場合 (例えば、タブとスペースの混在や異なるインデントが検出された場合)、以下のいずれかを行うことができます。

  • インテル® DPC++ 互換性ツールは、オリジナルコードのインデントサイズを検出して結果コード に適用します。.clang-format ファイルで TabWidthUseTab を設定してツールに指示できます。ただし、入力ソースコードが適切にフォーマットされていないと、移行したコード内のインデントが一致しない可能性があります。

  • --format-range=all オプションを指定してインテル® DPC++ 互換性ツールを実行し、結果ファイル全体をフォーマットします。入力ソースコードと結果ソースコードの変化が激しく、コードの比較が困難な場合があります。

  • 入力ソースコードをフォーマットして、同じ .clang-format ファイルでインテル® DPC++ 互換性ツールを使用して移行します。

コンパイル・データベースにプロジェクト内のすべてのファイルが含まれていないのはなぜですか?#

プロジェクトのビルドフォルダーで、intercept-build make [target] コマンドを使用してコンパイル・データベースを生成します。コンパイル・データベースの内容は、オプションの [target] パラメーターに依存します。デフォルトのビルドターゲットに対応するファイルリストを取得する必要がある場合は、[target] パラメーターを指定しません。

intercept-build を実行する前に、プロジェクトの ccache (コンパイラー・キャッシュ) を無効にしてください。ccache が有効の場合、ターゲット・オブジェクトがキャッシュ内にすでに存在すると、一部のコンパイル・コマンドがスキップされる可能性があるため、intercept-build で完全なコンパイル・データベースを生成できません。intercept-build を実行する前に、次のコマンドを使用して ccache を無効にします。

export CCACHE_DISABLE=1

移行したモジュールファイルを新しいプロジェクトで使用するにはどうしたらいいですか?#

.cu モジュールファイルは、オリジナル・プロジェクトの -ptx または -cubin オプションでコンパイルされ、cuModuleLoad()cuModuleLoadData() で別の *.cu ファイルに動的にロードされます。

インテル® DPC++ 互換性ツールは、ほかの *.cu ファイルと同様に、モジュールファイルのコードを移行します。さらに、モジュールファイル内の _global_ 属性を持つ各関数ににラッパー関数を追加します。

移行したモジュールファイルをダイナミック・ライブラリーにコンパイルして、プラットフォーム向けの適切なダイナミック・ライブラリー API でロードします。以下に例を示します。

  • Linux* では、dlopen() でダイナミック・ライブラリー (.so) をロードします。

  • Windows* では、LoadLibraryA() でダイナミック・ライブラリー (.dll) をロードします。

sycl::malloc_device、sycl::malloc_host、および dpct::dpct_malloc で割り当てられるメモリー空間は初期化されていますか?#

sycl::malloc_devicesycl::malloc_host、および dpct::dpct_malloc で割り当てられるメモリーは初期化されていません。新たに割り当てられるメモリーの初期値に明示的または暗黙的に依存しているプログラムは、実行時に失敗する可能性があります。このような失敗を回避するため、コードを調整してください。

例えば、以下のオリジナルコードについて考えてみます。

1  // 元のコード 
2 
3  int *device_mem = nullptr;device_mem = sycl::malloc_device<int>(size, dpct::get_default_queue()); 
4  device_mem[0] += somevalue;

新たに割り当てられたメモリーを使用する前に、0 に初期化するようにします。

1  // 修正された SYCL コード 
2 
3  int *device_mem = nullptr;device_mem = sycl::malloc_device<int>(size, dpct::get_default_queue()); 
4  dpct::get_default_queue().memset(0, size).wait(); 
5  device_mem[0] += somevalue;

CUB* ライブラリー実装ソースコードを含む CUDA* ソースコードを移行するにはどのようにすればよいですか?#

CUB* ライブラリー実装コードを直接移行すると、期待する結果が得られないことがあります。代わりに、--in-root-exclude=<path to CUB library source code> を移行コマンドに追加して、CUB* ライブラリー実装ソースコードを移行から除外します。

条件文で使用されるグループバリアなど、work-group レベルの同期が原因で SYCL* コードがハングする問題を修正するにはどうすればいいですか?#

条件文やループ文などの制御フロー文内の同期 API が SYCL* コードで呼び出される場合、実行時にハングアップする問題が生じる可能性があります。ハングアップの問題を解決する基本的なことは、各同期 API に work-group の全てのワーク項目が到達するか、work-group 内のすべてのワーク項目が同期をスキップすることです。

次の 2 つの修正方法を示します。

最初は、同期 API グループバリア (nd_item.barrier()) を if ブロック内で呼び出しています。条件文の評価結果はワーク項目ごとに異なるため、すべてのワーク項目が同期 API に到達するわけではありません。

1  // オリジナルコード 
2 
3  void kernel(const sycl::nd_item<3> &item_ct1) { 
4   unsigned int tid = item_ct1.get_local_id(2); 
5   if (tid < 32) { 
6   // CODE block 1 
7    ...
8   item_ct1.barrier(sycl::access::fence_space::local_space); 
9   // CODE block 2 
10   ... 
11  } 
12 }

次のコードは、同期文を if ブロックの外に移動することでハングアップする問題を解決する方法を示しています。

1  // 修正した SYCL コード 
2 
3  void kernel(const sycl::nd_item<3> &item_ct1) { 
4   unsigned int tid = item_ct1.get_local_id(2); 
5   if (tid < 32) { 
6   // CODE block 1 
7     ... 
8   } 
9   item_ct1.barrier(sycl::access::fence_space::local_space); 
10  if (tid < 32) { 
11  // CODE block 2 
12    ... 
13  } 
14 }

次の例は、同期 API が for ループで使用される場合にハングアップする問題を解決する方法を示しています。

1  // オリジナルコード 
2 
3  void compute(int id_space, const sycl::nd_item<3> &item_ct1) { 
4   unsigned int id = item_ct1.get_group(2) * item_ct1.get_local_range(2) + item_ct1.get_local_id(2); 
5   for (; id < id_space; id += item_ct1.get_group_range(2) * item_ct1.get_local_range(2)) { 
6     ... 
7     item_ct1.barrier(); 
8     ... 
9   } 
10 }

次のコードは、すべてのワーク項目が for ループ内で同じ実行フットプリントを持つようにすることで、ハングアップの問題を解決します。

1  // fixed SYCL code 
2 
3  void compute(int id_space, const sycl::nd_item<3> &item_ct1) { 
4   unsigned int id = item_ct1.get_group(2) * item_ct1.get_local_range(2) + item_ct1.get_local_id(2); 
5   unsigned int num_workitem = item_ct1.get_group_range(2) * item_ct1.get_local_range(2); 
6   // The condition is updated to make sure all work items can enter the loop body in each iteration 
7   for (; id < ((id_space + num_workitem - 1) / num_workitem) * num_workitem; 
8     id += item_ct1.get_group_range(2) * item_ct1.get_local_range(2)) { 
9     ... 
10    item_ct1.barrier(); 
11    ... 
12  } 
13 }

移行のトラブルシューティング#

“dpct –in-root=srcdir –out-root=dstdir *.cu” でファイルを移行すると、“error: unknown type name” (エラー: 不明なタイプ名です) などのエラーが発生しますが、どのようにすれば解決できますか?#

この問題は、*.cu リストに含まれるファイルのうち、ヘッダーファイル (#include 文でインクルードされる) として使用され、スタンドアロン・ファイルとして解析されることを想定していないファイルが原因の可能性があります。ファイルがほかのファイルの定義/宣言に依存しているためファイルを解析できない場合、インテル® DPC++ 互換性ツールはエラーを報告します。次のいずれかの方法でコンテンツを移行します。

  • インテル® DPC++ 互換性ツールに移行するファイルを決定させます: compile_commands.json: "dpct -p=compile_commands.json --in-root=srcdir --out-root=dstdir" を使用。

  • 手動で特定のファイルを渡します。ただし、ほかのファイルにインクルードされており、オリジナルのアプリケーションでスタンドアロンのファイルとしてコンパイルされることを想定していないファイルは渡せません。入力ファイルにインクルードされており、in-root フォルダー以下にあるヘッダーファイルは自動的に移行されます: dpct --in-root= srcdir --out-root=dstdir sample.cu を使用。

Windows* でコードを移行する際に、「no member named 'max' in namespace 'std' ('std' 名前空間に 'max' という名前のメンバーはありません)」や「no member named 'min' in namespace 'std' ('std' 名前空間に 'min' という名前のメンバーはありません)」などの解析エラーが発生した場合、どのように修正すればよいですか?#

以下のいずれかの方法でエラーを解決してください。

  • std::minstd::max を使用する前に、#include <algorithm> をソースファイルに追加します。

  • WinDef.h をインクルードする前に、#define NOMINMAX を追加して NOMINMAX マクロを定義します。

Linux* 上で移行されたコードを Windows* 上でコンパイルする際に「error: dlopen not declared (エラー: dlopen は宣言されていません)」などのコンパイルエラーが発生した場合、どのように修正すればよいですか?#

インテル® DPC++ 互換性ツールはソースコードを生成する際に、ツールが動作している OS に固有の動的ロード API を使用します。

例えば、Linux* では dlopendlclosedlsym が使用され、Windows* では LoadLibraryAFreeLibraryGetProcAddress が使用されます。

別の OS で移行されたコードをコンパイルする場合は、インテル® DPC++ 互換性ツールを使用してターゲット OS でプロジェクトを再度移行するか、手動でコードを修正します。

なぜ “atomic*” API は移行されないのですか?#

インテル® DPC++ 互換性ツールは、「atomic*」API をユーザー定義の API であると仮定すると移行しません。

これは、以下の場合に発生する可能性があります。

  • CUDA* インクルード・パスが --cuda-include-path-I* の両方で指定されているが、パスが異なる場合。

  • CUDA* インクルード・パスが -I* で指定されているが、デフォルトの CUDA* インストール・パスにほかの CUDA* インクルード・ファイルが存在する場合。

「atomic*」 API が確実に移行されるようにするには、dpct 移行コマンドで CUDA* インクルード・パスを指定する際に -I* をを使用しないでください。代わりに、--cuda-include-path で CUDA* インクルード・パスを指定してください。

“error: restrict requires a pointer or reference” (エラー: restrict には参照へのポインターが必要です) で移行に失敗しました、何が原因ですか?#

C++ 標準では restrict 修飾子をサポートしておらず、C 標準ではオブジェクト型へのポインターでのみ restrict 修飾子をサポートしています。

これらの言語標準に基づいて、インテル® DPC++ 互換性ツールは解析エラーを出力します。

ソースコードの調整が必要な場合があります。

別のアプリケーションで複数回ロードされるライブラリー・プロジェクトで、dpct::dev_mgr と dpct:mem_mgr のランタイム動作が正しくない場合、どのように解決したらよいですか?#

dpct::dev_mgrdpct::mem_mgr は、インテル® DPC++ 互換性ツールのヘルパー関数のシングルトン・クラスです。ヘルパー関数のヘッダーを使用して実行形式のプロジェクトのビルドする場合、dpct::dev_mgrdpct::mem_mgr はどちらも、実行形式では 1 つのインスタンスになります。しかし、ヘルパー関数のヘッダーを使用して、アプリケーション内で dlopen() (Windows* では LoadLibraryA()) を使って複数回ロードされるライブラリー・プロジェクトをビルドする場合、dpct::dev_mgrdpct::mem_mgr の 3 つ以上のインスタンスが作成され、正しくないランタイム動作になります。

例えば、libA.cpplibB.cpp の両方のファイルがインテル® DPC++ 互換性ツールのヘルパー関数のヘッダー dpct.hpp をインクルードすると、それぞれダイナミック・ライブラリー libA.solibB.so にビルドされます。アプリケーション main.cppdlopen() を使ってこれらのライブラリーをインポートすると、アプリケーションのランタイムで dpct::dev_mgrdpct::mem_mgr の 2 つのインスタンスが作成されます。

この問題を解決するには、インテル® DPC++ 互換性ツールのヘルパー関数で dpct::dev_mgrdpct::mem_mgr の実装と宣言を分離します。

  1. 新しい C++ ファイル dpct_helper.cpp を作成します。

  2. class dev_mgrinstance() の実装を dpct/device.hpp から dpct_helper.cpp へ移動します。

    例えば、以下はオリジナルの dpct/device.hpp です。

    1   class dev_mgr { 
    2   public: 
    3     static dev_mgr &instance() { // 実装と dev_mgr::instance の宣言 
    4     static dev_mgr d_m; 
    5     return d_m; 
    6     } 
    7     ... 
    8   }

    これを次のように変更します。

    1   class dev_mgr { 
    2   public: 3 static dev_mgr &instance();// dev_mgr::instance の宣言 
    4     ... 
    5   }

    そして、新しい dpct_helper.cppdev_mgr::instance() の実装を含めます。

    1  #include <dpct/device.hpp> 
    2  dpct::dev_mgr &dev_mgr::instance(){ // dev_mgr::instance の実装 
    3   static dev_mgr d_m; 
    4   return d_m; 
    5  }
  3. ステップ 2 と同様に、class mem_mgrinstance() 実装を dpct/memory.hpp から dpct_helper.cpp に移動します。

  4. dpct_helper.cpp をダイナミック・ライブラリー libdpct_helper としてビルドします。

    • Linux*:

      dpcpp -g -shared -o libdpct_helper.so -fPIC ./dpct_helper.cpp
    • Windows*:

      cl.exe /LD dpct_helper.cpp
  5. libdpct_helper ライブラリーを環境変数に追加します。

    • Linux*: libdpct_helper.so の場所を LD_LIBRARY_PATH に追加します。

    • Windows*: libdpct_helper.dll の場所を PATH に追加します。

  6. ライブラリーやアプリケーションをビルドする際に libdpct_helper を動的にリンクします。

上記のステップを実行すると、すべてのライブラリーとアプリケーションは、インテル® DPC++ 互換性ツールのヘルパー関数の dpct::dev_mgr デバイス・マネージャーと dpct::mem_mgr メモリー・マネージャーの同じインスタンスを共有するようになります。

移行したコードをインテル® oneAPI DPC++/C++ コンパイラーでコンパイルすると「warning: shift count >= width of type (警告: シフトカウントが型の長さよりも大きい)」になります。何が原因ですか?#

シフトカウントが型の長さよりも大きいシフト操作は、インテル® oneAPI DPC++/C++ コンパイラーでは未定義の動作であり、デバイスによって異なる動作になる可能性があります。コードを調整して、このようなシフト操作は回避してください。

例えば、以下は移行された SYCL* コードです。

1  // 移行された SYCL コード 
2 
3  void foo() { 
4   ... 
5   unsigned int bit = index[tid] % 32; 
6   unsigned int val = in[tid] << 32 - bit; 
7   ... 
8  }

シフトカウントが型の長さよりも大きくならないように、このコードを調整します。

1  // 修正された SYCL コード 
2 
3  void foo() { 
4   ... 
5   unsigned int bit = index[tid] % 32; 
6   unsigned int val; 
7   if(32 - bit == 32) 
8     val = 0; 
9   else 
10    val = in[tid] << 32 - bit; 
11  ... 
12 }

コードの移行時に発生する解決できないインクルードエラーにはどのように対処できますか?#

--extra-arg=-v オプションを使用すると、インテル® DPC++ 互換性ツールは詳しい情報を出力します。これには、ツールの検索パスに関連する情報も含まれます。

次のいずれかの方法で、インクルード検索の追加パスを指定します。

  • 移行コマンドで --extra-arg="-I<extra include path>" オプションを使用して、移行中にインクルード検索にツールが使用する追加のパスを指定します。

  • コンパイル・データベースを使用する場合、ソースファイルのデータベース内のコンパイルコマンドに -I<extra include path> オプションを追加して、インクルード・パスを指定します。