|
昨日のカウンタ: 今日のカウンタ: |
お気楽にプログラムを書いてもサクサク動いてくれるといいな。使うリソース量とかあまり気にしないで「やって欲しいこと」を書くだけでコーディングまで終わるような時代になるといいな。でも今日もまだコードに「どうやってやるのか」を書かないといけないんだなぁ。
そんなことを日々思っているのですが、局所的な話としてこのシリーズでずっと例に出しているモノクロ化にしても「浮動小数点演算なんて遅いから固定小数点演算で」みたいな小手先の技がまだ有効だったりします。いや、もう頭のいい人が素晴しい最適化をしてくれてそんなの必要なくなってるんじゃない? と思いつつも裏切られる日々な訳だったりしますが、RenderScriptではどうでしょうか。
話を戻します。モノクロ化ですが、red, green, blueの色要素を0.288, 0.587, 0.114の比率で混ぜて、その数値を各色要素に戻すだけですので、例えば(red×288+green×587+blue×114)/1000とするのも一例です。が、「1000で割る」という計算の「1000」という数字に特は意味はありません。「256で割る」つまり「8ビット左シフトする」の方が一般には計算が早いのでそうしましょう。つまり今回は(red×76+green×150+blue×30) >> 8での計算を比較してみることにします。
NDKではこんな感じです。
static const int r_lum_i = 76; static const int g_lum_i = 150; static const int b_lum_i = 30; …(中略) for (int i = 0; i < length4; i += 4) { r = inp[i + 0]; g = inp[i + 1]; b = inp[i + 2]; m = (r * r_lum_i + g * g_lum_i + b * b_lum_i) >> 8; outp[i + 3] = 0xff; outp[i + 0] = outp[i + 1] = outp[i + 2] = m; }
RenderScriptではこんな感じです。FilterScriptもほとんど同じなので省略します。
static const uint r_lum = 76; static const uint g_lum = 150; static const uint b_lum = 30; void root(const uchar4 *v_in, uchar4 *v_out) { uchar l = (uchar)((v_in->x * r_lum + v_in->y * g_lum + v_in->z * b_lum) >> 8); v_out->x = v_out->y = v_out->z = l; v_out->w = 0xff; }
さて、速度はどうなるでしょう。小手先の技は悲しいことに通用してしまうのでしょうか? そして浮動小数点を使わない場合であってもRenderScriptはNDKより速いのでしょうか?
処理自身は昨日と同じです。1024×768サイズの画像を100回モノクロ化します。単位はms(ミリ秒)です。relaxの有無とFilterScriptについては昨日の日記を参照して下さい。
機種名 | Nexus 4 | Galaxy Nexus | Galaxy Note 8.0 | Stream X |
---|---|---|---|---|
Androidバージョン | 4.3 | 4.3 | 4.1.2 | 4.1.2 |
NDK | 3809 | 4954 | 1434 | 5501 |
RenderScript | 985 | 2788 | 772 | 2907 |
RenderScript (relax) | 3097 | 5341 | 766 | 2885 |
FilterScript | 3038 | 5406 | 801 | 2899 |
RenderScript (relax)とFilterScriptの差はあまりないので、やっぱりFilterScriptのことはそれほど真面目に考えなくてもいいのかなという点と、NDKとRenderScriptのどちらでも選べるシチュエーションではRenderScriptを選択した方が良さそうという点は昨日の浮動小数点演算の場合と同じでしょうか。やっぱりマルチコアへの展開をやってくれているんでしょうかね。
浮動小数点演算での計算速度の違いとしては、relax指定の付いてないRenderScriptの方がrelax付きよりも速いってところでしょうか。relax付きがホントにGPUで計算してくれているのなら、整数演算はCPUでやった方が効率的かもなぁ、そうかもなぁと一応納得はできるところです。が、やはり確証は持てませんが。
理屈で納得するのはいいとして、Android 4.3の整数演算では、relax無しのRenderScriptがrelax付きより2〜3倍速いというのは、アプリ実装時に悩ましい点であります。だって浮動小数点演算ではrelax付きの方が速い傾向にある訳ですから。
浮動小数点で書くべきところを小手先でやったらどうなるかという点については、昨日の表と比較すればわかりますが、やっぱり小手先の技が効いちゃってます。例えばNexus 4で見ると浮動小数点で最速だったFilterScriptよりも整数演算で最遅のNDKの方がまだ速いです。Galaxy Note 8.0で見ても浮動小数点での最速であるNDKよりも整数演算で最遅のNDKの方がずっと速いとか。小手先の技もまだ有効みたいなのは複雑な気分です。
まぁインラインアセンブラでNEONとかがりがり書きつつも、Open GL ES 3.0でGPGPU的にがりがり書けばもっと速いんでしょうけど。