FPSカウンターの正しい実装方法

· coding · Source ↗

まとめ

  • FPSカウンターの正しい基盤は、固定1秒幅のローリング時間ウィンドウにフレームタイムスタンプを記録する方式だ。フレーム数ベースのウィンドウは誤解を招くグラフを生む。

重要なポイント

  • Method 1(単一フレーム)とMethod 2(直近Nフレーム)は誤り:前者はノイズが多く、後者はウィンドウの長さが計測対象の指標に依存する自己参照的な構造になる。
  • Method 4はフレーム完了タイムスタンプのキューを保持し、ウィンドウより古いものを捨て、カウントをウィンドウ長で割ってFPSを算出する。
  • Method 5はこれを拡張し、フレームごとの処理時間も記録する。同じデータ構造から平均フレーム時間・最遅フレーム・標準偏差が得られる。
  • タイマーの精度には SDL_GetPerformanceCounterstd::chrono::high_resolution_clock を使うこと。低精度タイマーはどの方式も台無しにする。
  • フレーム中のヒープアロケーションを避けるにはキューを循環バッファに置き換えられる。想定される最大バーストを超えるサイズに設定すること。

Hacker News コメントレビュー

  • コメント欄では概ねローリングウィンドウ方式に同意しつつ、よりシンプルな定数時間・定数空間の代替として指数移動平均(EMA)を推す声が多かった。alpha = 2/(n+1) とすれば、キュー不要でnサンプル移動平均と同等の平滑化が得られる。
  • FPS単体では体感パフォーマンスを把握するのに不十分という指摘も複数あった。10秒ウィンドウでlow1%・low0.1%といった低パーセンタイルのフレーム時間を追うことで、平均が隠すスタッターを検出できる。値が落ちたときにカウンターを色変えするのは実際に出荷されているパターンだ。
  • Vulkan固有の注意点:VK_EXT_present_timing なしでpresent間のタイミングを正確に取得することはできず、OSスケジューラのノイズが高精度レンダリングタイミングさえ乱すため、FPSカウンターはあくまでレンダースループットの推定値であり、ディスプレイの実際の表示タイミングではない。

注目コメント

  • @mightyham: alpha = 2/(n+1) のEMAはnサンプル移動平均と一致し、時間・空間ともにO(1)でキュー不要。
  • @NL807: 最終フレームFPSはスパイク検出向き、中央値ウィンドウは体感フレームレート向き、平均ウィンドウは統計的フレームレート向き――用途に合わせて選ぶべき。
  • @flohofwoe: 平滑化したフレーム時間はFPS表示だけでなく、アニメーションやゲームロジックのタイミングにも適用すること。そうしないとFPS表示がきれいでもマイクロスタッターは残る。

Original | Discuss on HN


英語版: How to Implement an FPS Counter · Original source