Amazon EC2でFPGAをつかう

2018/03/07

SDAccelでOpenCLのプロジェクトをbuildする

Amazon Web ServicesでFPGAを使い、OpenCLのコードを実行するため。

SDAccelのガイド

参考1 参考2

準備

OpenCLのbuildをするためには"FPGA Developer AMI"のインスタンスを稼働する必要がある。 buildには、ソフトウェアエミュレーション(sw_emu)、ハードウエアエミュレーション(hw_emu)、 FPGA用のビットファイル生成(hw)の三種類がある。

ビットファイルを生成するには、メモリの多い(32GB程度)インスタンスが推奨されているが、 2種のエミュレーションをするだけなら、その必要はないと思われる。 テストのプロジェクトでは、t2.large(メモリ8GB)でも問題はなかった。 build用のインスタンスは東京リージョン(ap-northeast-1)でもかまわない。 ただし、FPGAが使えるF1インスタンスは現時点では東京リージョンでは使えないため、 ビットファイルをテストするときには米国東部:バージニア北部リージョン(us-east-1)などの利用が必要。

ビットファイルを生成したあと、Amazon FPGA Imageの生成というタスクを AWS CLIから実行する必要があり、 これは東京リージョンではできない。 利用するS3のバケットおよび"aws"コマンドを実行するリージョンをus-east-1にする必要がある。

倹約のためt2.largeとc4.4xlargeのインスンタスを切り替えて使う。 OpenCLコードのテストデバッグはt2.largeで、ビットファイル生成はc4.4xlargeで。 切り替える時に、AMI用とユーザー領域のボリュームとをデタッチ・アタッチするのが面倒。 AWS CLIによって、Webコンソールを使わなくても、デタッチ・アタッチ及びインスタンス開始が可能。

“FPGA Developer AMI"を稼働する際のディスクは以下のようになっている。

ルートデバイス /dev/sda1  /
ユーザー領域   /dev/sdb   /home/centos/src/project_data

ユーザー領域には念のため30GBを割り当てた。

このAMIの中身はcentosで、sshするときのデフォルトのユーザー名は"centos"であり、 “root"や"ec2-user"ではない。

手順

SSAccelのガイドに従えばよい。

aws-fpgaレポジトリのclone

適当な場所にて。

git clone https://github.com/aws/aws-fpga.git

環境の設定

以下のコマンドはbashで行う必要がある。

source aws-fpga/sdaccel_setup.sh

この実行後は、他のshellを起動してもいい。zshでは問題なし。

ソフトウェアエミュレーション用のbuild

サンプルのプロジェクト(helloworld_oclなど)をコピーする、または自分のプロジェクトを作る。 以下、そのディレクトリ内で実行する必要がある。

make TARGETS=sw_emu DEVICES=$AWS_PLATFORM_1DDR all

DEVICESに指定できるのは、$AWS_PLATFORM、$AWS_PLATFORM_4DDRまたは$AWS_PLATFORM_1DDRのどれか。 最後の指定はメモリをひとつしか使わないので、より短時間で実行できるはず。テスト用。

ソフトウェアエミュレーションで実行する。

XCL_EMULATION_MODE=sw_emu ./helloworld

ハードウェアエミュレーション用のbuild

make TARGETS=hw_emu DEVICES=$AWS_PLATFORM_1DDR all

このエミュレーションもt2.largeインスンタスで実行した。 東京リージョンでは1時間あたり0.1216ドルかかる。

ハードウェアエミュレーションで実行する。

XCL_EMULATION_MODE=hw_emu ./helloworld

実機用のbuild

make TARGETS=hw DEVICES=$AWS_PLATFORM_1DDR all

この実行だけは推奨されているc4.4xlargeでおこなった。 c4.4xlargeの利用は東京リージョンでは1時間あたり1.008ドル(20180307時点)かかる。無料枠でもない。 これよりしょぼいインスタンスで実行するとどうなるかは不明。

デフォルトの$AWS_PLATFORM($AWS_PLATFORM_4DDR)の場合3時間以上かかった。 $AWS_PLATFORM_1DDRの場合1-2時間くらいで気持ち速い。

Amazon FPGA Image(AFI)の生成

実機用のビットファイルをEC2で実行できる形式に変換する。詳細は不明だが30分程度かかる。 結果を保持するS3のバケットを事前に作成する。 これはF1インスタンスがあるリージョン(今回はus-east-1リージョン)に作る必要がある。 また、以下のスクリプトはAWS CLIを呼び出すので、 デフォルトリージョンもus-east-1に設定する。

$SDACCEL_DIR/tools/create_sdaccel_afi.sh -xclbin=xclbin/<長い名前>.xclbin -o=<長い名前> \
   -s3_bucket=<bucket-name> -s3_dcp_key=dcp -s3_logs_key=log

ガイドに従う。"-xclbin"にはbuildしたビットファイルを指定する。 結果を保持するバケットに"dcp"と"log"というフォルダを作成しておく。

F1インスタンスで実行

AWSのアカウントを作っただけでは、us-east-1リージョンでのF1インスンタスの稼働は認められていない。 EC2ダッシュボードの「制限」から、F1を使えるようにリクエストする必要がある。

英語で、制限解除のリクエストをしてから約1日で承認された。 承認のメールは、日本時間の深夜に届いたので、多分USの担当者と思われる。 追加での特別な説明は必要なかった。

F1インスタンスの利用が承認されたら、 そのリージョンにて、“FPGA Developer AMI"を使ってF1インスタンスを開始する。 なおこのAMIはスワップ領域を30GBも指定しているが、実機テストには必要ない。 AMIをカスタマイズしたほうがよさそう。

AFIの生成が終わりavailableになっているとして、実機での実行に必要なものは、 アプリケーションの実行ファイルと”<長い名前>.awsxclbin"のファイルだけでよい。 後者のファイルにAFIをロードするのに必要な情報が入っている模様。 これらを稼働中のインスタンスまたは、利用するボリュームにコピーする必要がある。 今回は別の計算機を介してscpでコピーした。

1DDR用のビットファイルを利用するには、 SDAccelのガイドにあるように、 “<長い名前>.awsxclbin"の名前を変えたコピーが必要。

cp <kernel名>.hw.xilinx_aws-vu9p-f1_1ddr-xpr-2pr_4_0.awsxclbin <kernel名>.hw.xilinx_aws-vu9p-f1_4ddr-xpr-2pr_4_0.awsxclbin

これをしないと4DDR用のファイル名を探して失敗する。

実行するにはroot権限が必要なので

sudo bash
source /opt/Xilinx/SDx/2017.1.rte.1ddr/setup.sh #1DDRの場合

の後で、buildしたアプリケーションを実行できる。 初めて実行する時にビットファイルのコンフィグが行われるので、それにしばらく時間がかかる。

できた。 deviceに"4ddr"とあるが、上にあるようにファイルをコピーしているので、実際には1ddrである。

これは、整数ベクトルに定数を乗算するカーネル。 2度目以降は、コンフィグをスキップするので即実行される。

F1インスタンスが使えるリージョン

オンデマンドインスタンス 2018年3月

リージョン 英語名 f1.2xlarge f1.16xlarge
バージニア北部 us-east-1 1.65ドル 13.2ドル
オレゴン us-west-2 1.65ドル 13.2ドル
アイルランド eu-west-1 1.815ドル 14.52ドル

スポットインスタンス(20180308のある時刻)

リージョン 英語名 f1.2xlarge f1.16xlarge
バージニア北部 us-east-1 0.6572ドル 5.1121ドル
オレゴン us-west-2 0.7031ドル 13.2ドル
アイルランド eu-west-1 0.7003ドル 14.52ドル

新規プロジェクト用のMakefile

Introduction to the SDAccel Makefileにより詳しい説明がある。

アプケーションのコードが"main.cpp”、実行ファイル名が"run”、 OpenCLのカーネルファイルが"TemplateC_Kernels.cl”、 その中の利用するうカーネル関数名が"templateKernel"の場合。

COMMON_REPO := $(SDACCEL_DIR)/examples/xilinx
include $(COMMON_REPO)/utility/boards.mk
include $(COMMON_REPO)/libs/xcl2/xcl2.mk
include $(COMMON_REPO)/libs/opencl/opencl.mk

# run Host Application
run_SRCS=./main.cpp $(xcl2_SRCS)
run_HDRS=$(xcl2_HDRS)
run_CXXFLAGS=-I. $(xcl2_CXXFLAGS) $(opencl_CXXFLAGS)
run_LDFLAGS=$(opencl_LDFLAGS)

EXES=run

# Kernel
templateKernel_SRCS=./TemplateC_Kernels.cl

XOS=templateKernel

# run xclbin
templateKernel_XOS=$(XOS)

XCLBINS=$XOS

# check
check_EXE=$(EXES)
check_XCLBINS=$(XOS)

CHECKS=check

include $(COMMON_REPO)/utility/rules.mk

“# Kernel"と”# run xclbin"の次の行の変数名を正しく設定しないと、 カーネルファイル(今の場合、TemplateC_Kernels.cl)が見つからないと怒られる。