Scudo Allocator
アロケーション直後のメモリアクセスで page fault が起こるため超遅い(俺のせいじゃねー)のをなんとかしたい。
素朴なアイデア: 事前に巨大なメモリを確保し、そいつを pre-fault し、その後リリースすれば、そのメモリが再利用されてめでたしめでたしじゃね?
が、これはダメっぽい。
まず pre-fault だが、madvise にはそういうオプションがない。mmap() には MAP_POPULATE があるのに!MADV_POPULATE を入れたいぞ、というパッチがあるが今年のはじめとかで、どう考えても Android には入っていない。そもそも merge されているのだろうか。(されてはいるらしい。)まあこれは最悪 page を traverse すれば良い(ほんとに?)。
問題はアロケータ。Android は少し前から scudo というアロケータを使っている。
が、こいつのコードをみると・・・
- でかいメモリブロックはキャッシュされない!
- キャッシュされるときも releasePagesToOs という関数が madvise(...MADV_DONTNEED) してしまう!世知辛いねえ完全に正しいが・・・。
ところでメモリアロケータってなんとなく連続領域を確保してそいつからメモリを切り売りする、足りなくなったら brk() で伸ばす、みたいなメンタルモデルだったけど、全然違うね。普通に mmap() でインクリメンタルにページ/ブロックを確保していく。使い終わったら unmap() で返す。まあこれが正しいよなあ。
自分の冒頭の素朴なアイデアは完全に 20 世紀のメモリアロケータに依存していたと反省。
冒頭の問題を解決するにはアロケータ差し替えとかが必要な気がするが、それは現実的にはぜんぜん無理なのでなんとか scudo に抜け穴を作って欲しいが、上流が llvm じゃあそれも難しそうだなあ・・・。なんかパラメタいじって乗り切るとかする必要があるのかもしれない・・・。