2021年1月第1週レポート
あけましておめでとうございます。年末年始の休み期間はRustで遊んでいました。
インプット
📝 「Rustにおけるパフォーマンスの落とし穴」の記事を読んだ
事の発端はNESエミュレータの開発で、1フレームの描画に20msくらいかかっていた(60FPS = 16.666..ms/frameなのでかなり遅い)ので、そのボトルネックを探すために調査しました。
結局は参考記事の頭に書いてあるとおり、Releaseビルドに変更したところ4.5ms/frameほど速度が出るようになりました。(ものすごい見落とし…)
ただ、その他の節についても参考になるもので、知っておいて損はない内容だと思います。
📝 Rustの言語仕様を調べた
以前読んだ書籍では以下の内容について詳細を把握できなかったので、その他のソースを使って調べました。
- 所有権システム
- トレイト
- スマートポインタ
主に活用した情報ソースは以下の通りです。
特に所有権システムとスマートポインタの知識はNESエミュレータの開発に活かすことができました。
アウトプット
🛠️ Rustのライフタイム注釈について調べた結果を記事にした
個人的にまとめていたライフタイム注釈のメモを公開しました。
The Rust Programming Langurageがベースですが、その他のソースを参照しながら自分なりにまとめました。ライフタイム注釈がどうして必要なのか理解することができたのでまとめてよかったと思います。
🛠️ RustでNESエミュレータを作っている
ハローワールドまで到達しました。
なおしたw #NES pic.twitter.com/v7Tdb7lUyU
— d_yama (@dy_karous) January 1, 2021
ちょっと失敗もしましたが。
RustでNES、ハローワールドできたと思ったら微妙に間違っているw #NES pic.twitter.com/cCFEiWY88C
— d_yama (@dy_karous) January 1, 2021
今回フル活用したのはRustのスマートポインタまわりの知識です。NESは演算周りを担うCPUの他に描画周りを担うPPU(Picture Processiong Unit)というコンポーネントを持っています。このPPUにはCPUの3倍のクロックが入力されています。また、CPUからPPUのレジスタに読み書きすることもできます。なので、NESはPPUへの参照を持ち(クロックに応じてPPUを動かす)、またCPUもPPUへの参照を持つ(PPUレジスタへの書き込み)ようなモデルとなります。
このモデルだとNESはPPUの可変の参照を持ち(PPUの内部状態を変化させるようなメソッドをNESは実行できる)、またCPUもPPUに対する可変の参照を持つ(PPUのレジスタ状態を変化させるようなメソッドをCPUは実行できる)ことになり、Rustの所有権システムとはちょっと相性が悪いです。そこで活用できたのがRc型とRefCell型を使った、俗に言うRc-RefCellパターンですね。NESもCPUもPPUに対して所有権を持ち、PPUの可変の参照を使いたい場合はRefCell型から可変の参照を取得する、という実装にしました。RefCellは借用規則をコンパイル時にではなくランタイム時に評価する仕組みを提供する型です。コンパイル前にチェックできず実行時にパニックを起こす可能性があるので使い方を誤ると危険なのですが、今回はCPUで命令を実行したあとにPPUを動かすというシーケンシャルな実装にしているのでまあ問題ないでしょう。
リポジトリも公開しました。