5.分割読み込みの高速化
動画プレイヤー的動作をさせるときは、マルチコアでデコード中に次のファイルを読み込んでいた。時間のかかるSD読み込みに専念させているのでスピードが速い。
大きなファイルの分割読み込みでもマルチコアを使ってデコードしているが、デコーダから要求があってからファイルを読み込んでいるのでスピードが落ちてしまう。
なのでバッファを2面持って、1面目にファイル先頭からのデータを4kBとかを読み込んで、それを処理しているすきに、2面目に続きを読み込む感じで実装してみよう。
と、バッファの管理方法を考えていて気が付いたんだが、アドレスが毎回変わるのは不便だということ。read()を使ってるので、ファイル読むたびにバッファを新規に確保してるんでアドレスが毎回変わる。
あれ?でも変だな。read()で毎回変化するってことは、ファイルシステムにアクセスするOS部分も不便なはずでは?
調べてみると read() じゃなくて readinto() というメソッドがあり、これだと呼ぶ側が確保したメモリに読み込めるようだ。というかそれが普通のやり方っぽい。
クリティカルヒット。とーふは首をはねられた。
pythonで遊んでて半年も存在を知らなかった。ついでに、メモリ(bytearray)を確保して、その一部をmemoryviewで切り出してアクセスする方法が基本らしい。
クラスの初期化時にまとめてメモリを確保すれば gc の動作を減らすこともできるようだ。勉強になったなぁ(苦笑)
ともあれ、バッファを2面分確保して、デコード処理中に別の面へファイル読む処理を組み込んだ。デコーダはバッファを確認し、データが格納されていれば勝手に使い、無ければcore0へ要求を出す仕様。そして実行したところ、全然性能が向上していないという事実。むしろ遅いまである。あれ?
ファイル読み込み要求のアドレスとサイズをチェックしてみると、JPEGデータの内部構造に由来するのかデコーダは1.6kB ぐらい毎にファイル要求をしている。ファイルポインタの値は、バッファに読み込み済の領域なので二重に読み込んでる。あるぇ?
どうやらJPEGデータは圧縮したMCU単位で処理するからファイルバッファのサイズとは一致していない。デコード処理中のバッファチェックの際、バッファの最後の部分はMCUデータが途切れていることになるので、バッファは無効と判定する。先読みしたバッファを確認すると、こちらはMCUデータの途中から格納されているので、これも無効と判定する。
バッファ管理処理は「要求されたデータがすべてバッファに入っていれば、バッファ内部のデータを返す」という作りにしてしまったので、バッファまたぎのアクセスは、ファイル読み込みを要求する動作になった。
バッファ管理をもうちょっと考えないとダメだ。データが1面目と2面目にまたがっているときも、バッファ内部で完結するようにしないと。
この手の境界またぎのデータ処理って、なぜか苦手なんだよなぁ。
とりあえず、先読み時に 2KB ほど余計に読み込むことで、バッファを交代で使う処理が基本的には正しいことだけは確認した。




