OpenCVが…RISC-Vと…出会ったぁ…（ただし通り過ぎていく）

#はじめに
この記事は[OpenCV Advent Calendar 2018](https://qiita.com/advent-calendar/2018/opencv)の5日目の記事です．
他の記事は[目次](https://qiita.com/advent-calendar/2018/opencv)にまとめられています．
なお、本記事は筆者個人の意見であり、筆者の所属組織とは無関係です。

# この話のオチ

**OpenCV on RISC-V いけます！！** (2018/12/2 確認)

# RISC-Vとは？
オープンな命令セットを共有することで、ソフトウェアの互換性が高まる！！という夢に基づいたもの。

https://ja.wikipedia.org/wiki/RISC-V

- PCから組み込みまで、幅広く使わえる（かもしれない）
- 現状の「Intel/AMD」「ARM」に対する、第三の選択肢になる（かもしれない）。
- 独自に命令拡張したりすることも可能である。

~~SHとか78とかマイコン世界が楽しいとか言ってはいけない~~

# RISC-V エミュレータ環境構築
ではまず、エミュレータを動かすところから。

こちらをベースに作業をしました。
http://msyksphinz.hatenablog.com/entry/2018/09/24/040000

2018/12/1 現在、Ubutntu 18.04 をベースに作業をしました。

## ①ISSUE1: e2fsprogのコンパイル時に「名前衝突」で怒られ、失敗。
./output/build/host-e2fsprogs1.43.1/misc/create_inode.c

copy_file_range() が名前重複で引っかかる。
staticな関数だったため、_copy_file_range() に変更して問題回避。

## ②ISSUE2: automakeの変換部分で引っかかる。
Perlのバージョンでそのままだと、うまくいかないことがあるらしい。
下記内容を見て、修正。

buildroot-riscv-2018-09-22/output/host/usr/bin/automake
L3936
https://github.com/raspberrypi/noobs/issues/470

## ③ISSUE3: ワークディスクがない
このまま環境を用意すると、ディスクが少なすぎて何かするのも大変なので、qemuでディスクを作り、cfgに追加。

```
 [HOST] $ qemu-img create -f raw raw.img 4G
 [HOST] $ mkfs.ext3 raw.img
```

``` 設定ファイル(root-riscv64.cfg)
/* VM configuration file */
{
    version: 1,
    machine: "riscv64",
    memory_size: 512,
    bios: "bbl64.bin",
    cmdline: "console=hvc0 root=/dev/vda rw",
    drive0: { file: "../buildroot-riscv-2018-09-22/output/images/rootfs.ext2" },
    drive1: { file: "./raw.img" },
    eth0: { driver: "user" },
}
```
増設した方のディスクは、/dev/vdb として認識される。
なお、めんどくさがってパーティションも切らない悪い子です。

# RISC-V エミュレータ(temu)を動かしてみよう

```start.sh
../temu-2018-09-15/temu root-riscv64.cfg -m 512 -rw
```

temuを止めるには、C-a x (QEmuと同じ）　＜－　重要

# クロスコンパイルを動かそう(ｺﾞｺﾞｺﾞｺﾞｺﾞ
## クロスコンパイル用の設定ファイル

はーい、ここではあらかじめ用意したこちらを以下略。

https://raw.githubusercontent.com/Kumataro/opencv/master/platforms/linux/riscv.toolchain.cmake
https://raw.githubusercontent.com/Kumataro/opencv/master/platforms/linux/riscv64-gnu.toolchain.cmake

FLOAT_ABIほにゃららの残骸が残ってた…　ｷﾆｼﾅｲ

## パスを通す

```
[HOST] export PATH="${PATH}:~/workRiscV/buildroot-riscv-2018-09-22/output/host/usr/bin/"
```

## コンパイルする

```
 [HOST] mkdir build && cd build 
 [HOST] cmake -DCMAKE_TOOLCHAIN_FILE=../platforms/linux/riscv.tootlchain.cmake  ..
 [HOST] cmake-gui ../ ← ここで不要そうなパッケージ外しまくる
 [HOST] make -j8
 [HOST] make install  ← これをやると成果物が、build/install にまとまる。
``` 

## 動かしてみる
OpenCVのコンパイル成果物他を、tmpにコピーして持ち出す。
(libstdとかなんでやる必要があるのかわからないけど、とりあえずエラーになるので対策してみた。)

```
 [HOST] $ sudo -s
 [HOST] % mkdir tmp
 [HOST] % mount raw.img tmp
 [HOST] % rsync -avz ../../../opencv-4.0.0/build/install tmp/opencv
 [HOST] % umouont tmp

 [TARGET] $ mount /dev/vdb /mnt
 [TARGET] $ LD_PRELOAD=../lib/libopencv_core.so.4.0:/usr/lib/libstdc++.so.6:/usr/lib/libgcc_s.so.1 ./opencv_version
```

実行画面がこちら。cpuinfoがよくわからない！！（正しい）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/6c4b2643-ad67-f189-1d8c-be4f19847bf0.png)


そして、生成物のライブラリをobjdump してみた……　うん！！！わからん！！（正しい）

```
 0000000000066b76 <_ZN2cv3hal12cvtGraytoBGREPKhmPhmiiii>:
   66b76:       7169                    addi    sp,sp,-304
   66b78:       e64e                    sd      s3,264(sp)
   66b7a:       01810993                addi    s3,sp,24
   66b7e:       f9da                    sd      s6,240(sp)
   66b80:       f5de                    sd      s7,232(sp)
   66b82:       8b2e                    mv      s6,a1
   66b84:       8baa                    mv      s7,a0
   66b86:       00174597                auipc   a1,0x174
   66b8a:       0d258593                addi    a1,a1,210 # 1dac58 <_ZZN2cv3hal12cvtGraytoBGREPKhmPhmiiiiE26__cv_trace_location_fn1447>
```

#画像も扱おう
## 実行ファイルを作る

クロスコンパイル環境でのやり方になれていないので、力技使いまくりです。

```a.cpp
#include <stdio.h>
#include <opencv2/opencv.hpp>

int main()
{
	cv::Mat mat;
	mat = cv::imread("lena.jpg");
	cv::putText(mat, "OpenCV meets RISC-V", cv::Point(50,50), 
		cv::FONT_HERSHEY_SIMPLEX,
		1.2, cv::Scalar(255,255,255), 2 );
	cv::imwrite("lena_hello.jpg", mat);
	return 0;
}
```

ここまではまだよい。

```makefile
~/workRiscV/buildroot-riscv-2018-09-22/output/host/usr/bin/riscv64-linux-g++  a.cpp -o a.out \
	-I../opencv-4.0.0/build4/install/include/opencv4 \
	-L../opencv-4.0.0/build4/install/lib \
	-lrt -lm -lpthread -ldl \
	-lopencv_core \
	-lopencv_imgcodecs \
	-lopencv_imgproc 
```

これで作ったa.out を、raw.img経由で、temu環境に持ち出す。

## 動かしてみる

が、ld関係がなんかうまく作れなかったので「力づく」でねじ伏せる（良い子は絶対にまねしてはならない）

```exe.sh
[TARGET] LD_PRELOAD=./opencv/lib/libopencv_calib3d.so:./opencv/lib/libopencv_core.so:./opencv/lib/libopencv_dnn.so:./opencv/lib/libopencv_features2d.so:./opencv/lib/libopencv_flann.so:./opencv/lib/libopencv_gapi.so:./opencv/lib/libopencv_highgui.so:./opencv/lib/libopencv_imgcodecs.so:./opencv/lib/libopencv_imgproc.so:./opencv/lib/libopencv_ml.so:./opencv/lib/libopencv_objdetect.so:./opencv/lib/libopencv_photo.so:./opencv/lib/libopencv_stitching.so:./opencv/lib/libopencv_video.so:./opencv/lib/libopencv_videoio.so::/usr/lib/libstdc++.so.6:/usr/lib/libgcc_s.so.1 ./app/a.out
```

### 実行結果
RISC-V上でOpenCVモジュールを使い、
- ①JPG画像をMatに展開し、
- ②文字描画コマンドを介して画素にアクセスし、
- ③MatをJPEG画像に保存できる、
ことができました！！お疲れ様でございました！！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/15b9c60f-1f5e-7c3f-926a-07fc1e226ef1.png)

### 速度は…

まあ、Soft Emulationだし遅いのは今の時点では仕方がない…。(core i7 4770上のtemu上で測定)

```
[root@localhost mnt]# time sh exe.sh 
real	0m 3.03s
user	0m 2.79s
sys	0m 0.22s
```

# まとめ
## OpenCVは、RISC-V上でも動かせる！
**OpenCV on RISC-V いけます！！** (2018/12/2 確認)
ただし、性能検証や精度検証するには、ハードが欲しい。

## 今後の展望(OpenCV on RISC-V)
### risc-vの多様な構成をどう扱うのか。

もう一度、このcpuinfoをご覧ください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/6c4b2643-ad67-f189-1d8c-be4f19847bf0.png)

https://www.aps-web.jp/academy/risc-v/02/
https://en.wikipedia.org/wiki/RISC-V によると

rv64acdfimsu というのは、

| 文字列 | 意味 |
|:-:|:-:|
| 64i | Base Integer Instruction Set, 64-bit  |
| a | Atomic拡張  |
| c | 16bit短縮命令  |
| d | 倍精度浮動小数点  |
| f | 単精度浮動小数点  |
| m | 乗除算命令  |
| s | スーパーバイザモード  |
| u | ？ |

さて、となると「倍精度浮動小数」やら「単精度浮動小数」の扱いや、更には「４倍精度浮動小数点」の扱いなんかも考えないといけないということですね。

組込目的だけであれば、もちろん固定のプロファイルでよいのですが…というのが少し悩ましい感じです。


### risc-v対応SIMD検討
RISC-VにもSIMDの仕組みはある、のだからやらないと性能が十分に発揮できない、ということになってしまいますね。

https://content.riscv.org/wp-content/uploads/2017/12/Wed-1330-RISCVRogerEspasaVEXT-v4.pdf

### そして、128bit CPUへ・・・
そして128bitにも対応しています。
これは、まず、まともに動くのか、というレベルの検討からですね・・・

## はーい、明日の予告は
明日は @fukushima1981 さんの記事で，タイトルは「リアルタイム画像処理のための動体視力を求めない」となっています．もう私もおじいちゃんなので、うれしい記事ですね、きっと！！！

## 設定ファイル

今回の試作は以下の設定になりました。

``` version_string.tmp
General configuration for OpenCV 4.0.0 =====================================
  Version control:               unknown

  Platform:
    Timestamp:                   2018-12-02T02:09:41Z
    Host:                        Linux 4.15.0-39-generic x86_64
    Target:                      Linux 1 riscv64
    CMake:                       3.10.2
    CMake generator:             Unix Makefiles
    CMake build tool:            /usr/bin/make
    Configuration:               Release

  CPU/HW features:
    Baseline:
      requested:                 DETECT

  C/C++:
    Built as dynamic libs?:      YES
    C++ Compiler:                /home/kumataro/workRiscV/buildroot-riscv-2018-09-22/output/host/usr/bin/riscv64-linux-g++  (ver 7.3.0)
    C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
    C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
    C Compiler:                  /home/kumataro/workRiscV/buildroot-riscv-2018-09-22/output/host/usr/bin/riscv64-linux-gcc
    C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
    C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
    Linker flags (Release):      
    Linker flags (Debug):        
    ccache:                      NO
    Precompiled headers:         NO
    Extra dependencies:          dl m pthread rt
    3rdparty dependencies:

  OpenCV modules:
    To be built:                 calib3d core dnn features2d flann gapi highgui imgcodecs imgproc java_bindings_generator ml objdetect photo python_bindings_generator stitching ts video videoio
    Disabled:                    world
    Disabled by dependency:      -
    Unavailable:                 java js python2 python3
    Applications:                tests perf_tests examples apps
    Documentation:               NO
    Non-free algorithms:         NO

  GUI: 

  Media I/O: 
    ZLib:                        build (ver 1.2.11)
    JPEG:                        build-libjpeg-turbo (ver 1.5.3-62)
    WEBP:                        build (ver encoder: 0x020e)
    PNG:                         build (ver 1.6.35)
    TIFF:                        build (ver 42 - 4.0.9)
    JPEG 2000:                   build (ver 1.900.1)
    OpenEXR:                     build (ver 1.7.1)
    HDR:                         YES
    SUNRASTER:                   YES
    PXM:                         YES
    PFM:                         YES

  Video I/O:
    DC1394:                      NO

  Parallel framework:            pthreads

  Trace:                         YES (built-in)

  Other third-party libraries:
    Custom HAL:                  NO
    Protobuf:                    build (3.5.1)

  Python (for build):            /usr/bin/python2.7

  Install to:                    /home/kumataro/workRiscV/opencv-4.0.0/build4/install
-----------------------------------------------------------------
```

## 今後の展望（個人）
春先に画像処理と関係ないお仕事にふっとばれされてしまいましてね……。

今年はプライベートでもOpenCV触ってない事もあり、今年はOpenCVのAdvent Calenderに参加するか悩んだのですが、とりあえずえいやで参加する事にいたしました。内容が薄くて、非常に申し訳ありません。

あと、転職したい（真顔）。しかし、四十肩になってしまい辛い（超絶真顔）。