C++ Thrust アプリケーションを SYCL* と oneAPI DPC++ ライブラリー (oneDPL) へ移行する

インテル® oneDPL

この記事は、The Parallel Universe Magazine 51 号に掲載されている「Migrate C++ Thrust Applications to SYCL and oneDPL」の日本語参考訳です。原文は更新される可能性があります。原文と翻訳文の内容が異なる場合は原文を優先してください。


parallel_v51_02

プログラマーはライブラリーが大好きです。単に怠け者だからというだけでなく、ライブラリーが生産性とパフォーマンスを向上するからです。よくあるパターンを最適化するのに時間を浪費し、ターゲット・ハードウェアが変更されるたびにまた同じことをするのは無意味です。パターンを特定する作業はすでに終わっているため、ISO C++ 標準テンプレート・ライブラリー (STL) のような事前定義の抽象化機能を使うべきです。これらはすぐに使えて、専門家によって最適化されています。

STL は CPU だけをターゲットにしているのであれば最適ですが、コンピューティングの世界はヘテロジニアスです。CPU だけでなく、それ以外の選択肢も必要です。NVIDIA* Thrust ライブラリーと oneAPI データ並列 C++ ライブラリー (oneDPL) は CPU 以外にも対応しています。この 2 つを比較してみましょう。どちらもオープンソース・プロジェクト1、2ですが、Thrust のデバイスサポートはプロプライエタリーなソフトウェア・コンポーネントに依存しています (CUB*/CUDA* を通じてのみ GPU をサポートしています)。つまり、ベンダー依存です。一方、oneDPL は SYCL* をベースにしており、複数のベンダーのアクセラレーターをサポートするように設計されています。3

Thrust からベンダーに依存しない oneDPL への移行を検討するのは当然と言えます。ここでは、2 つの簡単な例を使用して、ツールを使用するアプローチと手動でコーディングし直すアプローチの 2つの補完的な移行戦略について見ていきます。CUDA* を SYCL* に移行する SYCLomatic ツールについては、皆さんすでにご存知かもしれません。4ツールを使用した移行には限界があり、特にテンプレート化されたコードでは、必ずしも機能的ではなく、生成されるコードの品質や保守性には限界があります。例えば、ラムダ関数や自動型推論のような新しいC++ の機能を導入する場合、手作業による編集やコードの現代化が通常必要になります。移行後のコードは、オープン・スタンダードに準拠した、最新の C++ に沿ったものになります。Thrust は登場から 10年が経っており、そろそろコードをアップグレードする時期と言えます。いくつかのコード例を見てみましょう。

最初の例は、シーケンス中のいくつかの値をインプレース変換します。変換する値はマスクで定義します。この関数は、値を格納するストリームと、ステンシルシーケンスを格納するストリームの 2 つの入力ストリームを受け取ります。最初のシーケンスの各値は、2 番目の入力シーケンスのステンシル値が特定の条件 (コード例では非ゼロのプレディケート) を満たす場合に変換 (コード例では符号反転) されます。

// Thrust コード例 (ステージ 0)
thrust::transform_if(dev_inp,
                     dev_inp + 10,
                     dev_stencil,
                     dev_inp,
                     thrust::negate<int>(),
                     thrust::identity<int>());

oneDPL は標準 C++ アルゴリズムと密接に連携しています。STL はステンシルのオーバーロードをサポートしていないため、oneDPL も同様にサポートしていません。このパターンは別の方法で表現する必要があるため、SYCLomatic は、ドロップイン置換として代替案を提供しています。

// 移行後のコード (ステージ 1)
dpct::transform_if(oneapi::dpl::execution::make_device_policy(syclQueue),
                   dev_inp,
                   dev_inp + 10,
                   dev_stencil,
                   dev_inp,
                   std::negate<int>(),
                   dpl::identity<int>());  // identity は C++20 の機能

ラムダ関数をカスタム・ファンクターとして使用し、標準 C++ コードを作成することで、さらに改善できます。この方法では、ステンシルシーケンスが一般的な入力シーケンスとは異なる方法で処理されます。プレディケートの評価はカスタム・ファンクターの内部で行われ、ライブラリーの内部に隠されることはありません。

// 手動編集後 (ステージ 2)
dpl::transform(dpl::execution::dpcpp_default,
               dev_inp,
               dev_inp + 10,
               dev_stencil,
               dev_inp,
               [&](const auto& input, const auto& mask)
                  {
                     return mask ? std::negate<>()(input) : input;
                  });

1 oneDPL リポジトリー: https://github.com/oneapi-src/oneDPL (英語)
2 Thrust リポジトリー: https://github.com/NVIDIA/thrust (英語)
3SYCL* の事例: ISO C++ がヘテロジニアス・コンピューティングに十分でない理由

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