みなさん、こんにちは。広島市立大学の窪田と申します。今回、ACRi ブログを執筆する機会をいただきましたので、高位合成ツールである Xilinx Vitis を使って連立一次方程式の求解法である Conjugate Gradient (CG) 法を FPGA で動かす例題を使って、ソフトウェアの FPGA への移植について説明します。
はじめに
私自身は、主に HPC 向けのソフトウェアや並列化コンパイラを研究、開発してきたのですが、最近は FPGA を使った処理の高速化にも手を広げ、Intel や Xilinx から提供される高位合成ツールを使ってみるようになりました。
大学の教員として、大学の学生向けに Verilog HDL で回路を記述してFPGA ボードで動かすような演習を担当したことはあったとはいえ、ハードウェアについては素人です。Vitis については、Vitis を用いたアクセラレータの開発や高位合成で加速するアクセラレータ開発などの ACRi ブログもある中、恐れ多いとは感じながらも、ソフトウェア屋が FPGA を使ってみるという目線で、お伝えできることがあるのではないかと思っています。
FPGA を使ってみる利点は?
FPGA を使うと CPU や GPU に比べて消費電力当たりの性能が高いなどの利点があり、アクセラレータとして注目されるようになってきました。また、高位合成が普及してきたことで、Verilog HDL や VHDL などのハードウェア記述言語だけでなく、C/C++ 言語などでの FPGA 上の回路の設計も実用的になってきましたので、手軽に FPGA を使えるようになってきたように思います。最近は、Amazon EC2 F1 が使えるようになったり、こちらの ACRi ルームも使えるようになったりと、ちょっと FPGA を試してみようという場も増えてきましたね。
一方で、FPGA を実際に使ってみると、プログラムを書いたとおりに (設計どおりに) パイプライン処理や並列処理が行われていることがクロックサイクルレベルで感じられることがあり、このような FPGA というハードウェアを直に扱う面白さも、このブログで伝えられないかと思っています。
このブログでターゲットとする FPGA
Vitis については、上に挙げたように ACRi ブログでも解説されていますし、公式ページ Vitis 統合ソフトウェアプラットフォームでも解説されています。
C/C++ 言語のみで FPGA を扱うことができて、さらに、上のページ中の図で説明されているように、同じプログラムを U250 と ZCU104 のどちらでも動かすことができるマルチプラットフォームに対応しているというのは、大きなメリットですね。
私も、このブログで扱う FPGA を、とても大雑把ではありますが、図に書いてみました。
この図のように C/C++ 言語で書かれたプログラムが、FPGA 上で動く「カーネル関数」と、そのカーネル関数を呼び出す「ホストプログラム」に分かれて実行されることになります。
Alveo U250 などのアクセラレータカードは、一般的な Intel x86 CPU を搭載したサーバや PC の PCI Express スロットに差して使用しますので、ホストプログラムは x86 上で動きますし、ホストプログラムと FPGA 上のカーネル関数のデータ転送などは PCI Express を介して行うことになります。
一方、Vitis のマニュアルなどではエンベデッドプラットフォームなどと呼ばれているボードには、図に挙げたような ZCU102 や Ultra96-V2, ZYBO などがあります。これらはいずれも ARM の CPU と FPGA が SoC (System on Chip) として実装されているチップを搭載した開発ボードです。搭載されている Soc は Zynq という製品群で呼ばれているのをご存じの方も多いと思います。このチップ内で、ホストプログラムは ARM 上で動き、ホストプログラムと FPGA 上のカーネル関数のデータ転送などは AXI を介して行うことになります。
ツールのバージョンでいうと、2019.1 までは、アクセラレータは SDAccel でエンベデッドは SDSoC と分かれていたのが、2019.2 以降、2020.1 と現時点の最新バージョンの 2020.2 では Vitis に統一されました。Vitis では、Alveo U250 などのアクセラレータカードと、ZCU104 のようなエンベデッドプラットフォームのマルチプラットフォームに対応するようになったのは先に述べたとおりです。
このブログでは、ACRi ルームで使用できる Alveo U50 を中心に扱いますが、私が普段使用していることもあり、少し古めの ZC706 や、最近注目されている Ultra96-V2 などのボードで Alveo と同じプログラムを動かすとどうなるか、などもお話したいと思います。
Vitis のサンプルを build & 実行してみよう
では、Vitis の1次元配列の和を求める例題を Alveo U50 で実行してみます。なお、サンプルの build を始めると15分から1時間程度かかることをお断りしておきます。このブログでは、その待ち時間にサンプルとして与えられるファイルやディレクトリを確認した後で実行するという流れで説明します。
さて、今回は Alveo が PCI-Express で接続され Ubuntu などの Linux が稼働する PC で、Vitis 2020.2 がインストールされているものとします。
今回使うサンプルもそうですが、ホスト、カーネルをすべて C/C++ 言語で記述する (OpenCLを含む) 場合については、今のところ (2021年4月現在) Windows 用の Vitis は対応していないようですので、Linux 用の Vitis が必要です。ACRi ルームの U50 サーバと同様の環境と思ってもらえれば良いです。
ご自身で Alveo の動作環境を整える場合は、Vitis-Tutorials の Getting_Started を参考にされるのが良いと思います。
ワークスペースとプロジェクトの設定
では、Vitis がインストールされた Linux が用意できたら、ターミナル (端末) を起動して、コマンドラインから以下のコマンドを実行して、Vitis を起動するための環境変数などを設定しましょう。
source /tools/Xilinx/Vitis/2020.2/settings64.sh
source /opt/xilinx/xrt/setup.sh
Vitis を常用する方は、.bashrc などにこれらの記述を加えても良いかもしれません。では、コマンドラインから Vitis を起動します。vitis &
Vitis IDE Launcher というウィンドウが現れます。ここで workspace 名を指定し、後で project 名を指定することになります。1つの workspace に複数の project を含めることも可能ですが、トラブルにハマることを少しでも避けるため、1つの workspace に1つの project にしておいた方が無難かもしれません。今回は vadd という Xilinx から提供される template を使いますので、
- workspace: vadd_workspace
- project: vadd_app
と指定することにします。
ちょっと説明が長くなりましたが、Vitis IDE Launcher ウィンドウで vadd_workspace というワークスペース名を指定して Launch ボタンをクリックします。
次に現れるウィンドウでは、Create Application Project をクリックして、新しいアプリケーションのプロジェクトを作成しましょう。
プロジェクトの概要を説明するウィンドウが現れます。Next をクリックして次に進みます。
次に Platform を選択するウィンドウが現れます。Alveo U50 上でカーネルを動かすなら xilinx_u50_ で名前が始まる platform を選択します。この例では platform の選択肢が1つしかありませんが、複数の platform が表示される場合は、適切な platform を選択する必要があります。適切な platform を選択したら Next をクリックします。
このウィンドウでは Application project name を指定します。先に書いたように、
- workspace: vadd_workspace
- project: vadd_app
という名前をつけることにしたので、vadd_app を入力し Next をクリックします。
このウィンドウがプロジェクトの各種設定の最後のウィンドウになります。今回はベクトルの和を求める Vector Addition という template をクリックして Finish をクリックします。これでプロジェクトの各種設定が終了します。
サンプルプロジェクトの build
各種設定が終わると、このようなウィンドウが現れます。この Vitis IDE は eclipse をベースにしているので、Java 言語などでソフトウェア開発を行った経験のある方には見覚えのあるウィンドウに見えるかもしれません。
では、このベクトルの和のサンプルプロジェクトを FPGA 上で動かしてみましょう。このウィンドウの真ん中、vadd_app というタブをクリックして下さい。このタブの右の Options の Target が SW Emulation になっていると思います。
Target は SW Emulation, HW Emulation, Hardware の3種類から選択できます。ハードウェア設計においては (ソフトウェア設計でもそうですが) バグがないか十分にテストしてから実機の Hardware 上で動かすのが鉄則ですが、今回は Xilinx 提供の template を使っているので、テストは済んでいるものとし、上の図のように Hardware を選択して実機で実行することにします。
念のため、vadd_app タブのとなりにある、vadd_app_system タブもクリックして確認しましょう。こちらも Target は Hardware になっているはずです。
では Target を Hardware として build してみましょう。具体的には、FPGA 上で動くカーネルと、ホスト PC 上で動きカーネルを呼び出すホストプログラムが生成されることになります。どのようなソースプログラムを build するのかの確認は後回しにして、まずは build してみましょう。
Vitis のウィンドウの左下に Assistant というタブがあります。一番上の vadd_app_system [System] をクリックし、トンカチアイコンをクリックして build を開始します。
なお、Assistant タブをダブルクリックするとタブのみが表示されます。(再びタブをダブルクリックすると元のサイズに戻ります。特定のタブのみを表示したいときに使うと便利です。)
このタブには vadd_app_system [System] 以外に、
- vadd_app_system_hw_link [Hw Link]
- vadd_app_kernels [Hw Kernel]
- vadd_app [Host]
などが並んでおり、さらに階層構造になっていて
- Emulation-SW [Software Emulation]
- Emulation-HW [Hardware Emulation]
- Hardware [Hardware]
- binary_container_1
- krnl_vadd [C/C++]
などが並んでいることがわかります。
build している PC の性能にもよりますが、上の図のように Hardware の箇所が build 中を示す円を描き始めると、build が終了するまで15分から1時間程度かかります。では、その間にこの階層構造をファイルシステム上で確認してみましょう。
プロジェクトのディレクトリ構成
ワークスペース vadd_workspace にプロジェクト vadd_app を作成すると、Linux のファイルシステム上の vadd_workspace ディレクトリの下に以下の図のようなファイルやディレクトリが自動的に作成されます。コマンドラインやファイルマネージャなどで確認してみましょう。
- vadd_app プロジェクト固有のディレクトリ
- vadd_app_system
- vadd_app_system_hw_link
- vadd_app_kernels FPGA 上のカーネル
- vadd_app ホストプログラム
- その他のファイル、ディレクトリ
- RemoteSystemsTempFiles
- ip_cache
- IDE.log
プロジェクト名を vadd_app とすると、vadd_app_kernels のように一定の命名規則に従ったディレクトリが生成されることがわかると思います。なお、これらのディレクトリは、Vitis の Assistant タブでは微妙に異なる階層構造で表示されています。
さらに、FPGA で動くカーネル関数や PC で動くホストプログラムのソースファイルの場所を確認しておきましょう。
- vadd_app_kernels/src/krnl_app.cpp
- FPGA で動くカーネル関数のソースファイル
- vadd_app/src/vadd.cpp
- ホストプログラム (main 関数を含む) のソースファイル
- vadd_app/src/vadd.h
- ホストプログラムがインクルードするファイル
これらのファイルは、プロジェクト生成時に、vector addition の template としてコピーされたものです。
注:これらのディレクトリ配置は、Vitis 2020.2 になって変更になったようです。2019.1 や 2020.1 では、ホストプログラムと FPGA カーネルのディレクトリはこのようには分離されていませんでした。
build 時にたくさんの一時ディレクトリや一時ファイルが生成されますが、最終的には vadd_app/Hardware ディレクトリにホストプログラムのバイナリと FPGA カーネルのバイナリがおかれます。
サンプルプロジェクト の実行
さあ、そろそろ build が終了した頃でしょうか。build が終了すると、ウィンドウの下の方の Console タブに Build Finished というログが表示されます。このとき、Assitant タブ内の階層構造状のエントリをいくつかクリックしてみると、それらのエントリの build のログが表示されます。
たとえば、vadd_app_system_hw_link をクリックすると、Console に表示されるログの最後に 14:48:26 Build Finished (took 40m:31s.396ms) などと表示され、build に40分以上かかった箇所があることがわかります。
プロジェクトの実行
build が終了したら、このサンプルプロジェクトを実行してみましょう。今回は Vitis の GUI から実行する方法と、コマンドラインから実行する方法の2つの方法を試してみます。
まず、Vitis の GUI で実行してみましょう。Assistant タブの「実行」アイコンを右クリックし、Hardware Configuration を選択すると、プログラムが実行されます。Console タブに実行結果が表示されるので、確認してみましょう。このサンプルプログラムは、FPGA 上でのベクトルの和の結果と、同じベクトルの和をホスト PC 上で実行した結果を比較し、同じ結果が得られれば TEST PASSED と出力されます。
同じことをコマンドラインからも試してみましょう。vadd_workspace ワークスペースの vadd_app/Hardware ディレクトリに
- vadd_app/Hardware/vadd_app
- ホストプログラム
- vadd_app/Hardware/binary_container_1.xclbin
- FPGA 上で実行されるカーネル
というファイルが生成されているはずです。ターミナルのコマンドラインで
cd vadd_app/Hardware
のように作業ディレクトリを移動して./vadd_app binary_container_1.xclbin
と実行してみて下さい。Loading: 'binary_container_1.xclbin'
TEST PASSED
と表示されれば、GUIでの実行と同様に正常に実行できたことが確認できます。
なお、以下のようなエラーが出ることがあるかもしれません。./vadd_app: error while loading shared libraries: libxilinxopencl.so.2: cannot open shared object file: No such file or directory
この場合は、このターミナルのコマンドラインからsource /opt/xilinx/xrt/setup.sh
を実行してからもう一度プログラムを実行してみて下さい。このコマンドは、最初の方で、vitis を起動する前に実行してもらうように説明していますので、vitis を起動したターミナルと同じターミナルならすでに実行済のはずです。しかし、vitis を起動したのと別のターミナルで実行しようとするときは、上記のコマンドだけは実行しておく必要があります。
まとめ
今回は、Vitis の vector addition の template を Alveo U50 で実行する例を説明しました。今回はここまでとしますが、次回以降、この vector addition の template の記述も参考にしながら、連立一次方程式を解く CG 法のプログラムを FPGA 用に移植する手順を説明します。
広島市立大学 窪田昌史