2017年8月12日土曜日

TE0720 No.4 (BNN-PYNQを動かしてみる 2)

TE0720でBNN-PYNQを動かすことが出来た。
以下は前回に続いてBNN-PYNQが動くまでの記録。

gdb (GNU debugger)で例外が出る原因を調べてみた。
例外が発生しているのはシェアードライブラリ(python_hw-cnv-pynq.so)の中であり、これはpythonからダイナミックリンクされるのでpythonごと gdb で追えば何か判るのではないかと考えた。

run ./x.py としてx.pyスクリプトを実行させると、以下のようにSIGILLシグナルを受けて停止したが、かまわず cont と打って実行を継続させた。

すると、あのterminate called after throwing an instance of 'char const*'というメッセージが表示され、SIGABRTシグナルを受けてプログラムが停止した。ここでバックトレースを確認した。


関数FoldedMVInitの400行目で例外がthrowされているようだ。python_hw-cnv-pynq.soはデバッグ用の情報も付いているようなので、gdbを一旦終了しBNN-PYNQのソースファイルを/home/xilinx/test-newswg/下に展開してgdbを起動して上述と同じところまで操作した。
次に関数 FoldedMVInitをリスト表示し400行目付近を見てみた。

accelBuffer用の領域確保に失敗して例外を投げているようだ。そこで397行目にブレークポイントを設定してプログラムを再実行した。



accelBufInの確保も失敗してnullポインタが返ってきているようだ。
そこで、今度はallocAccelBuffer関数の中を追ってみることにした。

allocAccelBuffer内部では引数をcma_allocに渡してcma領域を確保していた。cma_allocはContiguous memory allocatorでカーネル内部に物理アドレスが連続したバッファを確保するための関数らしい。今の場合は30MB分の連続領域を確保しようとしている。ステップ実行したところ、cma_allocからnullポインタが返っていることが判った。

現在のOSのcma領域がどうなっているか確認したところ、そもそも全体でも16MB分の領域しかないことが判った。


そこで容量を128MBに増やしてみた。


増量して、cma_allocをコールする直前での空き容量を見ると70MBあるので今度は大丈夫の筈だが、ステップ実行してcma_allocからの戻り値を見るとnullポインタが返されていた。


そこで、今度はcma_allocの中を追ってみることにした。cma_allocのソースファイルは無いので、アセンブラレベルでのステップ実行になったが、その結果 ioctl コールでエラーが返っていることが判った。






現状のカーネルはpetalinuxのカーネルでバージョンは4.9.0なのだが、もしかしたらcma_allocのioctlコールの引数仕様がカーネル4.9.0で動作しているデバイスドライバの仕様と違っているのかも知れない。そこで、カーネルをPYNQのカーネルに代えてみることにしたのだが、カーネルのファイル名やファイル形式、デバイスツリーのファイル名等がpetalinuxとPYNQとでは異なっており、そのためにu-bootも変更することになってしまった。ところが、Xilinxのgitリポジトリからu-bootをcloneしてビルドして動かしてみたところ、mmcを認識しない。。。仕方がないのでZYBOのu-bootを使うことにした。


上記構成のSDカードにして起動し x.py を実行したところ例外は発生しなくなった。

PYNQのカーネルのバージョンは4.6.0だった。4.6.0と4.9.0ではcma_alloc関連の仕様が変わっているのかも知れない。また、4.9.0ではFPGAのコンフィグレーションのFPGA managerが追加になっているのでそれに関連してxdevcfgも変わっている可能性もある。。 ともあれ、例外が発生しなくなったのでjupyter notebookでCifar10.ipynbを実行してみた。


実行できた!!

で、推論をハードウェアで実行(PLにダウンロードして実行)した場合とソフトウェアのみで実行した場合との差は801108 / 3199 = 250倍となった。 ARMのシングルコアのみで実行するよりも推論部をPLにダウンロードしてハードで実行させると250倍高速に実行できた、ということだ。本物のPYNQボードだとどの位なんだろうか?





Road-Signs-Batch(道路標識の識別)も実行してみた。


こちらも実行できた。




カーネル 4.9.0でioctlがなぜsyscall エラーになるのかという点など、まだ頭の中に?マークがあるが、なんとか動くようになったので良かった。 ワーイ \(^_^)/


2017年8月6日日曜日

TE0720 No.3 (BNN-PYNQを動かしてみる)

今度は BNN-PYNQ をTE0720で動かせるかをやってみている。
BNNはBinarized Neural Network (BNN) (2値化ニューラルネットワーク)のことで、BNN-PYNQはPYNQ-Z1ボードのシステム向けのBNNの実装だ。PYNQ-Z1に搭載されているZynqデバイスはZYNQ XC7Z020-1CLG400C、TE0720のそれはXC7Z020-1CLG484Cであり、ピン数は異なるがコアは同じXC7Z020なので動くんじゃないかと考えた。そのためには、PYNQ用のLinuxシステムをTE0720で動かす必要がある。PYNQ-Z1のprecompiled image(pynq_z1_image_2017_02_10.zipPYNQのGitHubからダウンロードして中を見てみた。

pynq_z1_image_2017_02_10.imgはディスクまるごとのイメージでboot用パーティションとrootfs用のパーティションが入っている。そこで、それぞれのパーティションのイメージをddコマンドで抽出した。

必要なのはrootfsの方なので、これをcpioイメージに変換しておく。

前回のブログで作成したpetalinuxのSDカードのrootfsパーティションの内容を、抽出したPYNQのrootfsに書き換え、TE0720に装着して起動してみた。

起動してコマンドプロンプト表示まで行くのだが、キー入力を受け付けない。
現状、FPGAのPL部はTE0720のsampleデザインになっており、PYNQ-Z1ボードのそれとは異なる。起動時の処理で初期化か何かでPL部にアクセスをしていた場合は当然ハングアップする可能性は考えられる。ただし、BNN-PYNQはBNNの推論部をFPGA Overlaysの機能を使ってシステム起動後にFPGAにダウンロードして動かしているはずであり、起動時のPL部にはその回路は入っていないはずである。GitHubからPYNQのプロジェクトをダウンロードし、VivadoでBlock Designを見てみた。

Arduino sheild用の回路やHDMI、GPIO等の回路が入っているようだ。これらを起動時に初期設定しているのかも知れない。そこで、rootfsの/etc/rc 関係を見てみたところ rc.local にあった。

各シェルスクリプトの内容を確認した結果、4_boot_leds.shでPL部のGPIOを介してボード上のLEDのon/offをしていることが判った。そこで、rc.localの4_boot_leds.shの呼び出し部分をコメントアウトするように変更し、再度TE0720に装着して起動してみたところ、今度はキー入力も受け付けるようになった。

イーサネットも動作しておりDHCPでIPも取得できている。

そこで、開発PCのブラウザからTE0720のJupyter notebookのポートにアクセスしてみた。

アクセスできた。
そこで、次にBNN-PYNQのGitHubのQuickStartの記載内容に従って、BNN-PYNQをインストールした。

  sudo pip3.6 install git+https://github.com/Xilinx/BNN-PYNQ.git

すると、Jupyter notebookの項目にbnnが現れた。


Cifar10.ipynbを選択して実行してみた。

が、Jupyter notebookカーネルが死んでしまった。 orz

cell単位でステップ実行してみると、最初のcellでカーネルが死んでしまっていた。
overlayでPL部にダウンロードするBNN-PYNQのBlock DesignをVivadoで見ると以下のようであった。

これを見るとデバイス外部への入出力は無いので、TE0720でも動きそうな気がするのだが・・・
そこで、スクリプトをpyスクリプトとしてダウンロードし手動で実行してみた。


terminate called after throwing an instance of 'char const*'というメッセージが出て終了してしまっていた。念の為、最初のセルの内容だけのスクリプトを書いて実行してみた。

classifier = bnn.CnvClassifier('cifar10')でエラーになっているようだ。
そこから、/opt/python3.6/lib/python3.6/site-packages/にあるpynqディレクトリ下のスクリプトやbnnディレクトリ下のスクリプトを追ってみた。回路情報(bitファイル)の/dev/xdevcfgへの書き込みは成功しているようだが、その後のpython_hw-cnv-pynq.soというライブラリ内部で例外が発生しているようだ。ソースコードを見ると、このpython_hw-cnv-pynq.soはパラメータのダウンロードを行うライブラリのようだ。なぜここで例外になる??? うーむ……


TE0720 No.4 (BNN-PYNQを動かしてみる 2)

TE0720でBNN-PYNQを動かすことが出来た。 以下は前回に続いてBNN-PYNQが動くまでの記録。 gdb (GNU debugger)で例外が出る原因を調べてみた。 例外が発生しているのはシェアードライブラリ(python_hw-cnv-pynq.so)の中であ...