MPDとRustとRaspberryPiで遊んでみる9 飛騨茉莉

え~、今日はネタは二つ

まず、MPDのフロントエンドを作ろうというプロジェクト『飛騨茉莉』ですが、なんか進んだり戻ったりしています。

というのも、RPi3 でさぁ動かそうと思って、RPi3 で $ cargo run としたら、なんと初回ビルドに10数分かかる! おっそい。遅すぎるぞぉ~

しかも動き出したら、今度は結構CPUをもっていってしまう。だいたい CPU使用率 80% くらい。ちょっと重すぎる。ロードアベレージ的には 1未満だけど、いくら何でもなぁ。 相方の mpd サンは、10% 未満で動いているのでかなり差がある。うーん。

FFT やっているので多少は CPU使うだろうとは思っていたのですが、それほど使うとなるとちょっと開発コンセプトをミスったかしらと思ってしまいました。

Rust って、そんなに重いのか? 作りが悪いのか? 止めるか?

で、 もうちょっとカリカリにしたいと思ったとき、actix-web はなんか触りにくい。tokio ランタイムとの関係性が分かりにくいことと、actix のコンセプトが色々なものを隠していることが気に入らない。actix-web をやめてもちょっとシンプルなフレームワークを使おう。なんて考えが沸々とわいてきまして、こりゃもーやるしかないと...

で、actix-web 捨てて、別のwebサーバーフレームワークにしました。ははは。

wrap というのを知りまして、下層の hyperに対して比較的薄いかぶせ具合のライブラリとなっています。また wrap も hyper も tokio ランタイムを変に被せず普通に使っているので、hyper と tokio の ドキュメントやサンプルがそのまま使えます。なんかよさそう。

結構それなりにまで動くようになった状態だったのですが、一気にぶっ壊して、wrap で建て直しました。いやぁ大変でした。

やっぱりフレームワークというのは、それなりに実装方法を強制してくるわけですので、ほとんど似たよーな事をするにしても全然違うコードが必要となります。あっちではこーなのに、こっちではあーだ。の連続。またそれぞれの個性みたいなものに合わせる必要があるわけで旧来のコードではダメ部分は総とっかえです。

ただ先ほどの言ったように、最下層となる tokio ランタイムがそのまま使えるのは大きかったです。async/await 絡みの部分に対する理解も深まりましたし、実装もいい感じになりました。actix-web を使っていたころよりもコードがシンプルで分かりやすく自由度も高い感じです。websocket もちゃんと行けました。

プロダクト自体もだいたい元の動作が全部動くようになり、ほっと一安心。何とかなってよかった。

しかし、プログラム効率が多少良くなったりしたところで、負荷がそんなに変わるもんでもありません。相変わらず重いわけです。とほほ

RPi3 ってそんなに非力なのか.... RPi4 にすべきか...

などと思ってたのですが、母艦の CentOS8 で開発しているときもちょっと思ってたのですが、Rustで作ったものってよそ様で宣伝されているほど早く無い感じがずーっとしてたんです。なんとなくもちょっとキビキビと動いてほしいのに、スクリプト系で作ったもの見たいに、もっさり感があったんです。CentOS8 でうごかすと、CPU使用率10%ちょっと割るくらいで動くんですが、それでもなんかちょっと高いなぁと...

そこで何気に、リリースビルドを作って動かしてみたんです。

top コマンド使いながら、多少は CPU使用率下がるのかなぁと眺めてました。

ん?でてこん。動いてないのかな?普段なら一番上にくるのになぁ....。いや動いてるぞ。あれ?

そうです。CPU使用率が一気に 1% 未満になったのです。えぇぇぇ~。ちょー軽くなりました。

なんだそれはと思い、armv7 用のリリースビルドをこさえて、RPi3 にもっていってみました。で動かすと、CPU使用率が 5 ~ 12% 位に収まります。相方の mpd サンより、ちょっと重いくらい。ロードアベレージも十分低いです。やった!これならいける!

でも、なんかちょっと rust に振り回された感があったのでちゃんとテストしてみました。(これが二つ目のネタです)

github.com

適当な重い処理として FFTを実行してCPUを使うようなプログラムを作ってみました。でこれ自体のコンパイル時間と、これの実行速度を、デバッグビルト・リリースビルド別に計測してみました。また母艦と RPi3 とでも比べてみました。

母艦と RPi3 の性能差も、8~10倍くらい違ってました。んまぁこれはそんなもんかなとは思っていましたので全然不思議じゃなかったです。

ですが、リリースビルドは、デバッグビルトの10倍以上のスピードで動きます。なにそれ!差がありすぎじゃない? C/C++ とかだと、1.5 ~3倍くらいしか差がなかったよーな気がしてたのです。この認識が間違ってるのかもしれませんが、 10倍ってかなりショックでした。

というより、今までほとんど ログデバッグで済ませててデバッガとか使ったりしてなかったので、デバッグビルトである必要がほとんどなかったわけです。というより、mpd の fifo 食べて FFT してブラウザにデータ送るって処理の部分は音楽の再生に合わせた動作となるので、デバッガで止めながらやるってわけにもいかないですからねぇ。どーしてもってならデバッガ使おうと思ってたんですが、いまんところそこまでではなかったわけです。こんなことならば、最初っから リリースビルドつかってればよかった!

ちなみに、ビルド速度に関しては、デバッグビルトに対してリリースビルドは、おおよそ 1.5倍の時間がかかります。ただ普段はcargo clean なんてしないので作業時間にはそこまで影響しないです。cargo check が爆速なのでコード中は、cargo checkだけで進めてビルドを行わないようにするスタイルになってきているのでなおさらです。cargo watchも使ってますよ。

そもそも、10倍も処理スピード違うと、デバッグビルトの意味が薄くなりそーですよね。(そーいうもんなのかなぁ?)

んまぁ、あらためて Rust のそういうところ勉強させてもらったわけですが、はぁぁぁ。疲れるぅ。

『飛騨茉莉』開発に関しては、あと2つほど山があって、まだまだ疲れそーです。

  • Bluethooth 入力を手作業でやってみたんです。bluez と bluealsa と mpd の組み合わせです。うまく鳴るのですが、bluez側でコネクションを切ると、mpdがコアダンプするんです。たぶん携帯側から Bluethooth 切断しても、同じようにおっこっちゃいそーだなぁ...(まだ試してない)
  • Bluethooth 出力ですが、Moodeさんはかなり強引な方法でやっているよーです。mpdの設定ファイル書き換えて mpd リブートしてます。outputデバイスを動的に追加する方法が無いので、それしか方法なさそうですが...
  • RPi3 の mpd で 結構音飛びする mp3 ファイルがあります。自前で入れた Raspbian と Mooreさんでちゃんと比較したわけでは無いのですが、音飛びはちょっとなぁ...

課題をメモしてみました。なんか大変そうだぁ。