5870性能評価(4)

測定用に作ったテストプログラムで10K個を超える頂点数のモデルを表示していたら、どうも頂点数4個の時より重いなぁと感じたのでいろいろ調査していたのがようやく答えらしきところまで到達できた…
長かった。



事の発端は、板きれモデルの頂点数を4から一気に1.5M(1,500,000)まで増やしてPixel Shaderの命令数2000で表示させると、60fpsどころかガクガク状態になってびっくり。ってところから始まった。

最初はIndex BufferからVertexを引っ張ってくるのが重いのかと思ってIndexなしにしてみたけど変化なし。なんか、Vertex Cacheってのがあるらしいのでアクセス時間的に関係ないのかもしれない。そもそもデータ量も数10MBだし。
次にPixelの命令数が2000と多すぎるので、SIMD Coreがなかなか空かなくてVertexが待ちになってるのかと思って、Pixelの命令数を減らす代わりにレンダリングを100回繰り返してみたりしたけど、これはまったく意味がなくてPixel命令数がたとえば20でも100回繰り返したら合計2000のままじゃん!ってことで原因究明には役立たず(後で書くように、命令数を維持したままだとダメだった)。この辺のプログラム作成、検証と考察、Web調査などで数週間を無駄にしてしまった…この測定法がダメってことに気づいたのは今日になってからだったり…
cbufferのmapが重いのか、とかAPI呼び出しの数を減らさないとオーバーヘッドが大きいのか、とかいろいろ無駄に検討したりしてしまった。


で、昨日の夕方になって、昔Compute ShaderでGPUの性能評価を試みようとしていた時期にATIGPU PerfStudioなるパフォーマンス測定用ツールをダウンロードしていたことをWeb調査中に思い出したり…*1
当時はダウンロードしたものの、DrawXXX()系APIを呼び出していないとツールが動作してくれなかったので、放置したままになっていたという状況だったりした。
今回はテストプログラムでちゃんとDrawIndexed()を呼んでいるので試してみたらパフォーマンス測定ができた。


で、測定してみると「GPUTime」って項目で実際にGPUが稼働している時間を出してくれて、「GPUBusy」とか「ShaderBusy」とかで%単位でどれくらい時間がかかっているか表示してくれた。
測定結果をつらつらと眺めていて気になったのが「PAStalledOnRasterizer」って項目。これが90%を超えてる。一瞬ラスタライザがボトルネックになってるのかと思ったけど、ヘルプの「Frame Analyzer」−「Frame Profiler」−「Available Counters」とたどって該当項目を見てみると、

Percentage of GPUTime that primitive assembly waits for rasterization to be ready to accept data. This roughly indicates for what percentage of time the pipeline is bottlenecked by pixel operations.

となっていて、どうやら”Pixel処理待ちのせいでラスタライザが次の頂点データを受け取れない状態になってる割合”のことっぽい。
これが90%超えてるってことは、Pixel命令数が多すぎてラスタライザが待ちになっている、ということになる。Vertex Shaderが待っている訳じゃなかったみたい。だけど、だいたい読みは当たってるじゃないかー!ヽ(`Д´)ノ


Pixel命令数を22まで引き下げてみたら、1.5M頂点でも待ちが22%まで落ちて、フレームレートも60どころか1000超えまで回復。ただ、ここまでPixel命令数を落としても待ちがあるってことは、頂点数をある程度以上に引き上げるとどうしてもPixel待ちが発生しちゃうってことになる。(なので、上述したPixel命令数を維持したままレンダリング回数を増やす方法は検証方法としてダメだった)
この結果をみるに、どうやら頂点数とPixel命令数はバランスをとらないと待ちが発生しちゃうっぽいなぁ。しかも22命令ですら22%待ちとかコンピューティングパワーを100%使えないじゃん…命令数2000の時も頂点数を4から少しでも増やすとフレームレートが下がったから事実上フルに使い切れない感じかと。



ということで、まとめ。

  • 頂点数とPixel命令数は独立に変更できない
  • 現実的な頂点数(4より大きい)のモデルを表示する限りGPUのコンピューティングパワーを100%使い切れない

1番目は結構ヤバい制約かもしれない。ゲームの設計をするときに表現したいPixel処理の命令数と、画面に表示できるモデルの頂点数を独立に決められないので、どっちかをリッチにしたらどっちかをショボくしなきゃフレームレートを維持できなくなるかもしれないってことになる。しかも実際に測定してみないとどの程度の影響があるのか見切れないのが痛い。プロトタイプを動かしながらゲームデザインを進めていく感じになるか。しかも最悪フレームレート変更とかになったらプログラマが死ねる。マジで。

2番目は5870的には大丈夫かもしれない。100%使い切れないのはエンジニアとしては悔しいけど、頂点数を減らせばなんとかなりそうだし。てか、普通1.5M頂点のモデルとか表示させないし。いろいろ試してた感触だと960Kに減らすだけでずいぶんフレームレートが回復したし。(普通は数10K頂点くらい?)
あれ?そもそも1.5M頂点も使わないなら1番目も問題にならない??あ、いや、最初にがっちり見積もれないのは問題だよね。

*1:ツールのページに飛んでようやく思い出す始末