Intel DevCloudで遊んでみた

# はじめに

[Intel DevCloud](https://www.intel.com/content/www/us/en/developer/tools/devcloud/overview.html) は，Intelが提供しているFPGAを利用可能なクラウドサービスです．この記事では，DevCloudの使い方，何ができるか，を，簡単に紹介します．

# DevCloudの構成

Intel DevCloudは，ログイン用のサーバーと実際にFPGAを搭載したサーバで構成されています．中の本当のことは知りませんが，ユーザからは次の図のように見えます．

![devcloud_overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/ad76da4e-e759-8ee2-7842-b517ad8a5ca1.png)

sshでログインした踏み台マシン(図中のlogin-2)から，`qsub`/`qstat`/`qdel`といったTorqueのコマンドでFPGAを搭載したノードでジョブを走らせることでFPGAを利用します．FPGAを搭載しているサーバーでは，OPAEやOneAPIを使ってFPGAに処理を実行させることができます．

用意されているマシンのリストを取得してみると，次のように表示されました．Stratix 10(PAC D5005)を搭載したサーバーは5台あるようなのですが，結構よく使われています．うまく隙間を狙って使いましょう．

```
--------------------------------------------------------------------------------------
Nodes with no attached hardware: (18 available/35 total)
s001-n054 s001-n057 s001-n058 s001-n059 s001-n060 s001-n061 s001-n063 s001-n064 s001-n065 s001-n066 s001-n067 s001-n068 s001-n069 s001-n070 s001-n072 s001-n076 s001-n078 s001-n079
--------------------------------------------------------------------------------------
Nodes with Arria 10: (8 available/8 total)
Release 1.2:

Release 1.2.1:
s001-n137 s001-n138 s001-n139 s005-n001 s005-n002 s005-n003 s005-n004 s005-n007
--------------------------------------------------------------------------------------
Nodes with Arria 10 OneAPI: (7 available/12 total)
s001-n081 s001-n082 s001-n083 s001-n084 s001-n085 s001-n086 s001-n089
--------------------------------------------------------------------------------------
Nodes with Stratix 10: (0 available/5 total)

--------------------------------------------------------------------------------------
Nodes with Stratix 10 OneAPI: (3 available/3 total)
s001-n142 s001-n143 s001-n144
--------------------------------------------------------------------------------------
```

# DevCloudにログインする

DevCloudを利用する際には，[Intel DevCloud](https://www.intel.com/content/www/us/en/developer/tools/devcloud/overview.html) でアカウントを作成する必要があります．

![Screenshot_2021-12-24_13-29-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/ee50f3a6-0b02-db10-21ab-e3af68a9a532.png)

「Sing In →」をクリックして，「Register now for Intel® DevCloud」から無料でアカウントを作ることが出来ます．

アカウントを作成したら，DevCloudにsshでログインするための設定をします．Linuxが楽です．Windows10以降のユーザはWSLでも構いません．
アカウント登録のあと[Intel® DevCloud for oneAPI](https://devcloud.intel.com/oneapi/get_started/opencl/)にアクセスします．sshの設定スクリプト`setup-devcloud-access-ユーザーID.txt`というファイルがダウンロードできます．

ダウンロードした設定スクリプトを実行します．

```
$ bash setup-devcloud-access-ユーザーID.txt
```

実行すると，`$HOME/.ssh`の下に`devcloud-access-key-ユーザーID.txt`という名前で秘密鍵が登録されます．また，`$HOME/.ssh/config`に，以下のようなDevCloudにsshでアクセスするための設定が保存されます．

```
Host devcloud
User ユーザー名
IdentityFile ~/.ssh/devcloud-access-key-ユーザーID.txt
ProxyCommand ssh -T -i ~/.ssh/devcloud-access-key-ユーザーID.txt guest@ssh.devcloud.intel.com
```

この設定によって，DevCloudにログインする場合には，単に

```
ssh devcloud
```

として実行するだけでログインできるようになります．

# OneAPIで遊んでみる

GitHubで公開されている [OneAPIのサンプル](https://github.com/oneapi-src/oneAPI-samples) をDevCloudで試してみることができます．手順は，[Intel® DevCloud for oneAPI](https://devcloud.intel.com/oneapi/documentation/base-toolkit/) で解説されていますので，その通りに実行します．

まずは，GitHubからサンプルをcloneして，該当のディレクトリに移動します．

```
u89703@login-2:~$ git clone https://github.com/oneapi-src/oneAPI-samples.git
u89703@login-2:~$ cd oneAPI-samples/DirectProgramming/DPC++/DenseLinearAlgebra/vector-add/
u89703@login-2:~/oneAPI-samples/.../vector-add$ ls
License.txt    Makefile.win       sample.json               vector-add-buffers.vcxproj
Makefile       Makefile.win.fpga  src                       vector-add-usm.vcxproj
Makefile.fpga  README.md          third-party-programs.txt  vector-add.sln
```

普通の環境では，直接 `make` を使ってビルドしたり実行したりすればよいのですが，DevCloudでは合成や実行をバッチジョブとして投げられるようにするためにシェルスクリプトを用意するのがキモです．
以下のようなスクリプトを用意します．

```build_hw.sh
#!/bin/bash
source /opt/intel/inteloneapi/setvars.sh
make hw -f Makefile.fpga
```

バッチジョブを実行するには， `qsub`コマンドを使います．ジョブの実行先に，`fpga_compile`を指定します．

```
u89703@login-2:~/oneAPI-samples/.../vector-add$ qsub -l nodes=1:fpga_compile:ppn=2 -d . build_hw.sh 
1024878.v-qsvr-1.aidevcloud
```

バッチジョブの実行状況は，`qstat`コマンドで確認できます．

```
u89703@login-2:~/oneAPI-samples/.../vector-add$ qstat
Job ID                    Name             User            Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
1024878.v-qsvr-1           build_hw.sh      u89703                 0 R batch          
```

しばらくして`qstat`コマンドを実行すると，何も結果が返ってこなくなります．これで実行が完了です．だいたい10秒くらいでジョブは終わりました．

```
u89703@login-2:~/oneAPI-samples/.../vector-add$ qstat
u89703@login-2:~/oneAPI-samples/.../vector-add$
```

実行も，バッチジョブとして実行できるように，シェルスクリプトを用意します．

```run_hw.sh
#!/bin/bash
source /opt/intel/inteloneapi/setvars.sh
make run_hw -f Makefile.fpga
```

`run_build.sh`を実行したときと同じように，`qsub`コマンドを使って実行します．今度は，`-l nodes=1:fpga_runtime:arria10:ppn=2`として，FPGAが搭載されているサーバーにジョブを投げます．

```
u89703@login-2:~/oneAPI-samples/.../vector-add$ qsub -l nodes=1:fpga_runtime:arria10:ppn=2 -d . run_hw.sh 
1024879.v-qsvr-1.aidevcloud
```

このジョブで，実際にFPGAを使った処理の前にFPGA向けの合成と配置配線が走ります．45分くらいかかりました．
プログラムの実行結果は標準出力に表示されます．標準出力の結果は，`実行スクリプト名.oジョブ番号`というファイルに格納されています．ジョブ番号は，`qstat`で，一番左に表示されている番号です．

結果は，

```
u89703@login-2:~/oneAPI-samples/.../vector-add$ cat run_hw.sh.o1024880

########################################################################
#      Date:           Sun Nov 21 17:29:09 PST 2021
#    Job ID:           1024880.v-qsvr-1.aidevcloud
#      User:           u89703
# Resources:           neednodes=1:fpga_runtime:arria10:ppn=2,nodes=1:fpga_runtime:arria10:ppn=2,walltime=06:00:00
########################################################################

:: WARNING: setvars.sh has already been run. Skipping re-execution.
   To force a re-execution of setvars.sh, use the '--force' option.
   Using '--force' can result in excessive use of your environment variables.
dpcpp -O2 -g -std=c++17 -fintelfpga a.o -o vector-add-buffers.fpga -Xshardware
aoc: Compiling for FPGA. This process may take several hours to complete.  Prior to performing this compile, be sure to check the reports to ensure the design will meet your performance targets.  If the reports indicate performance targets are not being met, code edits may be required.  Please refer to the oneAPI FPGA Optimization Guide for information on performance tuning applications for FPGAs.
./vector-add-buffers.fpga
Running on device: pac_a10 : Intel PAC Platform (pac_ee00000)
Vector size: 10000
[0]: 0 + 0 = 0
[1]: 1 + 1 = 2
[2]: 2 + 2 = 4
...
[9999]: 9999 + 9999 = 19998
Vector add successfully completed on device.

########################################################################
# End of output for job 1024880.v-qsvr-1.aidevcloud
# Date: Sun Nov 21 18:17:45 PST 2021
########################################################################
```

のように得られました．

# Quartusを起動してみる

いつもの(？)FPGA開発のように，Quartus Primeをインタラクティブに利用することもできます．

まずはsshでログイン用サーバーにログインします．

```
$ ssh devcloud
```

サーバーにログインしたら，次のように環境変数設定用のスクリプトを読み込み`devcloud_login`コマンドでFPGA搭載サーバーにログインします．

```
u89703@login-2:~$ source /data/intel_fpga/devcloudLoginToolSetup.sh
u89703@login-2:~$ devcloud_login 

You are selecting an interactive compute server sesssion. Please consider using batch mode submission using
devcloud_login -b to not tie up compute servers with idle sessions.
See the help menu using devcloud_login -h for more details.

What are you trying to use the Devcloud for? 

1) Arria 10 PAC Compilation and Programming - RTL AFU, OpenCL
2) Arria 10 - OneAPI, OpenVINO
3) Stratix 10 PAC Compilation and Programming - RTL AFU, OpenCL
4) Stratix 10 - OneAPI, OpenVINO
5) Compilation (Command Line) Only
6) Enter Specific Node Number

Number: 
```

利用したい用途に応じたサーバーを選択します．たとえば，Stratix 10(PAC D5005)を使いたければ，3を入力します．番号を入力すると，次のように該当のサーバーにログイン出来ます．ログイン先のサーバー，下の例では，`s005-n008`はマシンの空き状況によって変わります．なお，ホームディレクトリは，ログイン用サーバーでもどのFPGAを利用するためのログインするサーバーでも共有されています．

```
Number: 3

--------------------------------------------------------------------------------------
For X2GO tunneling access. If connected to intel firewall, copy and paste the following text in a new mobaxterm terminal:  

ssh -L 4002:s005-n008:22 colfax-intel 

For X2GO tunneling access. For users NOT connected to intel firewall, copy and paste the following text in a new mobaxterm terminal:  

ssh -L 4002:s005-n008:22 devcloud 
--------------------------------------------------------------------------------------

running: qsub -q batch@v-qsvr-fpga -I -l nodes=s005-n008:ppn=2
qsub: waiting for job 28442.v-qsvr-fpga.aidevcloud to start
qsub: job 28442.v-qsvr-fpga.aidevcloud ready


########################################################################
#      Date:           Thu Dec 23 21:52:29 PST 2021
#    Job ID:           28442.v-qsvr-fpga.aidevcloud
#      User:           u89703
# Resources:           neednodes=s005-n008:ppn=2,nodes=s005-n008:ppn=2,walltime=06:00:00
########################################################################

u89703@s005-n008:~$ 
```

インタラクティブなアクセスは一度に一つしか開くことが出来ません．もし，複数のターミナルからサーバにアクセスしたければ，ログイン時にヒントがかかれているようにsshでログインしましょう．

```
$ ssh -L 4002:s005-n008:22 devcloud
```

FPGA搭載用サーバーにログインしたら，以下のようにスクリプトの読み込んで`tools_setup`を実行して，開発用の環境を準備します．

```
u89703@s005-n008:~$ telnet localhost 4002
-bash: telnet: command not found
u89703@s005-n008:~$ source /data/intel_fpga/devcloudLoginToolSetup.sh
u89703@s005-n008:~$ tools_setup 

Which tool would you like to source?
1) Quartus Prime Lite
2) Quartus Prime Standard
3) Quartus Prime Pro
4) HLS
5) Arria 10 PAC Compilation and Programming - RTL AFU, OpenCL
6) Arria 10 - OneAPI, OpenVINO
7) Stratix 10 PAC Compilation and Programming - RTL AFU, OpenCL
8) Stratix 10 - OneAPI, OpenVINO

Number:
```

たとえば，Stratix 10を利用したい，ということであれば7を入力します．

```
Number: 7
sourcing /glob/development-tools/versions/fpgasupportstack/d5005/2.0.1/inteldevstack/init_env.sh
export QUARTUS_HOME=/glob/development-tools/versions/fpgasupportstack/d5005/2.0.1/inteldevstack/quartus
...
Putting python2 in the search path - required for Stratix 10 development stack
u89703@s005-n008:~$ 
```

# OPAEのサンプルをビルド，利用してみる

OPAEを使ってFPGAを制御できます．サンプルをビルドして利用してみましょう．環境変数が正しくセットされていれば，`$OPAE_PLATFORM_ROOT`でOPAEに関するリソース一式にアクセスできます．手順自体は，手元で合成・配置配線して実行する場合と何も変わりません．

まずは，サンプルをホームディレクトリにコピーします．

```
u89703@s005-n008:~$ cp -r $OPAE_PLATFORM_ROOT/hw/samples/dma_afu .
```

サンプルプロジェクトの下で，`afu_synth_setup`を使ってビルド環境を用意，`run.sh`で合成と配置配線を実行します．

```
u89703@s005-n008:~$ cd dma_afu
u89703@s005-n008:~/dma_afu$ afu_synth_setup --source hw/rtl/filelist.txt build_synth
u89703@s005-n008:~/dma_afu/$ cd build_synth
u89703@s005-n008:~/dma_afu/build_synth$ run.sh
```

合成と配置配線が終了するまでに，約55分かかりました．合成が終わったら，`.gbs`ファイルができあがりますので，FPGAに書き込みます．

```
u89703@s005-n008:~$ fpgasupdate dma_afu_S10.gbs
```

FPGA側の準備が終わったので，プロセッサ上で動かすソフトウェアをビルドして実行しましょう．

```
u89703@s005-n008:~/dma_afu/build_synth$ cd .. 
u89703@s005-n008:~/dma_afu/sw$ make clean all
rm -f fpga_dma_test *.o *.so *.a *.dat *.log
g++ -D FPGA_DMA_DEBUG=0 -g -O2 -fPIC -D EMU_MODE=0 -Wall -Wno-unknown-pragmas -I/include -fpermissive -std=c++11 -DFPGA_DMA_MAX_BLOCKS=256 -DFPGA_DMA_BLOCK_SIZE=64   -c -o fpga_dma_test.o fpga_dma_test.cpp
...
g++ -o fpga_dma_test fpga_dma_test.o fpga_pattern_gen.o fpga_dma.o fpga_pattern_checker.o fpga_dma_test_utils.o fpga_dma.a  -luuid -lsafestr -lrt -ltbb -L/lib/intel64_lin/gcc4.7/ -ljson-c -lopae-c -lhwloc -pthread -lm
u89703@s005-n008:~/dma_afu/sw$ ./fpga_dma_test -s 104857600 -p 1048576 -r mtom
PASS! Bandwidth = 12645 MB/s
```

せっかくビルドしたので，DMAの転送性能，MMIOでのリードライトのレイテンシを測定してみました．

スループットは，ホストサーバのメインメモリからFPGAボード上のメモリへのデータ転送(HOST->FPGA)が，約7.6GBps，FPGAボード上のメモリからホストサーバーのメインメモリへのデータ転送(FPGA->HOST)が，約12.7GBpsでした．
![dma_afu_result_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/3b3c82c1-d799-bcf2-76aa-1f47e0098a85.png)

サーバー上のプログラムからFPGAに制御コマンドを送ったり，FPGAの状態を知るためには，OPAEでは`fpga{Write,READ}MMIO64という関数を用います．それぞれのレイテンシも測定してみました．繰り返し同じレジスタの読み書きを行なってもほぼレイテンシは一定で，書き込みは150n秒程度，読み出しは1マイクロ秒程度のレイテンシであることがわかりました．
![dma_afu_result_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/a1de0204-3a70-3794-d396-2e90ea316399.png)

# GUIを利用する

GUIを利用する場合には，X2Goを利用します．[X2Go](https://wiki.x2go.org/doku.php)は，ssh上でXクライアントを転送するサーバーとクライアントがペアになったソフトウェアです．RDPやVNCと違って，sshをそのまま利用するので別途通信ポートを開ける必要がないというメリットがあります．

X2Goでアクセスする前に，以下のようにして，ログインしているサーバーへのsshポートフォワーディングを開きます．次のコマンドでは，devcloudを踏み台にしてs005-n008の22番ポートに対して，localhostの4002番ボートからアクセスできるようなポートフォワーディングを設定している例です．

```
$ ssh -f -N -L 4002:s005-n008:22 devcloud
```

開いたローカルポート(4002)に対して，X2Goで接続するように設定します．

![Screenshot_2021-12-24_21-06-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/edea208d-a54c-659b-dd79-4924cefc7fdf.png)

接続すると，指定したプログラム（ここでは，デスクトップ環境のXFCEを指定している）を起動することができます．

![Screenshot_2021-12-24_21-10-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/32cfdc11-2499-6b7c-aded-f38792fce3d7.png)

あとは，普段と同じように，QuartusなどのGUIウィンドウを開くことができます．ターミナルを開いて，ツールを利用するための環境設定をしてから，`quartus`を起動しましょう．

![Screenshot_2021-12-24_21-14-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/642933ed-dc86-f69d-7ff8-02891231d14b.png)

![x2go_quartus.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/e5b52011-c5a2-e6bb-2e7a-b1df11c63a45.png)

# 独自の回路を組み込む

もちろん，自分の回路を組み込むこともできます．一度ビルドしたサンプルのプロジェクトを開いて，OPAEのGreen bit stream部分に独自回路をぶらさげるのが楽でよいでしょう．
Green bit streamのトップエンティティには，Quartusでプロジェクトを開いた後，Project Navigatorのインスタンスツリーを開いていくことでアクセスすることができます．

OPAEのサンプルの一つであるdma_afuの場合，`dcp_top`->`fpga_top`->`inst_green_bs`->`platform_shim_ccip_std_afu`->`ccip_std_afu`->`afu_inst`と辿ってアクセスすることができます．このサンプルの場合は，メインロジックはPlatform Designerを作って組み立てられています．`afu_inst`の下の`system_wrapper`->`u0`とツリーを開いて，`u0`をダブルクリックするとメインロジックを構成するPlatform Designerの設定ウィンドウを開くことが出来ます．

DMAコントローラなどに，独自ロジックをぶらさげることで，DevCloud上のFPGAに所望の処理をさせることができます．

![add_orig_logic_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25342/6b748433-d06d-76ae-5067-0c46ae0c342e.png)

# おわりに

Intel DevCloudで遊んでみる方法を紹介しました．DevCloudはArria 10やStratix 10といった高価なボードを無料で利用できるありがたいサービスです．ツールのセットアップ，FPGAと通信するためのOSの設定も終わっていますので，すぐにFPGA開発をはじめることができます．折角なので，OneAPIを試してみたり，独自ロジックをFPGA上で動かしてみたり，と，楽しんでみてください．