FAQ

このページは、インテル® DPC++ 互換性ツールに関するよくある質問 (FAQ) をまとめたものです。

一般情報

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++ 互換性ツールを使用して移行します。

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

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

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

.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
4
// original code

int *device_mem = nullptr;device_mem = sycl::malloc_device<int>(size, dpct::get_default_queue());
device_mem[0] += somevalue;

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

1
2
3
4
5
// fixed DPC++ code

int *device_mem = nullptr;device_mem = sycl::malloc_device<int>(size, dpct::get_default_queue());
dpct::get_default_queue().memset(0, size).wait();
device_mem[0] += somevalue;

トラブルシューティング

“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* では dlopendlclose、および dlsym が使用され、Windows* では LoadLibraryAFreeLibrary、および GetProcAddress が使用されます。

別の 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
    2
    3
    4
    5
    6
    7
    8
     class dev_mgr {
     public:
       static dev_mgr &instance() { // the implementation and the declaration of dev_mgr::instance
         static dev_mgr d_m;
         return d_m;
       }
       ...
     }
    

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

    1
    2
    3
    4
    5
     class dev_mgr {
     public:
       static dev_mgr &instance();//the declaration of dev_mgr::instance
       ...
     }
    

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

    1
    2
    3
    4
    5
    #include <dpct/device.hpp>
    dpct::dev_mgr &dev_mgr::instance(){ // the implementation of dev_mgr::instance
      static dev_mgr d_m;
      return d_m;
    }
    
  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++ コンパイラーでは未定義の動作であり、デバイスによって異なる動作になる可能性があります。コードを調整して、このようなシフト操作は回避してください。

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

1
2
3
4
5
6
7
8
// migrated DPC++ code

void foo() {
  ...
  unsigned int bit = index[tid] % 32;
  unsigned int val = in[tid] << 32 - bit;
  ...
}

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// fixed DPC++ code

void foo() {
  ...
  unsigned int bit = index[tid] % 32;
  unsigned int val;
  if(32 - bit == 32)
    val = 0;
  else
    val = in[tid] << 32 - bit;
  ...
}