GUIサーバ高速化/01.ヒント


Top / GUIサーバ高速化 / 01.ヒント

Tinoさんのヒント

# Tino 『GUIサーバーはパフォーマンスチューニングはほとんど考慮されていません。たとえば描画はウィンドウ単位でしか行えず、部分指定できません。ですが毎回全体を再描画するのは論外なので、裏VRAM(ただのバッファ)と比較して変更があった部分だけを実VRAMに書き込むようになっています。その結果Noiz2bgのパフォーマンスは直接VRAMに書き込むのに比べて半分くらいに落ちていますが、その性能は想定していたよりまし(私としては許容範囲)だったため、それ以上のチューニングはしませんでした。
GUIサーバーのバッファは三重になっています。ウィンドウ→トップレベルウィンドウ→裏VRAM→実VRAM。これは透過処理をやりたかったのと、再描画要求をアプリに毎回伝えないでサーバー内で処理させた方がパフォーマンス的に有利だったからです。 詳しいことは↓のコメントとかを参照してください。
http://d.hatena.ne.jp/Bayside/20050527』 (2006/08/27 20:42)

# Tino 『↑のような部分描画と、後述の遅延描画を導入して、抜本的にGUIサーバーの描画を最適化しないとダメだと思います。
Windows にはRefreshとInvalidateの区別があります。Refreshはその場で描画要求を送ります。Invalidateは領域を無効にして遅延描画します。GUIサーバーにはRefreshしかありません。Invalidateをサポートすれば高負荷時のパフォーマンスが改善すると思われます。
Invalidateの動作を具体的に説明すると、無効にする領域を受け取ったらキューに入れて何もせずに処理を戻して、イベントキューが空になってwait状態になってから無効にされた領域だけを再描画するということです。これを遅延描画と表現しました。
無効にされた領域のキューはvector<Rectangle>辺りで管理して、描画する前に幾何学的な重複領域の省略などのチェックをして最適化するべきです。たとえば(x=0,y=0,w=20,h=20)と(10,10,20,20)の長方形があった場合、重複領域 (10,10,10,10)を二度描画するのは無駄なので、それを省いた3つの領域(0,0,10,20),(10,0,10,30), (20,10,10,20)に分割して描画するようなことです。この辺はほとんど幾何学の領域なのですが、マイクロソフトは数学者を動員してこの手の最適化を施したのだそうです。
あまりあれこれやると全部中途半端になるので、今すぐ私が取り掛かるのは無理です。』 (2006/08/27 21:00)

# Tino 『あとついでに書くと、バッファを共有メモリに確保しているため、リサイズで毎回作り直すとおかしなことになるため、リサイズの実装は避けました。
リサイズを真面目にやると、バッファを4KB単位に分割して、動的に繋ぎかえるなどの工夫が必要になりそうです。モザイクな飛び飛びのメモリをリニアなものに見立てるようなイメージです。これも真面目に考えると頭が痛いです。
一番簡単な実装は透過処理や非矩形を捨ててバッファをやめて、アプリから毎回VRAMに直接再描画することでしょう。
ただ個人的な好みを言うと、機能を落としてスピードが速くなるのは当たり前なので、いかに機能は維持したまま最適化を施すかが腕の見せ所なんじゃないかと思います。』 (2006/08/27 21:12)

# Tino 『今だから言いますが、前述のようなことは当時から分かっていました。そしてそこまで作りこむ気はありませんでした。なぜならひげぽんさんのGUIの実装が開始されてから、少しずつ手の内や問題点を説明していくつもりだったからです。GUIも真面目に追求するとかなり頭が痛いです。
ところで実は自分でもGUI Shellがとても遅いと思っていました。一文字表示するたびにウィンドウ全体の再描画要求を送っているから当然です。ただ字を入力する程度なら我慢できるレベルですが、lsなどとして大量に細かい描画要求を送りつけると、そのたびに全部再描画しているため遅さが一目瞭然です。この辺は Invalidateを実装すれば劇的に改善するはずです。』 (2006/08/27 22:06)

# Tino 『MonaFormsとBayGUIのパフォーマンスを確認する方法は簡単です。
文字を一文字ずつ表示してウィンドウを埋めるようなものを作って、所要時間を計測すれば良いです。多分大きな差はないと思います。
そしてそのテストでウィンドウのサイズを変えて実験すれば、面積に比例して遅くなるのが分かると思います。理論上100x100は50x50の4倍時間がかかるはずです。部分描画がないのでその辺は直撃するはずです。』 (2006/08/27 22:11)

# Tino 『あ、4倍というのは語弊があったかもしれません。一文字の描画にかかる時間が面積に比例して4倍ですが、文字数も4倍になるので、全体で16倍の時間がかかるはずです。n^2ということです。200x200は50x50の256倍も時間がかかるはずです。』 (2006/08/27 22:17)

# Tino 『Refreshの部分描画なら小一時間で出来ると思います。
Invalidate を最適化するのは難しいですが、他のOSで実装してから移植するというより、幾何学図形を処理する過程として一般化した方が良いと思います。視覚化を一般的な過程に盛り込む考え方です。回り道に見えるかもしれませんが、多分その方が近道です。』 (2006/08/27 22:34)

# Tino 『最後に一言。当時GUIを作れと突いていたのは、こういうことをきちんと説明しながら作る体制に持って行きたかったからです。説明しないで逃げた形になったのは不本意でした。以上。

[Mona] みくびっていました orz
BayGUIリライトのためにとりあえずデバッグの楽なSDLを使っているのですが、NOIZ2BGが思ったより早くなかったのでこんなもんか・・とみくびっていました。BayGUIではダブルバッファリングを行っていまして、SDL版ではSDL_UpdateRectという関数でスクリーンに実際に描画を行っています。この関数は引数に更新範囲を指定できます。いままでは指定なし(スクリーン全体を更新)にしていましたが、更新範囲をきっちり指定してみたところ劇的に早くなりました。現状のコードに満足するな!ですね(XPでは日々リファクタリングを薦めています)。

/* screenの全領域を更新 */
SDL_UpdateRect(screen, 0, 0, 0, 0);
       ↓
/* screenの一部領域を更新 */
SDL_UpdateRect(screen, this->x, this->y, this->width, this->height);

MonaのGUIサーバーはアプリケーションフレームも部品もすべてウィンドウ(いわゆるWin32APIのウィンドウと同義)として管理しています。しかし親をもっているウィンドウ(一般的な部品)に再描画メッセージを送っても親ウィンドウが再描画されない限り画面に反映されることがありません。この辺りをなんとかしたいと思いつつも描画系やイベント系をいじるとBayGUIだけじゃなく、MonaFormsにも影響が出るのでずっと躊躇しているんですよね・・。MonaForms(というかGUIサーバー)のリファクタリングとパフォーマンスチューンを行ってくれる方を強く希望しています。


互換性を維持するには動作を変更するのではなく、
新しい動作を追加してそちらを使えばいいでしょう。

追加ですまないような場合は、たとえば、
MonaFormsがマウスイベントの受け取り方を変更したとき
guiserver_window::Protocolというフラグを新設して
値が設定されているときだけ変更されたイベントを通知するように拡張したため、
追随していない場合も影響を受けないという仕組みがあります。

描画の遅さはバッファが多重になっているのと
部分描画がサポートされていないのが原因と考えられます。

再描画のMSG_GUISERVER_DRAWWINDOWは
上のSDL_UpdateRect(screen, 0, 0, 0, 0)の例のように、
トップレベルウィンドウ単位での丸ごと再描画しかサポートされていません。
これを範囲指定できるように拡張したとしても、
もともと指定せずにゼロが送られていたわけですから、
ゼロの場合は全描画(SDL_UpdateRectと同じ)するようにすれば
互換性に影響せずに拡張できるでしょう。

バッファの多重性は、
1. ウィンドウごとのバッファ
  ↓
2. トップレベルウィンドウのバッファ
  ↓
3. 仮想VRAM(32bpp)
  ↓
4. 本当のVRAM
という、double buffer(2重)どころかquadruple buffer(4重)になっています。

再描画がトップレベルウィンドウを経由するのは2の存在のためです。

わざわざ3を挟んでいるのは2つ理由が考えられます。

1つ目は、3→4でbpp変換を行うことで
クライアントからはbppを隠蔽して常に32bppに見せ
処理を単純化するのが狙いでしょう。

2つ目は、VRAMへのアクセスは普通のメモリより遅いので、
2→3への書き込みで変更があるときだけ3→4に転送することで、
可能な限りVRAMへのアクセスを抑える狙いもあります。

しかしそれが有効かどうかはベンチマークをしてみて、
差分チェックをせずに単純に転送する場合と比較する必要があります。

仮に3の存在意義がないと判断された場合でも、
3自体はサーバー内部で管理されているだけなので、
サーバー内で3を廃止して2から直接4に書き込むように変更しても
クライアント側には影響は出ないでしょう。

コメント

コメントはありません。 コメント/GUIサーバ高速化/01.ヒント?

お名前:

MENU

now: 2

リンク


最新の20件
2018-05-03 2017-09-29 2017-04-25 2017-01-10 2016-12-11 2016-10-04 2016-08-14 2016-06-05 2016-05-29 2016-04-15 2015-12-28 2013-02-25 2013-02-21 2013-02-20 2013-02-12 2013-02-11 2013-02-10
最新の20件
2010-02-01 2010-01-31 2010-01-30 2010-01-29 2010-01-16

Counter: 2204, today: 1, yesterday: 0

リロード   新規 編集 凍結 差分 添付 複製 改名   トップ 一覧 検索 最終更新 バックアップ   ヘルプ   最終更新のRSS

Last-modified: 2008-03-28 (金) 15:47:54 (3735d);  Modified by mona
PukiWiki 1.4.6 Copyright © 2001-2005 PukiWiki Developers Team. License is GPL.
Based on "PukiWiki" 1.3 by yu-ji
Powered by PHP 5.2.17
HTML convert time to 0.045 sec.