std::offload
このモジュールは活発に開発されています。
アップストリームに取り込まれれば、Rust 開発者が GPU 上で Rust コードを実行できるようになるはずです。
私たちは、安全で便利で、デフォルトで十分に高速な rusty な GPU プログラミングインターフェイスの開発を目指しています。
これには、GPU へのデータ移動と GPU からのデータ移動を効率的に自動で行うことが含まれます。
また、(後で)より高度な制御を可能にする、
場合によっては unsafe な、より高度なインターフェイスも提供する予定です。
実装は LLVM の “offload” プロジェクトに基づいています。 これは、OpenMP が Fortran や C++ コードを GPU 上で実行するためにすでに使用しています。 プロジェクトが開発中である間は、 ユーザーはコンパイルプロセスを完了するために clang などの他のコンパイラを呼び出す必要があります。
高レベルなコンパイル設計:
単一ソース・2 パスのコンパイル方式を使用します。
まず、デバイス向けにオフロードされるべきすべての関数をコンパイルします
(例: nvptx64、amdgcn-amd-amdhsa、将来的には intel)。
現在は扱いにくい #cfg(target_os="") アノテーションが必要ですが、将来的には offload intrinsic に基づいてそれらを認識する予定です。
この最初のコンパイルは現在 rustc の内部 Query システムを活用していないため、現時点では常にカーネルを再コンパイルします。
これは簡単に修正できるはずですが、現時点では機能とランタイム性能の改善を優先しています。
とはいえ、これを実装したい場合はぜひ連絡してください!
次に、ホスト(例: x86-64)向けにコードをコンパイルします。オフロード処理の大半はここで行われます。
ホスト側では、openmp offload ランタイムへの呼び出しを生成し、
型のレイアウト(autodiff TypeTrees の簡略版)をそれに通知します。
また、型システムを使用して、カーネル引数をデバイスへ移動するだけでよいのか(例: &[f32;1024])、
デバイスから移動する必要があるのか、またはその両方なのか(例: &mut [f64])を判断します。
その後、カーネルを起動し、
その後でランタイムにこの環境を終了することと、(必要な範囲で)データを戻すことを通知します。
ホスト向けの 2 回目のパスでは、前回のコンパイルからカーネルアーティファクトを読み込みます。 一般に rustc はビルドディレクトリのレイアウトを「推測」したりハードコードしたりしてはならず、 そのため 2 回目の呼び出しでは、カーネルアーティファクトへのパスを伝える必要があります。 このためのロジックは cargo に統合できますが、 必要なのは単純な cargo ラッパーだけでもあります。 これは、より広く採用されるまで、crates.io 経由で簡単に提供できます。
単一ソース・単一パスのコンパイル方式を考えたくなるかもしれません。
しかし、rustc フロントエンドの多く(例: AST)は、あらゆるデッドコード(例: 非アクティブな cfg の背後にあるコード)を削除します。
フロントエンドに 2 つのターゲット向けのコードを素朴に展開および lowering させると、同じシンボルの複数定義(およびその他の問題)が発生します。
rustc の middle と backend 全体に、任意のシンボルが今や 2 つの実装を含む可能性があることを認識させようとするのは大きな取り組みであり、
代替案が約 5 行の cargo ラッパーであるなら、コンパイラ全体をより複雑にするべき理由は疑問です。
それでも私たちはコンパイルパイプライン全体を制御しており、ホストコードとデバイスコードの両方を利用できるため、
2 つの方式の間にランタイム性能の違いはないはずです。