Zybo+VitisでSDSoC相当の高位合成やってみた

2019年11月25日

先日、Vitis初のリリースとなるVitis 2019.2がリリースされました。
VitisはXilinx FPGAのSW部分のための統合開発環境で、従来は3つのツールに分かれていたXilinx SDK, SDSoC, SDAccelをひとまとめにしたツールとなっています。
Vitis+Alveoボードを使用した、SDAccel相当の高位合成の方法は先日当ブログでも紹介しましたが、本稿では安価なZybo Z7-20 FPGAボード (以下、Zybo)を用いて、SDSoC相当の高位合成を紹介したいと思います。

実際の高位合成の説明を行う前に、まずSDSoCについて簡単に説明します。
SDSoCは、ARM CPUとFPGAロジックの搭載された、Zynq/Zynq Ultrascale+ FPGAをターゲットとした高位合成ツールです。
ユーザはまずC/C++でARM CPU向けに行いたい処理を記載し、その処理のうちFPGA側で高速化したい処理を、関数単位で指定することができます。
FPGA側で処理される関数は、Vivado HLSにより高位合成されRTLコードへと変換されるため、ユーザはハードウェア記述言語によるプログラミングを必要とせず、あくまでC/C++のみでFPGAを使用することができます。
実際にFPGA上で高速に処理を行うには、#pragma をC/C++コード内に挿入するなどの方法でチューニングが必要となるのですが、RTLより大幅に時間を節約することができます。

Vitisでは、SDSoC時代と比較してARM CPU側のコード上からOpenCL APIを用いてFPGA側の関数を呼ぶ必要があったりするなど (SDSoC時代はC APIと選択可)、不便ではある点もあるのですが、何よりSDSoCと違い無料で使用できるというメリットがあります。また、Alveo等のアクセラレータカードと同じコードのまま組み込み環境でも使えるなどのメリットもあるので、勉強しておいて損はないと思われます。

準備

本実験は、以下の環境で行いました。

  • OS: Ubuntu 16.04 LTS
  • CPU: Intel Core i7-6800K
  • Memory: 64GB

また、開発には以下のツールが必要となったため、それらをインストールします。
XRTはFPGAとホストPCを繋ぐためのランタイムのため今回は必要なさそうですが、<XRT_ROOT>/bin/xclbinutilというツールをVitisが必要とするためインストールします。

また、以下のコマンドを実行して環境変数を更新しておきます。

$ source <VIVADO_ROOT>/settings64.sh
$ source <VITIS_ROOT>/settings64.sh
$ source <PETALINUX_ROOT>/settings.sh
$ source <XRT_ROOT>/setup.sh

プラットフォームの作成

ここからの内容は、Vitis Application Acceleration Development (UG1393)のSection IXの内容と、SDSoC Environment Platform Development Guide (UG1146)の内容を、Zybo向けに移植したものとなります。

Vitis上でSDSoC相当の高位合成を行うためには、まずアプリケーションが動作するためのプラットフォームを定義する必要があります。
プラットフォームには、FPGAに実装されるハードウェアの情報や、ARMが動作するOS等のソフトウェアの情報が含まれます。
プラットフォームの作成は、以下の3手順で行うことができますので、次節から順に行っていきます。

  1. HWコンポーネントの作成 (Vivado)
  2. SWコンポーネントの作成 (Petalinux)
  3. Vitis プラットフォームプロジェクトの作成 (Vitis)

HWコンポーネントの作成

まず最初に、Vivadoを用いてHW情報を定義します。
ここでの目的は、後にVitisがFPGA内の機能を使う際に、クロックやAXIポートなど、どの部分を使ってよいかを定義することです。

まず、Vivadoを立ち上げてZybo Z7-20をターゲットとしてプロジェクトを作成します。
その後、Flow NavigatorからIP INTEGRATOR -> Create Block Design を選択し、デフォルト名のままブロックデザインを作成します。
この時点での画面は、下図のようになります。

この状態から、以下の手順でIPを配置していきます。

  1. Add IP (+)をクリックし、ZYNQ7 Processing Systemを追加
  2. Run Block Automationをクリックし、デフォルト値のままOKを押す
  3. ZYNQ7 Processing Systemをダブルクリックし、PS-PL Configuration -> AXI Non Secure Enablement -> GP Master AXI Interface -> M_AXI_GP0 interface のチェックを外し、OKをクリック
  4. Clocking Wizardを追加し、その後同IPの設定のOutput Clocksタブより、clk_out2 を150MHz, clk_out3を200MHz, Reset TypeをActive Lowとする
  5. clk_wiz_0 (Clocking Wizard)のresetnをprocessing_system7_0 (ZYNQ7 Processing System)のFCLK_RESET0_[N]に接続し、同様にclk_in1をFCLK_CLK0に接続
  6. Processor System Reset を3つAdd IPより追加し、以下のポートを接続
    • clk_wiz_0のclk_out[N]とproc_sys_reset[N-1]のslowest_sync_clk
    • clk_wiz_0のlockedと各proc_sys_resetのdcm_locked
    • processing_system7_0のFCLK_RESET0_Nと各proc_sys_resetのext_reset_in

文字だけになってしまいましたが、上記手順を終えると以下のようなブロックデザインとなります。

ここまでで、Vivadoによるベースとなるデザインの定義が完了します。
一方で、せっかく作成した3種類のクロックは、現デザインではどこにも接続されていません。
これらのポートをVitisが高位合成に使用していることを、次の手順で定義していきます。

まず、メニューバーのWindow -> Platform Interfaces をクリックし、現れた画面のEnable Platform Interfaces をクリックします。
この時点で、下図のようなウィンドウが表示されます。

この画面では、Vitisが高位合成時に使用できるポートのリストが定義されています。
デフォルトでは全てのポートが無効となっているため、右クリック->Enableとすることで、必要なポートを有効にしていきます。
今回は、FCLK_CLK0を除くすべてのポートを有効とします。

また、クロックに関してのみ追加で設定が必要となります。
clk_out1から順にidを0, 1, 2とし、clk_out1のみis_defaultをチェックします。
ここで、idが0番のクロックを作成し忘れたり、is_defaultをチェックし忘れたりすると後にVitisが高位合成時にエラーを出力するので、忘れずに設定するようにしましょう。
最終的には以下の画面のような設定となります。

最後に、Tcl Console より以下のtclコマンドを実行します。

set_property platform.design_intent.embedded true [current_project]
set_property platform.design_intent.server_managed false [current_project]
set_property platform.design_intent.external_host false [current_project]
set_property platform.design_intent.datacenter false [current_project]
set_property platform.default_output_type "sd_card" [current_project]

ここまででVitisのための設定は終わりです。
後は、Sourcesビューよりdesign_1を右クリックし、Create Design Wrapperを押してラッパを作成し、Flow -> Generate Bitstream としてビットストリームを作成します。
合成自体はマシンスペックにもよりますが10分もかからず完了するので、完了後次のtclコマンドを実行して、プラットフォームを出力・検証します。

cd <VIVADO_PROJECT_TOP>
write_hw_platform -include_bit zybo_min.xsa
validate_hw_platform zybo_min.xsa

SWコンポーネントの作成

次に、SWコンポーネントを作成します。
SWコンポーネントとは、後に作成する高位合成アプリケーションを動かすための環境であり、今回はXRT等をインストールした、ARM上のlinux環境となります。
SDSoC以前はlinuxを使用しないスタンドアロン実行も可能でしたが、Xilinxのドキュメントを見る限りでは、HWによるアクセラレーション機能を使用する場合は、Vitisでは XRTをインストール済みのlinuxが必須となるようです。

以下よりLinuxのビルドをpetalinuxツールにより行います。
0. まず、以下のような構成でpfm以下のディレクトリ構成を作成します。

<VIVADO_PROJECT_TOP>
|-- <XXX>.xpr
|-- zybo_min.xsa
|-- ...
`-- pfm
    |-- boot 
    |-- qemu
    `-- wksp1

1. Zynq用のpetalinuxプロジェクトを次のコマンドで作成します。

$ cd <VIVADO_PROJECT_TOP>                                  
$ petalinux-create -t project --template zynq -n petalinux 
$ cd petalinux

2. zybo_min.xsaファイルの存在するディレクトリをpetalinux-configに与え、ハードウェア情報を取得します。menuconfigの画面が出るので、そのままexitします。

$ petalinux-config --get-hw-description=..

3. 以下に示すコードをproject-spec/meta-user/conf/user-rootfsconfigの末尾に追記することで、rootfsのコンフィグ時にXRT等を追加できるようします。

CONFIG_xrt
CONFIG_xrt-dev
CONFIG_zocl
CONFIG_opencl-clhpp-dev
CONFIG_opencl-headers-dev
CONFIG_packagegroup-petalinux-opencv                       

4. project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsiの末尾に以下のコードを追記し、zoclドライバーをデバイスツリーに追加します。

&amba {
    zyxclmm_drm {
        compatible = "xlnx,zocl";
        status = "okay";
    };
};

5. $ petalinux-config -c rootfs を実行し、User packages 以下の項目を全てチェックし、保存して終了します。
6. $ petalinux-config -c kernel を実行し、Device Drivers -> Generic Driver Options -> DMA Contiguous Memory Allocator -> Size in Mega Bytes の値を64MBとします。
7. $ petalinux-build として、linuxをビルドします。この手順は10分~程度かかります。
8. $ cd images/linux; petalinux-build --sdk として、sysrootを作成します。この手順は30分近くかかるので気長に待ちましょう。
9. $ ./sdk.sh -d <VIVADO_PROJECT_TOP>/pfm とし、pfmディレクトリ以下に作成したsysrootを出力します。
10. 次のファイルをimages/linux以下から<VIVADO_PROJECT_TOP>/pfm/boot に移動、リネームします。

images/linux/image.ub      -> <VIVADO_PROJECT_TOP>/pfm/boot/image.ub
images/linux/zynq_fsbl.elf -> <VIVADO_PROJECT_TOP>/pfm/boot/fsbl.elf
images/linux/u-boot.elf    -> <VIVADO_PROJECT_TOP>/pfm/boot/u-boot.elf
images/linux/system.dtb    -> <VIVADO_PROJECT_TOP>/pfm/boot/system.dtb

11. 次に示すBIFファイルを<VIVADO_PROJECT_TOP>/pfm/boot/linux.bif として作成します。Vitisに絶対パスやビットストリーム名を補完してもらうため、<>はつけたままにします。

/* linux */
the_ROM_image:
{
    [bootloader] <fsbl.elf>
    <bitstream>
    <u-boot.elf>
}

12. 下に示すファイルを<VIVADO_PROJECT_TOP>/pfm/qemu/qemu_args.txt に作成します。この手順はUG1393には記載がないのですが、後にSW/HWエミュレーションをQEMU上で動かす際に必要となります。

-M
arm-generic-fdt-7series
-serial
/dev/null
-serial
mon:stdio
-device
loader,addr=0xf8000008,data=0xDF0D,data-len=4
-device
loader,addr=0xf8000140,data=0x00500801,data-len=4
-device
loader,addr=0xf800012c,data=0x1ed044d,data-len=4
-device
loader,addr=0xf8000108,data=0x0001e008,data-len=4
-device
loader,addr=0xF800025C,data=0x00000005,data-len=4
-device
loader,addr=0xF8000240,data=0x00000000,data-len=4
-boot
mode=5
-kernel
<u-boot.elf>
-dtb
<system.dtb>
-machine
linux=on

長くなりましたが、ここまででlinuxの準備が完了します。
後は、Vitisからここまでで定義したHW/SWコンポーネントを使用した、プラットフォームを作成するだけです。

Vitis プラットフォームの作成

ここでようやくVitisを立ち上げます。
<VIVADO_PROJECT_TOP>/pfm に移動し、$ vitis -workspace wksp1 として、Vitisを起動しましょう。
Vitisが起動したら、以下の手順でVitisプラットフォームを作成していきます。

  1. Create Platform Project をクリック
  2. プロジェクト名をzybo_minとしてNext
  3. Create from hardware specification (XSA) がチェックされていることを確認し、Next
  4. XSAファイルに<VIVADO_PROJECT_TOP>/zybo_min.xsa を指定し、Software SpecificationのOSをLinuxとしてFinish

この時点で、下図のような画面となります。

後は、先ほどまでに生成したファイルをBIF File以降にそれぞれ設定していきます。

  • BIF File: <VIVADO_PROJECT_TOP>/pfm/boot/linux.bif
  • BOOT Components Directory: <VIVADO_PROJECT_TOP>/pfm/boot
  • Linux Image Directory: <VIVADO_PROJECT_TOP>/pfm/boot
  • Sysroot Directory: <VIVADO_PROJECT_TOP>/pfm/sysroots/cortexa9t2hf-neon-xilinx-linux-gnueabi
  • QEMU Data: <VIVADO_PROJECT_TOP>/pfm/boot
  • QEMU Arguments: <VIVADO_PROJECT_TOP>/qemu/qemu_args.txt

上記設定後、画面左下のAssitantビューからzybo_minを右クリック -> Build とすれば、プラットフォームが完成します。
boot 以下のファイルを書き換え等する際は、適宜プラットフォームを再ビルドします。

長くなりましたが、ここまででプラットフォームが作成できました。
このプラットフォーム作成は初回のみで良いので、後は自由に高位合成アプリケーションを作成していくことができます。

アプリケーションの作成

ようやくアプリケーションの作成です。
今回は、元々サンプル上で定義されているvecaddアプリケーションを使用して、Vitisによる高位合成結果を確認していきたいと思います。

Vitisプラットフォーム作成後の画面から、File -> New -> Application Project とし、プロジェクトを作成します。
プロジェクト名はvecaddとして、Nextをクリックします。

次に、zybo_minがプラットフォーム内にあることを確認し、それを選択します。
ここでzybo_minが見えない場合は、上記までのプラットフォーム作成で何らかの失敗をしていると思われます。
例えばプラットフォーム作成時に最後にビルドを忘れた場合などでもzybo_minが見えないため、注意が必要です。
また、FlowがEmbedded Accelerationとなっていることを確認しましょう。
Embeddedのみの場合は高位合成によるアクセラレーションが有効でないため、これも何かの手順が間違っていると思われます。
またAccelerationがついていてもEmbeddedでない場合は、HWコンポーネント作成時のset_propertyが間違っている可能性が高いです。

次の画面ではDomainが聞かれますが、デフォルト値のままで良いのでそのままNextします。
最後に、アプリケーションテンプレートをVector AdditionとしてFinishします。
結果として、下図のような画面が得られます。

このvecaddアプリケーションでは、krnl_vaddという関数がHardware Functions、つまり高位合成対象の関数として定義されています。
krnl_vadd関数自体は下図のようになっており、ハードウェア上で効率的に実行されるように、ループ順の変更や#pragmaが追加されたコードとなっています。

Vitisでは、アプリケーションを実機上で動かす以外に、Software Emulation, Hardware Emulationと呼ばれるエミュレーション機能があります。
Zynqでは、これらエミュレーションはXilinxのビルドしたQEMU上で行われます。
Software Emulationは、上記のkrnl_vadd関数をそのままCコードとして実行することを指し、Hardware Emulationは上記のkrnl_vadd関数を高位合成でRTLコードに変換した後に、RTL+Cの協調シミュレーションでkrnl_vadd関数を実行することを指します。
次節より、順にこれらの実行結果を確認していきます。

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

ソフトウェアエミュレーションは、Vitisの左下のAssistantビューより行うことができます。
まず、Assistantビュー内のvecadd_system->vecadd->Emulation-SWを右クリックし、ビルドします。
ビルド後、再度Emulation-SW を右クリックし、 Run -> Launch On Emulatorを選択します。
ポップアップした画面のStart Emulator and Runをクリックすると、自動的にQEMUが立ち上がり、その上でSoftware Emulationが行われます。

下図は、エミュレーション実行後の画面となります。左から順に、Assistantビュー、Vitisのコンソール、QEMUのコンソールとなります。現状では、残念ながらVitisコンソール2行目でFATAL ERRORが発生し、テストが失敗となっています。

この現象が起きるのは、/mnt/data/emulation/unified/cpu_em/zynq/model/genericpciemodel というファイルがQEMUで動作しているlinux上で存在しないためです。
このファイルは、QEMUをブートするためのSDカードイメージ内に含まれているのですが、これはデフォルトで/run/media/mmcblk0p1 にマウントされています。なので、上記SDカードを/mnt 以下に再マウントします。
画面右下のqemu% からのコンソールに、次のコマンドを順に入力していきます。最初の2行はユーザー名とパスワードです。

root
root
umount /run/media/mmcblk0p1
mount /dev/mmcblk0p1 /mnt

上記コマンドを入力し、Assitantビュー内のDebugger_vecadd-Emulationを右クリックし、再度Runします。
ここで以下のようなQEMUを再起動するかどうか尋ねるコンソールが現れますが、今回は再起動をしたくないため、そのままRunとします。

すると、下図のように今度はテストが成功します。
Vitisでは、エミュレーション/実機実行の後に実行時間などを含むレポートを出力する機能が入っており、Debuggger_vecadd-Emulationの下にRun Summaryというファイルができています。
これをダブルクリックすればVitis Analyzerが起動しレポートの内容を確認できるのですが、これは後の実機動作で確認したいと思います。

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

次にハードウェアエミュレーションを行います。
ビルド・実行の手順自体はソフトウェアエミュレーションと同じ手順となります。

ハードウェアエミュレーションでは、ビルド時にVivado HLSによるC->RTL変換が走るため、ソフトウェアエミュレーションよりも長くなります。
Vivado HLSによる高位合成結果は、ビルド後にAssitantビューから Emulation-HW -> binary_container_1 -> krnl_vadd を右クリックすると、Open HLS Projectという項目があるため、そこから確認できます。

krnl_vadd 高位合成結果

上記の合成結果では、ap_clkのTargetが10.nsのため、HWコンポーネント作成時にis_defaultとした100MHzをターゲットに高位合成が行われているようです。
また、Latency->Summaryの項目を見ると、このkrnl_vadd関数は4096要素のvector additionを行うのですが、それを8609サイクルで処理できていることが分かります。

それでも実際の回路の合成に比べれば非常に短い時間となるため、まずはハードウェアエミュレーションで所望の性能が出ているか確認することが大事になります。
高位合成による開発を行う際には、まずこのレポートを見て所望の性能が達成できているか確認することで、無駄な論理合成時間を削れたりするので忘れずに確認するようにしましょう。

ハードウェアエミュレーションを実行すると、Vivadoが立ち上がり、波形シミュレーションが始まります。
本来はSDSoCでのQEMUエミュレーションのチュートリアルの2:30~のような形でエミュレーションができるとは思うのですが、今回は以下のようにVivado上で下図のようなエラーが発生してしまいました。

ログを見る限り、_ZN14remoteport_tlm7tie_offEv関数がリンクされていないようです。
VIVADO_ROOT以下にある上記関数が含まれるライブラリ(libremote_port_sc_v4.so) を無理やりリンクしてみたりもしたのですが、Vivadoの波形シミュレーションは可能になったものの、VivadoとQEMUがうまく繋がっていないようで、QEMUが上記画面から進みませんでした。
おそらくremote_port_sc_v4というIPがVivado上でインスタンスされていないのが根本的な問題のような気がするので、何か手順が不足しているのかもしれません。
こちらは原因が分かり次第更新したいと思います。

実機動作

最後に、ハードウェアでの実行を行います。
ハードウェアもエミュレーションと同様にビルドを行えるのですが、そのまえにまずいくつかのプロファイル機能を有効としておきます。
AssistantからHardware->binary_container_1->krnl_vaddを右クリックし、Settingsをクリックすると、下図のような画面が表示されます。

krnl_vadd 設定画面

上記画面では既に設定を更新済みなのですが、デフォルトではCompute Unit Settings内のMemoryがAuto、Data TransferがNone、Stall Profilingのチェックがオフとなっています。
今回はプロファイル情報が欲しいため、Data TransferをCounters+Traceに、Stall Profilingをチェックしています。
Memoryの値はAuto, HPの他にACPが選べるのですが、HPがARM側のDDRに対して直接アクセスするポートで、ACPがARM内のキャッシュとの一貫性を保ちつつアクセスするポートとなります。ACPの方がCPUキャッシュからDDRへのフラッシュを省けるため一般的にはレイテンシが良くなるのですが、今回は特に必要ないためHPに固定しています。

また、上記設定の他にもCompute unitsを増やすことでkrnl_vaddを複数インスタンス化したり、色々と設定を変更できるようです。
またここではHWプラットフォーム作成時に行った、複数クロックの選択機能は見つからなかったのですが、v++コンパイラオプションには--clock.defaultId arg というオプションもあるので、適切に書けばクロックを変更できると思われます。

また、ビルドを行う前に、veaddアプリケーションのデフォルトの要素数が4096と少ないため、値を増やしておきます。
ここでは、vadd.cppの49行目及びkrnl_vadd.cppの52行目のDATA_SIZEを4096から4194304とします。
ここで設定できるDATA_SIZEの上限はSWコンポーネント作成時の手順6で、どれだけCMA領域を割り当てたかによって決定されます。
今回は64MBを設定し、vaddの演算対象がunsigned intのため、設定可能な要素数は最大でも64MB/(sizeof(unsigned int)*3)となります。
実際に要素数を8*1024*1024としたところ、std::bad_allocが出てテストが失敗することを確認できました。

ここまで設定が完了したら、ハードウェアのビルドを行います。
上記までのエミュレーションとは異なり、ここではFPGAの論理合成が行われるため、大きく時間がかかります。今回の例では十数分程度かかりました。
このため、今回は動作に至らなかったものの、エミュレーション段階でデバッグやカーネル関数の性能評価をしておくことが大切です。

合成後は、AssistantビューのHardware->binary_container_1を右クリックすると、Open Vivado Projectという項目から合成後のVivadoプロジェクトを開くことができます。
興味があれば見てみると面白いかもしれません。

次に、合成した回路をハードウェア上で実行します。
ここでは、エミュレーションと同様にRun -> Launch On Hardwareをそのまま押すと、ホスト上のLinux Agentが見つからないというエラーが出てテストが失敗します。
合成した回路をZybo上で動かすには、まずZybo上でLinuxを起動し、それに対してVitisからアタッチする必要があるようです。

Zybo上でLinuxを起動するには、FAT32でフォーマットしたSDカードを用意し、それに対してVitisの出力したSDカードイメージを書き込む必要があります。
このSDカードイメージにはAssitantビュー上のHardware -> binary_container_1 -> SD Card ImageからOpen In File Browserとすればアクセスできるので、ディレクトリ内のファイル全部をSDカードにコピーします。

上記SDをZyboに挿し、JP5のジャンパーピンをSDにして電源を起動すると、Linuxが立ち上がります。
Linuxに対しては、ZyboにUSBで接続したマシンからbaudrateを115200としてシリアルポートを開くことでアクセスできます。
正しく起動していれば以下の画面となりますので、User/Passwordをroot/rootでログインし、ifconfigでZyboのIPを調べておきます。

Zybo上のLinuxブートログ

ここまで作業したらVitisに戻り、Assistantビュー内のHardwareを右クリックし、Run -> Run Configuration とします。
左側のSingle Application Debugをダブルクリックすると、Debugger_vecadd-DefaultというConfigurationが作られるので、これに対して設定を行っていきます。
まずMainタブのConnectionの欄からNewをクリックし、Zyboへの接続を定義します。
Target Name をremoteとし、Hostに先ほど調べたZyboのIPを設定し、ポートはデフォルト値のままOKをクリックします。

次に、プロファイル用の設定を行います。
上の図では既に更新済みですが、Enable Profilingをチェックし、Generate timeline trace reportの値をYesとします。
次に、Collect Data Transfer SizeをFineとし、Collect Stall Trace をAllとします。
これらの設定は、合成前に行った設定とは異なり実行時の設定となり、xrt.iniというファイルに書き込まれます。
後はXRTが実行時にこの設定を読んでプロファイル結果を出力してくれるようです。

また、場合によっては、ここでRunを押した際に下のようなエラーが出ることがあります。

上記エラーは、下図に示すようにpetalinux内のrootfsの使用率が100%のため発生します。
実際のSDカードは十分空きがあるはずなので、/run/media/mmcblk0p1にマウントされているSDイメージを/mntにマウントしなおせば、とりあえず動作させる分には問題ありません。
おそらくpetalinuxビルド時の設定でこの辺は変わるとは思うのですが、正しい対処法は現在調査中です。

Runが成功すれば、VitisのConsole上にTEST PASSEDというログが表示され、AssistantビューのHardware -> Debugger_vecadd-Default 以下にRun Summaryというレポートファイルが出力されます。

最後に、Run Summary をダブルクリックし、Vitis Analyzer上で結果を確認してみましょう。
Vitis AnalyzerでProfile Summaryを表示した際のレポートが下図のようになります。
Host <-> Global Memory 間の転送プロファイル結果、カーネルの実行時間、カーネルのメモリアクセス効率などが表示されます。

Profile Summary: Top Operations

次に、Kernel & Compute Unitsのタブを見てみます。
上2つの情報からは今回は新しい情報は得られないのですが、ビルド時にStall Profilingをチェックしたため、一番下にStall Informationが表示されています。
これを見ると、118msの実行時間中、メモリ依存で36ms近くストールしていることが分かります。
高々100MHzのSIMD幅1のvecadd演算のため、メモリ帯域が問題になっているとは思えず、おそらくはメモリアクセスの発行が十分でなくレイテンシが見えているなど、何らかの問題があるのでしょう。
ここでAnalyzer上のRun Guidanceを見ると、今回はAXI-MMの幅が32bitのためもっと幅を増やすべきという情報があるため、こういったところを直していけばより性能が向上すると思われます。

Profile Summary: Kernel & Compute Units

最後に、Application Timeline からタイムラインを表示した結果が下図のようになります。
最初に述べた通り、VitisではOpenCLをホストコードに使用するため、OpenCL APIの呼び出し単位でタイムラインが作られます。
また、前述したようにカーネルのプロファイルもVitisはとっているので、図の下部に示すように、カーネル関数の実行時間も表示されています。
この図では、ホストスレッドがHost->Device転送・krnl_vadd実行・Device->Host転送のタスクを順にキューに追加した後clFinishで待ちに入り、その裏でドライバ・FPGAカーネルがメモリ転送・実行を行っていることが見て取れます。
現在は一つのカーネルのためそこまで得られる情報はないですが、FPGA内で複数のカーネルを実行し、それを制御するようなホストコードを書く際には、こういった可視化ツールでホストやデバイスの稼働率を見れると非常に助かりそうですね。

Application Timeline

今回は全部は表示しなかったのですが、Vitis Analyzerでは他にもデータ転送効率の詳細レポートなども出力できるので、必要に応じて使い分けるとよさそうです。

最後に個人的な見解を述べると、ある程度Vivadoでの開発フローに慣れた人が敢えてVitisでの開発を行うメリットは、こういったプロファイリングツールが充実している点だと感じました。
FPGA上で性能のプロファイリングを行うには、そのプロファイリングを行うための回路をFPGA上に実装したり、その結果を表示するためのソフトウェアを書いたりする必要があるので、それなりに手間がかかります。
一方で、Vitisではそういったプロファイリング機構が自動で埋め込まれる分、開発期間が短縮できる点がありがたいですね。

おわりに

本稿ではVitisを用いてSDSoC相当の高位合成を行いました。
最初のプラットフォーム定義こそ大変なものの、一度作ってしまえばソフトウェアを書くだけでFPGA上で回路を作成できるので、大分敷居は下がったと言えるのではないでしょうか。
また今回は行わなかったものの、プラットフォーム作成時にカメラやモニタへの入出力を定義しておけばFPGA上での画像処理など比較的面白い処理もできるはずなので、時間があれば触ってみたいですね。

Tags

About Author

yuki.matsuda

Leave a Comment

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Recent Comments

Social Media