SYCLを使ってOpenCLを単一ソースで書いてみる

OpenCLを書いている時、ホストとデバイスのコードが完全に分離していて連携しづらくてツライ・・・といった経験ありませんか?AMDのGPUに限るならHIPといった選択肢もあるのですが、OpenCLであってほしい場面はたくさんあります。

そんなところで、実は、OpenCLを単一ソースで書けるKhronosの規格にSYCL(シクル、と発音します)というものがあります。

この記事ではこの規格の実装をためしにつかってみました。付属してるサンプルなどを動作させるところまでの解説と、書いてみたコードの紹介をします。

SYCLについて

Khronosグループによると、単一ソースのモダンなC++(具体的にはC++11)でOpenCLデバイスを扱うための規格です。バージョン1.2と2.2の暫定版が策定されています。詳しくはKhronosCodePlayのサイトに書いてありますので詳しく知りたい方はお読みください。

KhronosによるとSYCLの実装は、CodePlayによるComputeCPPとGitHubで開発されているtriSYCLの二つがあるそうです。今回はこの二つの実装をそれぞれ動かしてみました。

実験環境

今回使った環境は特に明言しない限り以下の通りです

  • OS : Ubuntu 16.04
  • GPU : AMD Radeon R9 Fury X
  • ドライバ : AMDGPU-Pro Driver Version 17.10 for Ubuntu 16.04.2
  • SDK : AMD APP SDK v3.0

ほかの環境で試すときは適宜読み替えてください。OpenCLが使える新しめなx86_64のLinux環境であればなんとかなるかもしれません。

ComputeCPP

ComputeCPPはCodePlayが公開しているクローズドソースなSYCL1.2の実装(注: Khronosのサイトでは2.2を実装してあるかのように書いてありますが、CodePlayのサイトを見渡す限り1.2です)で、Community Editionのベータ版が使えます。ライセンスは実行ファイル等と一緒に圧縮されているdoc/LICENSE.TXTに書いてあります。

この実装の動作としてはComputeCPPはSYCLのコードを一旦LLVMIRに変換し、それをSPIR1.2を使ってGPUで動かしています。したがって、OpenCLデバイスがKhronos拡張のcl_khr_spirに対応している必要があります。

準備

ComputeCPPの入手

まず、公式サイトでアカウントを作成し、使ってるOSにあったバージョンのComputeCPPをダウンロードし、解凍します。この記事ではこれ以降、解凍したフォルダが/opt/ComputeCPP-CEにあることにします。

なお、ComputeCPPはCentOSとUbuntu 14.04、Ubuntu16.04のそれぞれの64bit版に対応しているバイナリを提供しています。

ComputeCpp-SDKの入手

CodePlayがComputeCPPのためのユーティリティとドキュメントをgithubで公開しています。この中にサンプルコードもあります。また、このリポジトリはApache Licenseでライセンスされています

サンプルのビルドと実行

サンプルは以下の手順でビルドできます。(筆者の環境ではfind_package(OpenCL REQUIRED)がうまく動かなかったため-DOpenCL_LIBRARYをつけています)

しかし、この方法で作成したバイナリは筆者の環境だと実行時にSegmentation Faultになってしまいます。(どうやらNVIDIAのプロプライエタリドライバを使った環境ではSegmantation Faultにならないこともあるようです)

しかし、以下のように直接ビルドするとSegmentation Faultにならないようです。ここではsamples/matrix_multiply.cppをビルドするものとします。

-Iや-Lは環境や設定に応じて適宜書き換えてください。二行目でmatrix_multiply.syclというファイルを生成します。この.syclにSPIRが含まれているようです。

実行すると以下のように出力が得られました。

triSYCL

triSYCLはオープンソースで開発されている実装で、ComputeCPPと違いインクルードするだけで使うことができます。ライセンスはLLVM/Clangと同じようです。

OpenCLデバイスでコードを走らせることはできず、普通に書くとOpenMPでSYCLのカーネルを並列実行することができるだけのようです。boost::computeのkernelを使ったりするinterperability modeというものを使うことでOpenCLデバイスを使うこともできますが、SYCLで書くことはできないようなのでここでは割愛します。

準備

triSYCLの入手

GitHub からcloneするだけです。

boost::compute

triSYCLがboost::compute依存しているので、インストールしておきます。

テストのビルドと実行

triSYCLに付属してるテストをビルドします。boost::computeが/usr/include/computeにあったので、指定を追加しています。

ビルドには数分程度かかるかもしれません。また、ビルド中に大量のwarningが出ます。

とするとテストが実行されます。最後の行に

と出ていれば成功です。

どちらでも動くコード

先ほど動かしたComputeCPPのサンプルとtriSYCLのテストはそれぞれのライブラリでしかビルドできないようなので、どちらでもビルド & 実行できるプログラムを書いてみました。

triSYCL

triSYCLでは

とするとビルドでき(現状ではOpenCLをリンクせずとも、また-std=c++14でも動きますが、ここで提示したオプションは念のためです)、

とすると実行できます。

 

ComputeCPP

ComputeCPPでは

とするとビルドでき、実行のためにはlibComputeCpp.soが必要なので、

としてやれば動きます。

まとめ

二つの実装について一言でまとめると、

triSYCL
OpenMPの使える環境であれば手軽にSYCLを書くことができるが、並列処理を書きたいだけであれば直接OpenMPで書いたほうが良いかと思います。
ComputeCPP
サイトに登録したり、専用のビルド手順を踏む必要があるものの、SYCLで書いたものをOpenCLで動かすことができる。

といったところでしょうか。調べてる過程でtriSYCLもComputeCPPのどちらも未実装な部分が見られたり、動作が怪しい部分が見つかったりしたものの、活発に開発されているようなので筆者としてはこれからに期待しています。

今回の記事は動かすところまでだったので、性能評価などはおこなっていませんが、機会があれば性能評価を行った記事も書きたいですね。

2017/09/29追記

ルネサス社が、ComputeCPPの開発元であるCodeplayと共同で、SYCLを使ってADAS(先進運転システム)に取り組むそうです。SYCLの今後が楽しみですね!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です