JNI遅くないよ。SQLite悪くないよ。TraceViewかわいいよ。

id:minghaiさんがSKKAndroidに実装*1されてて、SQLite遅すぎワロタwwwとかおっしゃってたので、なんでそんなに遅いんだろと思って、ごにょごにょしてみた。
jni-sqlite.tar.gz.gz
ダウンロードすると、いくつかファイルが入っている。

PlatformLib.patch Client*.traceを作るためのdevelopment/samples/PlatfromLibraryにあてたパッチ
Client.trace PlatformLibraryのTraceView用ログ。1回目
Client2.trace PlatformLibraryのTraceView用ログ。2回目
SQLiteTest SQLiteのTraveViiewログをとるためのソースコード
sqlite1.trace SQLiteTestのTraceView用ログ。1回目
sqlite2.trace SQLiteTestのTraceView用ログ。2回目

TraceView用ログを/android/sdk/tools/traceviewで開くと、関数の呼び出しシーケンスと、それぞれの関数でどれだけ時間がかかったかをグラフィカルに表示する。これらのログは、donut版のAndroidを載せたZaurus C3000で取得した。ちなみに、このTraceViewの存在は、前回のAndroid勉強会@金沢*2で行われた、おおいしさんのプレゼンで知った。

$ /android/sdk/tools/traceview Client.trace

Client.traceを見るとJNI経由でintの値を取るgetIntJNIは、40μ秒とか50μ秒とか、そーゆーオーダーでしか時間がかかっていない。つまり、JNIは十分早い。Client.traceを取った後で、再度アプリを立ち上げてClient2.traceを取得してみると、プログラム全体では時間が短くなっている。これはライブラリの初期化とかをしなくて済んでいるからで、JNIそのものの時間は変わっていない。


で、SQLiteTestを書いて実際にSQLiteを実行してプロファイルしてみた。データベースへのアクセスは、id:minghaiさんのコードをコピペしたもの。

$ svn diff -r3

とかして、昔のSQLiteのコードを拾った。念のためにAsyncTaskを使って別スレッドで動かしている。余談だけど、このAsyncTaskの使い方もadamrockerさんが丁寧に説明*3してくださっていて、あと1日記事の公開が早かったら、アタイも20分くらい節約できたのにwwwとか思た。


結果から言うと、SQLiteの実行そのものよりも、Cursorで結果を受け取る部分のオーバーヘッドが大きい。hogehoge_nativeという部分は確かに時間がかかっているけど、その他のごにょごにょが結構大きい。というわけで、JNIもSQLiteも遅いわけではなく、Androidフレームワークとしてデータベースを使いやすくする部分のオーバーヘッドが重い。ということ。


この実験には含めていないけど、繰り返しSQLiteを呼び出すと、GCされるオブジェクトが大量に発生する。そのオーバーヘッドも考慮する必要がある。で、結論。チュートリアルのNotePadが、すべてのエントリを一度に読み出し、すべてのエントリを一度に書き戻す実装になっているのは、こまめなDBアクセスは、かえって重くなるというAndroidの特質。逆に言うと、データはクラウドに置け、という御託宣。


もうちょっと丁寧にエントリを書こうと思ってたけど、なんか風邪っぽくて熱っぽくて、せっかくデータとったのに公開が先になりすぎると、腐りそうなので、とりあえずのうp。追試とかデータ見てツッコミとか大歓迎。データの読み方、難しい。


あと、profiling重要。Debug Hacksネタでもあるので、id:hyoshiokさんにAndroid向けHackとしてトラバ。