ロード トップ 参照元 逆検索 検索 ヘルプ

[logo] MGLは遅い?


MGL2は遅い?

実際 遅いという話を良く聞く。マシンの性能を出しきるというのが、 MGL の チューニングポリシーじゃないんで、ある程度遅いのはやむを得ない としても、遅いんであれば、コードをでかくしすぎない範囲で速くはしたい。

ここでは、MGL の設計上のおもわくを説明した上で、 MGL が どれだけ遅いか考察してみようかと思う。

モデル

   a1) SCREEN_WIDTH 分を table 使って MGL の 色コードに変換する。
   a2) put_pixstream() で SCREEN に書き込む。
   ( 1-2 を SCREEN_HEIGHT 分やって(=1画面分が終ったら)、refresh() で
     画面イメージを update する。)
   a3) (refresh) get_pixstream() で SCREEN のデータを取って来る。
   a4) (refresh) MD_PUT_PIXSTREAMXX() で データを framebuffer に書き出す。

よく使われているのは、だいたいこんな感じだろうと思う。 で、いまは、16bpp なマシンが最も遅いから ターゲットは 16bppということ にする。

完全に最適化できたとして、

   b1) 24bpp(32bpp) RGB から 16bpp への変換する
   b2) そのデータをフレームバッファにたたきこむ

ということになると思う。

そうすると余分な処理は、

おもわく

ざっと見積もって、b1 + b2 のコストと a3 + a4 のコストは同じぐらい ではなかろうか。

a4 で、色変換のためのテーブルを使っているんだけれども最大でも

     4096 * 2 = 8K バイト

だし、色使いはランダムじゃないから、うまくキャッシュに載ってくれるはず。 そうすれば、メモリアクセスほどのコストにはならない。

で、a1 + a2 が余分であるのだが... フレームバッファへの書き込みは、メモリへの書き込みとくらべて 遅い。b1 + b2 より速くできることが期待できる。

というわけで、1/2 よりちょい速めの 60% が目論見値。

実際

実際はどうなのか。シグマリオンで性能を比較してみることにする。

まずはハードの性能。

fb16.h の

static char *fb16_base;
static int fb16_rowbytes;
の static を外し、ここに RGB 生データをたたき込む性能を測る。

ケース1: line 単位で memcpy 使って framebuffer に書く
   ( source は、同じデータ,  dist は 1 画面 を scan) 
ケース2: 同じ条件で メモリ に書く

値: 
   ケース1:  28.750 ms (per frame) , 5.343 Mdots/sec
   ケース2:  13.781 ms (per frame) , 11.146 Mdots/sec

ケース1 は、ソースデータはキャッシュに載り、framebuffer はキャッシュ OFF だから 1 メモリトランザクション しか発生しないと思う。

ところが、ケース2 では、cache-fill のために、いったんデータを読み込み モディファイするから、read-write で 2 メモリトランザクションになるはず。

16bppだから... ケース2 で使えたメモリ帯域は、44MB/sec ということになりそうだ。

それはともかく、framebuffer は、メモリと比べて半分の性能も出ないという 結果になった。たぶん妥当だろうなぁ。

ちなみに、この性能は 画面クリアの性能ということになるだろう。 イメージ転送とかでは、source がキャッシュにないからもっと遅い。

モデルでは、RGB データを変換しつつ... ということにする。

ケース3: 640x240 の 32bpp RGB (R8G8B8) データを配列に用意して、
16bpp RGB に変換しつつ framebuffer にたたき込む。

値: 
   ケース3:  59.016 ms (per frame) , 2.603 Mdots/sec

メモリから読み出して色変換するのと、フレームバッファに書き込むのが 同じぐらいだから、意外に速いように思う。

コードは、

         for (j=0; j<SCREEN_WIDTH; j++) {
               d1 = *ip++;
               d2 =   ( (d1 >> 8) & 0xf800 )
                    | ( (d1 >> 4) & 0x07e0 )
                    | ( (d1 >> 3) & 0x001f );
               *sp++ = d2;
         }
         memcpy(p,data_s,SCREEN_WIDTH*2);

こんな感じ。

ケース4: 今度は、MGL の色に一旦変換し、put_pixstream を使ってみる。
ただし refresh なし。
ケース5: refresh 付き

値: 
   ケース4:  72.891 ms (per frame) , 2.107 Mdots/sec
   ケース5: 158.609 ms (per frame) , 0.968 Mdots/sec

うーん。理論性能の 2.603 Mdots/sec に対して 0.968 Mdots/sec (37%) しか出ていない。やっぱ遅いなオィ。

ぜんぜん 思惑と違うぞ。 ケース4でも b1+b2 を下回っている。ここでは、メモリに書くだけだから、 もっと速い予定だったのだのにぃ。

ちょっと put_pixstream をアンローリングしてみる。

結果は... ちょっとは速くなるんだけどなぁ。

値: 
   ケース4:  68.602 ms (per frame) , 2.239 Mdots/sec
   ケース5: 148.969 ms (per frame) , 1.031 Mdots/sec

やっぱり遅いね。

結論

おもわくは外れた。MGL は遅い。

どれぐらい遅いかというと...

画面サイズが 320x240 だとして... 直接フレームバッファを叩けば 33.8 fps ぐらい出るのに対し MGL 使うと 13.4 fps ぐらいしか出ない。

もうちょいがんばるかなぁ。

付録

使ったプログラム http:arc/bench16.c


どうがんばろうか?'

native ドローエンジン作ってみようかと思って、シミュレーションしてみた。

ケース6:
ドローエンジンだけ native 化したときのシミュレーション:
bitmap に書くときに fb16_ctable[] を通す。

ケース7:
さらに、frame buffer に直急く書く シミュレーション(shared_fb)

値: 
   ケース6:  65.625 ms (per frame) , 2.341 Mdots/sec 
   ケース7:  65.961 ms (per frame) , 2.329 Mdots/sec 

ん? なんかうそっぽいぐらいの値が出てしまった。 ホントかなぁ。

# ちなみに、新しい bench16.c だと ケース3 の最高速の値が、1.954 Mdots/sec
# になってしまう。たぶん、キャッシュのあたり具合が変わってしまった
# ためだと思う。

それはともかく... これぐらいの値が出るなら、shared_fb でなくても 100 ms (= 320x240 で 20fps) ぐらいにはなりそうかなぁ。

じつは、16bpp native ドローエンジンってのは既にある。dec3kc っていうやつ。 なんで、使っていないかというと...

うーん。 MGL は遅いというステータスは悲しいし、がんばろうかなぁ。


(最終更新 Thu Mar 30 18:50:40 2006)