FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RISC-Vのランダムテストriscv-tortureの+signature

f:id:msyksphinz:20180909010643p:plain

RISC-V Tortureは、生成したテストパタンをシミュレータで実行し、最後にシグニチャを出力する。 シグニチャを他の実装(Rocket-Chipなど)との結果と比較して正しく実行できたかを判定している。

SpikeおよびRocket-Chipでシグニチャを生成するためには+signature=<filename>とすればよいというのは前回解析した。 次にこのシグニチャが具体的にどのような方法で生成されているのかについて調査する。

RISC-V Tortureのシグニチャは生成されたテストパタンのbegin_signatureend_signatureの間メモリの内容がダンプされている。 また、テストパタンの最後に`レジスタの値をすべて比較該メモリ領域にダンプすることでレジスタの中身を一致比較させるようになっている。 まあ、これだと計算の最後しか見ることができないな。。。

reg_dump:
        la x1, loop_count
        lw x2, 0(x1)
        addi x3, x2, -1
        sw x3, 0(x1)
        bnez x2, pseg_0
        la x1, xreg_output_data
        sd x0, 0(x1)
        sd x2, 16(x1)
        sd x3, 24(x1)
        sd x4, 32(x1)
        sd x5, 40(x1)
        sd x6, 48(x1)
        sd x7, 56(x1)
...

従って、同じような仕組みで自作RISC-Vシミュレータにもシグニチャを生成する仕組みを入れると、Spikeとのランダムテストの一致比較ができるはずだ。早速やってみよう。

  for (Addr_t addr = m_sig_addr_start; addr <= ((m_sig_addr_end-1) | 0xf); addr += 0x10) {
    for (Addr_t b_addr = addr + 0xf; b_addr >= addr; b_addr--) {
      UByte_t b_data;
      LoadMemory<UByte_t> (b_addr, &b_data);
      fprintf (fp, "%02x", b_data);
    }
    fprintf (fp, "\n");
  }

追加したものをテストしてみる。同じパタンで、Spikeの生成したtest.spike.sigと自作シミュレータで生成したシグニチャを比較する。

$ diff
$ diff test.forest.sig test.spike.sig
22c22
< d6bd427500000006ffffffffffff8008
---
> d6bd4275000000067ff8000000000000
26c26
< 7ff0000000000000ffffffffffff8008
---
> 7ff00000000000007ff8000000000000
29c29
< 0000000000000000ffffffffffffffff
---
> 00000000000000007ff8000000000000

ありゃ!差分がある。解析が必要だなあ。

RISC-Vのランダムテストriscv-tortureを試す

f:id:msyksphinz:20180909010643p:plain

RISC-Vの実装を作るとまずはテストパタンを生成してテストを流してみたくなるのだが、RISC-Vにはテスト用のパタンがいくつか用意されている。

RISC-V Tortureのダウンロードとインストール

RISC-V TortureのConfiguration

Tortureの生成パタンの構成を変えたいときは、config/*.configを変更するとよいらしい。

  • config/default.config
torture.generator.nseqs     200
torture.generator.memsize   1024
torture.generator.fprnd     0
torture.generator.amo       true
torture.generator.mul       true
torture.generator.divider   true
torture.generator.segment   true
torture.generator.loop      true
torture.generator.loop_size 64

torture.generator.mix.xmem    10
torture.generator.mix.xbranch 20
torture.generator.mix.xalu    50
torture.generator.mix.fgen    10
...

RISC-V Tortureのテスト生成

実際にテストを生成してみた。

$ make igentest
java -Xmx1G -Xss8M -XX:MaxPermSize=128M -jar sbt-launch.jar 'testrun/run'
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=128M; support was removed in 8.0
[info] Loading project definition from /home/masayuki/work/riscv-torture/project
[info] Set current project to torture (in build file:/home/masayuki/work/riscv-torture/)
[info] Running torture.testrun.TestRunner
Physical mode
running:List(spike, +signature=output/test.spike.sig, output/test)
running:List(spike, +signature=output/test.spike.sig, output/test)
///////////////////////////////////////////////////////
//  All signatures match for output/test
///////////////////////////////////////////////////////
[success] Total time: 1 s, completed 2018/09/06 10:18:52

テストの中身を見てみる。アセンブラで記述してあり、ランダムパタンの様相を呈している。

// random assembly code generated by RISC-V torture test generator
// nseqs = 200
// memsize = 1024

#include "riscv_test.h"

RVTEST_RV64UF
RVTEST_CODE_BEGIN

        j test_start

crash_backward:
        RVTEST_FAIL

test_start:

freg_init:
freg_s_init:
        la x1, freg_init_data
        flw f0, 0(x1)
        flw f2, 16(x1)
        flw f4, 32(x1)
        flw f10, 80(x1)
        flw f13, 104(x1)
        flw f15, 120(x1)
...

pseg_0:
        addi x18, x0, -1973
        addi x29, x0, 1316
        sraiw x4, x28, 24
        remw x6, x30, x30
        la x5, test_memory-184
        addiw x1, x30, 1106
        fmul.d f24, f9, f1
        slti x20, x10, 2037
        sll x24, x10, x27
        fmadd.d f5, f16, f9, f3
        mulh x26, x22, x22
...

outputディレクトリが生成されていた。

$ tree output/
output/
├── Makefile
├── test
├── test.S
├── test.spike.sig
└── test.stats

テスト結果の検証については、signatureのdiffを取ってチェックするらしい。

Rocket-Chip環境でtortureテストを実施する

Rocket-Chipのリポジトリにもtortureがサブリポジトリとして格納されているので、これを使ってみよう。

cd torture
make

Verilatorでの実行が失敗するので、Makefileを以下のように変更した。

index a85579f..8138c8b 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@

 SBT ?= java -Xmx1G -Xss8M -XX:MaxPermSize=128M -jar sbt-launch.jar
 RTL_CONFIG := DefaultConfig
-C_SIM := ../emulator/emulator-rocketchip-$(RTL_CONFIG)
+C_SIM := ../emulator/emulator-freechips.rocketchip.system-$(RTL_CONFIG)
 R_SIM := ../vsim/simv-rocketchip-$(RTL_CONFIG)
 TEST := output/test.S
 OPTIONS := $(empty)

実際にテストを実行してみる。Rocket-Chipにも+signature=filenameオプションが通じるらしい。

$ make ctest
java -Xmx1G -Xss8M -XX:MaxPermSize=128M -jar sbt-launch.jar 'testrun/run -c ../emulator/emulator-freechips.rocketchip.system-DefaultConfig -a output/test.S '
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=128M; support was removed in 8.0
[info] Loading project definition from /home/masayuki/work/rocket-chip/torture/project
[info] Set current project to torture (in build file:/home/masayuki/work/rocket-chip/torture/)
[info] Running torture.testrun.TestRunner -c ../emulator/emulator-freechips.rocketchip.system-DefaultConfig -a output/test.S
Physical mode
running:List(spike, +signature=output/test.spike.sig, output/test)
running:List(spike, +signature=output/test.spike.sig, output/test)
running:List(../emulator/emulator-freechips.rocketchip.system-DefaultConfig, +max-cycles=10000000, +signature=output/test.csim.sig, output/test)
This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.
Listening on port 46292
///////////////////////////////////////////////////////
//  All signatures match for output/test
///////////////////////////////////////////////////////
[success] Total time: 25 s, completed 2018/09/06 20:29:47

Nightly Testの実施

これはランダムテストを用いたリグレッションみたいなものかな?

一度に複数のテストも生成してリグレッションテストをすることができそうだ。

$ make cnight
...
[warn] there was one deprecation warning; re-run with -deprecation for details
[warn] one warning found
[info] Running torture.overnight.Overnight -c ../emulator/emulator-freechips.rocketchip.system-DefaultConfig -g none
Physical mode
running:List(spike, +signature=output/test_1536233603600.spike.sig, output/test_1536233603600)
running:List(spike, +signature=output/test_1536233603600.spike.sig, output/test_1536233603600)
running:List(../emulator/emulator-freechips.rocketchip.system-DefaultConfig, +max-cycles=10000000, +signature=output/test_1536233603600.csim.sig, output/test_1536233603600)
This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.
Listening on port 45600
///////////////////////////////////////////////////////
//  All signatures match for output/test_1536233603600
///////////////////////////////////////////////////////
Physical mode
running:List(spike, +signature=output/test_1536233629933.spike.sig, output/test_1536233629933)
running:List(spike, +signature=output/test_1536233629933.spike.sig, output/test_1536233629933)

NVDLAの内部構成調査(7. Caffeのモデルを使ってNVDLAでCIFAR10を動かす)

前回、NVDLA Virtual PlatformでMNISTを動作させることができた。同じように、NVDLAでCIFAR-10も動作させることができるはずだ。

PGMは1色の画像しか認識できないので、PGMでCIFAR-10の画像を渡すことはできない。そこで、JPEG形式でNVDLAにデータを渡して推論を実行することにした。

CIFAR-10の画像は、以下のサイトからPNG形式を取得し、ImageMagickを利用してJPEGに変換した。

pjreddie.com

$ for pgm in `ls -1 *.pgm`; do convert ${pgm} +compress conv_${pgm}; done

CaffeでのCIFAR-10の学習

こちらもExampleが用意されている。 fullモードで学習を行うと非常に時間がかかるので、Quickで学習を行った。

$ data/cifar10/get_cifar10.sh
$ examples/cifar10/create_cifar10.sh
$ examples/cifar10/train_quick.sh

これでCIFAR-10のCaffeのモデルが生成されるので、nvdla_compilerコンパイルしてNVDLA用のバイナリを作成する。

nvdla_compiler --prototxt ../cifar10/cifar10_full.prototxt --caffemodel ../cifar10/cifar10_quick_iter_4000.caffemodel

basic.nvdlaが生成されたので、NVDLAに渡して実行してみる。 以下はQEMU上で実行する。

# ./nvdla_runtime --loadable ../cifar10/basic.nvdla  --rawdump --image ../cifar10/0_cat.jpg
# cat output.dimg
0.00832367 0.000235677 0.00159931 0.0301514 0.00696945 0.122803 0.000342846 0.192383 0.623535 0.0136414 #

# ./nvdla_runtime --loadable ../cifar10/basic.nvdla  --rawdump --image ../cifar10/1_ship.jpg
# cat output.dimg
0.00250626 5.126e-06 9.77516e-06 0.00281715 0.000716209 0.00065136 1.01924e-05 0.00177479 0.991211 0.000142932 #

# ./nvdla_runtime --loadable ../cifar10/basic.nvdla  --rawdump --image ../cifar10/3_airplane.jpg &> /dev/null
# cat output.dimg
0.548828 0.000263214 0.00307655 0.0654297 0.00289726 0.00300217 0.000976562 0.0108719 0.364258 0.000113666 #

CIFAR-10は以下の順番でラベルが定義されている。

カテゴリ 番号
airplane 0
automobile 1
bird 2
cat 3
deer 4
dog 5
frog 6
hourse 7
ship 8
truck 9

0_cat.jpgは推論に失敗している(9番目が選択されている)。 1_ship.jpgは9番目が選択されており、認識成功だ。 3_airplane.jpgは0番目の数値が高く認識成功だ。

f:id:msyksphinz:20180908013303p:plain

NVDLAの内部構成調査(6. Caffeのモデルを使ってNVDLAでMNISTを動かす)

前回はNVDLAを使ってCaffeのモデルを実行してみた。 ただし実行結果が分からないので何とか解析できるようにしたい。

nvdla_runtimeの実行オプションには--rawdumpオプションがあるので、これを使えば実行後の結果をダンプできるらしい。

# ./nvdla_runtime --help
Usage: ./nvdla_runtime [-options] --loadable <loadable_file>
where options include:
    -h                    print this help message
    -s                    launch test in server mode
    --image <file>        input jpg/pgm file
    --normalize <value>   normalize value for input image
    --mean <value>        comma separated mean value for input image
    --rawdump             dump raw dimg data

実行後に、output.dimgを参照すると結果を見ることができる。

# ./nvdla_runtime --loadable ../lenet/basic.nvdla --rawdump --image ../lenet/digits/one.pgm
...
[33150.014288] reset engine done
Work Found!
Work Done
Shutdown signal received, exiting
Test pass
# cat output.dimg
1 0 0 0 0 0 0 0 0 0

結果を見てみるとone.bgmなので1の結果が出てほしいのだけれども、インデックス0、つまり1が判定されている。 one.bgmを参照すると、白黒逆転じゃない?NVDLAのGitHub Issueにも同じような話が出ていた。 本物のMNISTを使わないとだめだな。

MNISTのテストデータをBGMに変換する

MNISTのデータはバイナリで提供されているので、それをBGMに変換しなければならない。

MNISTのデータのダウンロードとBGMへの変換は、以下のサイトを参考にした。

qiita.com

これだけではテキストタイプのBGMなので、ImageMagickを使ってバイナリに変換する。

$ convert 0.pgm +compress conv_0.pgm
$ convert 1.pgm +compress conv_1.pgm
f:id:msyksphinz:20180906004538p:plain
図. conv_0.pgmの出力 (5の画像)
f:id:msyksphinz:20180906004719p:plain
図. conv_1.pgmの出力 (0の画像)

変換したBGMを使って、再度NVDLAを実行した。

# ./nvdla_runtime --loadable ../lenet/basic.nvdla --rawdump --image ../lenet/image/conv_0.pgm
...
# cat output.dimg
0 0 0 0 0 1 0 0 0 0 
#

conv_0.pgm(5の画像)については正しく認識できたようだ。次に、conv_1.pgm(0の画像)の認識に挑戦する。

# ./nvdla_runtime --loadable ../lenet/basic.nvdla --rawdump --image ../lenet/image/conv_1.pgm
...
# cat output.dimg
1 0 0 0 0 0 0 0 0 0
#

こちらも正しく認識できた。

f:id:msyksphinz:20180906005206p:plain

NVDLAの内部構成調査(5. NVDLA VPによるアプリケーション実行)

前回はCaffeをインストールして、LeNetを実行した結果をnvdla_compilerに食わせて、NVDLAのバイナリファイルを作成した。

これを実行するためには、NVDLA Virtual Platformを実行してLinuxを立ち上げ、そこでnvdlaを動作させるランタイムプログラムを実行しなければならない。

大まかな手順はNVDLAのウェブサイトに掲載されているが、いろいろとテクニックが必要だ。

NVDLA Virtual Platformの立ち上げ方はこちら。

msyksphinz.hatenablog.com

f:id:msyksphinz:20180904234315p:plain
図. NVDLA Virtual Platformの概要図 (http://nvdla.org/vp.html より抜粋)

Caffeのニューラルネットワークのモデルをロードして実行

QEMUにログインすると、まずはホストのディレクトリをマウントしてCaffeのモデルとランタイムプログラムを参照できるようにする。

# QEMUログインして実行
$ mount -t 9p -o trans=virtio r /mnt

QEMUを立ち上げた場所(おそらく高確率でvp)がマウントされるので、そこにファイルを集める。 Caffe で作成したbasic.nvdlaswリポジトリなどに格納されている画像ファイル(sw/regression/images/*.pgm)などをマウント領域に見えるようにコピーしてくる。

ドライバのロード

まずはドライバをロードする必要がある。sw/prebuilt/linux/をマウントしている場所に移って、以下を実行する。

$ insmod drm.ko
$ insmod opendla.ko

nvdla_runtimeを実行する

NVDLAを動かすためのフロントエンドはnvdla_runtimeだ。いろいろオプションを探して、lenetを実行した。

以下ではLeNetのモデルを入力し、入力画像として1の画像(one.pgm)を入力している。

# ./nvdla_runtime --loadable ../lenet/basic.nvdla --image ../lenet/digits/one.pgm
creating new runtime context...
Emulator starting
ppgminfo 1 28 28
pgm2dimg 1 28 28 1 32 896 896
submitting tasks...
[ 1429.133975] Enter:dla_read_network_config
[ 1429.134275] Exit:dla_read_network_config status=0
[ 1429.134504] Enter: dla_initiate_processors
[ 1429.134729] Enter: dla_submit_operation
[ 1429.134918] Prepare Convolution operation index 0 ROI 0 dep_count 1
[ 1429.135157] Enter: dla_prepare_operation
[ 1429.135409] processor:Convolution group:0, rdma_group:0 available
[ 1429.135706] Enter: dla_read_config
[ 1429.135976] Exit: dla_read_config
[ 1429.136147] Exit: dla_prepare_operation status=0
[ 1429.136336] Enter: dla_program_operation
[ 1429.136521] Program Convolution operation index 0 ROI 0 Group[0]
...
[ 1651.413376] Enter: dla_free_op_desc op desc index 10 ROI 0
[ 1651.413632] Exit: dla_free_op_desc
[ 1651.413793] Exit:dla_op_completion processor SDP group0 status=0
[ 1651.414039] Exit:dla_handle_events, ret:0
[ 1651.414210] Enter:dla_handle_events, processor:PDP
[ 1651.414417] Exit:dla_handle_events, ret:0
[ 1651.414603] Enter:dla_handle_events, processor:CDP
[ 1651.414791] Exit:dla_handle_events, ret:0
[ 1651.414971] Enter:dla_handle_events, processor:RUBIK
[ 1651.415184] Exit:dla_handle_events, ret:0
[ 1651.418539] reset engine done
Work Found!
Work Done
Shutdown signal received, exiting
Test pass

一応実行できたぞ。ただしメッセージも出てこないし、正しく推論できたかもわからない。 もう少しプログラムを改造して解析したいのと、NVDLAがどのように動いているのかを見ていきたい。

Design Solution Forum 2018にて発表します

去年よりも開催が1か月早くて焦っています。

2018/09/12(水)に開催されるDesign Solution Forumにて、RISC-V/IoTのトラックの1つとして発表させて頂くことになりました。

13:30~14:10 で、タイトルは "試しながら学ぶオープンソースプロセッサRISC-V の世界" としました。 なんか去年とタイトルが似てますね!つまりあまりしゃべることが無いんです。

仕事としてやってきたわけでもなく、仕事から帰ってきてクタクタになりながら更新していたブログなので、情報量としてはいまいちになるかもしれません。興味のある皆様よろしくお願いします。

f:id:msyksphinz:20180901131835p:plain

あと一週間なのにまだスライド全然できていなくて内容変わるかもしれないんですが、

  • RISC-Vの最新動向をまとめて解説。発表者がブログを通じて感じたRISC-Vのよもやま話
    • RISC-V Foundationは、どこへ向かおうとしているのか
    • どこで使われている?徐々に世界に浸透する”RISC-V”
    • RISC-Vの仕様を読みながら実装を作って、RISC-Vの光と闇を覗いてみる
    • RISC-Vを通じて変わる「ハードウェア設計の常識」

っていうか、お隣のセッションでポスト京やってるので集客は期待しておりません。。。静かに気づかれないよう発表したいところ。

という訳で、「ポスト京なんかどうでもいいからRISC-Vの話を聞きたい」とか、「ポスト京についての情報も気になるけどRISC-Vの冷やかしをしたい」っていう方は聴講お待ちしております。

お手柔らかにお願いします。

RISC-Vを使ったEnclaveプロジェクトKeystone

f:id:msyksphinz:20180904021652p:plain

限りなく内容の無い、メモのような日記になってしまったが。。。

RISC-Vアーキテクチャを使ったセキュリティ技術の開発で、Keystoneというプロジェクトがあるらしい。 Hisa Ando氏の記事で知った。

    1. KeystoneでRISC-Vをセキュア化

20180901

  • Keystone Open-source Secure Hardware Enclave

keystone-enclave.org

ちょうどIntel SGXのEnclaveについて知識もついてきたところだし、論文も公開されているので読んでみようかな。