コード探偵 ファイル02「FPSで犯人割り出し」
パフォーマンス殺害の容疑者は常に二人居ます。CPUとGPUです。この二人の容疑者から考えられるのは以下の三つ。
- CPUが犯人(CPUバウンド)
- GPUが犯人(GPUバウンド)
- 二人は共犯者(CPUとGPUのバランスが取れている)
まずはパフォーマンスを殺した犯人を特定するのが先決で、その後に犯行の動機や手段を洗い出します。
FPSを測定して犯人を特定する
CPUバウンドかGPUパウンドを見つけだすには、FPSを測定する方法と、タイムルーラーを使う二つの方法があります。
FPSを測定する場合は、コードに簡単な変更を加える必要があります。このときに注意しないといけないのは、描画コードをコメントアウトしただけではCPUバウンドかGPUバウンドかは特定できないことです。コメントアウトをすることでFPS値は高くなりますが、描画にはCPUとGPUの両方が仕事をするので、どちらが犯人かは特定できません。
もっとも簡単な方法はGame.Updateメソッド内に以下の一文を加えるだけです。
// 1ミリ秒休む
Thread.Sleep(1);
もし、この行を加えてもFPS値が変化しないのであれば、GPUバウンドということになります。更にこのアイドル時間を少しずつ増やしていき、FPSが変更した時点のアイドル時間がそのままCPUがヒになっている時間を測定することができます。
もし、FPS値に影響するようであれば、CPUバウンドか、CPUとGPUのバランスが取れている可能性があります。
この場合、今度はCPUの作業量を減らしてCPUバウンドか、CPUとGPUのバランスが取れているのかを特定することになります。
CPU作業を減らす簡単な方法は、更新部分の処理を丸ごとスキップすることです(この方法はCPUがある程度の時間を使っている状態じゃないと使えないことに注意)。とは言っても、更新部分のコードは描画部分のコードにも影響するので(更新部分が呼ばれないと、敵とかが出現しなくなっちゃうから)、常に更新部分をスキップするのではなく、指定した期間だけ更新部分をスキップすることにします。
例えば、以下のコードのように、ゲームに関係ないキーなどを使うと良いでしょう。ここでは前回紹介したPROFILE構成を使っています。
protected override void Update(GameTime gameTime)
{
#if PROFILE
// 1ミリ秒スリープ
if (currentKeyboardState.IsKeyDown(Keys.PageUp))
Thread.Sleep(1);
// 更新処理を丸ごとスキップする
if (currentKeyboardState.IsKeyDown(Keys.PageDown))
return;
#endif
....
この変更を加えた後にゲームを実行し、CPUバウンドかGPUバウンドかを特定したい場所まできたら、これらのキーを押してFPS値の変化をみます。
もし、スリープしてもFPSが変化しなければ、GPUバウンド
もし、更新処理をスキップしてFPS値が上がったら、CPUバウンド
もし、更新処理をスキップしてもFPSに変化がなく、スリープしてFPS値が下がるようであれば、CPUとGPUはバランスがとれた状態。
次回はタイムルーラーを使用してCPUバウンドかGPUバウンドなのかを判別する方法を紹介します。
元ネタ:
http://blogs.msdn.com/shawnhar/archive/2008/04/07/how-to-tell-if-you-are-cpu-or-gpu-bound.aspx