librealsense2にARM NEONを実装してみた

過去にX（Twitter）で下記のようなやりとりがありました
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">librealsenseにx86_64アーキテクチャ向けのSIMD実装はありますがaarch64向けのNEON実装はない（Intel的に開発プライオリティが低いのはそれはそう）ので最適化の余地ありそうです。 <a href="https://t.co/aCwz49wV25">https://t.co/aCwz49wV25</a></p>&mdash; dandelion (@dandelion1124) <a href="https://twitter.com/dandelion1124/status/1743257677604765961?ref_src=twsrc%5Etfw">January 5, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

簡単に説明すると、IntelやAMDのCPUが乗っているマシンに比べて、ラズパイ等のArm CPUのマシンではRealSenseの動作がとても重いということらしいです。

SIMD聞いたことあるけどよくわからんなぁという感じでしたが、仕事でSIMD使いそうだったのでお勉強を兼ねて実装してみることにしました。

ArmのSIMDことNEONの技術的な内容は下記ページをかなり参考にさせていただきました
- https://arm-software.github.io/acle/neon_intrinsics/advsimd.html
- https://www.docswell.com/s/fixstars/KENEQJ-20210805
- https://qiita.com/advent-calendar/2020/neon-only

すでにx86_64向けのSIMD実装はあるのでそれを参考に、何を実装すべきか洗い出したところ下記の処理を実装すればよさそうということがわかりました。
- 画像フォーマットの変換処理
- Depth画像から点群データに変換する処理
- 画像の視点を変換する処理

実装の具体的な内容はここでは割愛します（気になる方はソースコード読んでみてください）。
大きなリポジトリにプルリク送るの初めてだし、外国の人とやりとりするのも緊張しましたが、DeepL駆使してなんとかやり取りできました。多少変な英語でもなんとかなります。

そして最近、ベータ版ですがNEON実装がリリースされたので、どれくらいCPU負荷を下げることができたのかテストします。

実装時の動作確認にはOrangePi5というSBC使っていましたが、持っている人は少ないと思いますので、Raspberry Pi 5で改めて動作テストです。

### 動作確認環境
- PC: Raspberry Pi 5 (8GB)
- OS: Raspberry Pi OS 64bit 2024-11-19
- RealSense D435i
- librealsense `development`ブランチ
    - コミット: `01ac7862f422449967f3bfc3eec600375825761c`
    - `v2.56.3`以降のバージョンでNEON対応しているはずですが、うまくビルドが通らなかったので`development`ブランチで作業します

### librealsense2のビルド手順

```bash
# 依存関係のインストール
sudo apt update & sudo apt upgrade
sudo apt install libssl-dev libusb-1.0-0-dev libudev-dev pkg-config libgtk-3-dev cmake
sudo apt install libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev at

# ソースコードの取得
git clone https://github.com/IntelRealSense/librealsense
cd librealsense
git checkout 01ac7862f422449967f3bfc3eec600375825761c

# udevの設定
./scripts/setup_udev_rules.sh

mkdir build
cd build

# ビルド設定
cmake -D FORCE_RSUSB_BACKEND=ON \
      -D BUILD_WITH_OPENMP=ON \
      -D BUILD_EXAMPLES=ON \
      -D BUILD_GRAPHICAL_EXAMPLES=ON \
      -D CMAKE_BUILD_TYPE=Release \
      ..

# ビルド～インストール
make -j 4
sudo make install
```

### realsense-viewerで動作確認
- デフォルト設定（解像度848x480 30FPS）のままですが、起動～点群の表示まで問題なく動作しました
- topコマンドでCPU使用率を確認したところ、100%を切っています（後述の`OMP_NUM_THREADS`は未設定）
- これ以上解像度を上げる場合、OPEN_MPのスレッド設定をしてあげる必要がありそうです
```bash
# スレッド数を指定 (指定しなくてもよい)
# export OMP_NUM_THREADS=4

# 起動
realsense-viewer
```
- ![WIN_20241221_23_31_46_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270599/21c23c6b-d655-c0b8-5cae-4e571029e738.jpeg)

### NEON実装の入っていないバージョンとCPU使用率を比較
NEON実装の入っていない少し前のバージョン`v2.54.2`とCPU使用率を比較します
色付き点群の表示時の設定で比較します

- 設定
  - スレッド数: 4 (`export OMP_NUM_THREADS=4`)
  - 解像度: 848x480 30FPS

- v2.54.2 CPU使用率=約210%
  - ![WIN_20241222_00_44_04_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270599/e9c386c4-51d1-fac9-811b-02e70243bc9a.jpeg)

- NEON実装あり CPU使用率=約120%
  - ![WIN_20241222_00_45_32_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270599/4bdaf9cd-197c-fc14-3134-9ae6542dd804.jpeg)

NEON実装のありなしで比べると、CPU使用率を約4割削減できています
また、NEON実装ありの数値が100%を超えているのは、マルチスレッド動作させているオーバーヘッドによるものと思われます
（よくみるとdevelopment版でIMUが認識していない。。。）

### まとめ
- Raspberry Pi + RealSenseの組み合わせでなにかやろうとしていたけど、CPU負荷高すぎて使えないという人も多かったのではないでしょうか
- まだベータ版にしかNEON実装は入っていませんが使ってみたい方はお試しいただければと思います