フレーム レート

平均 FPS

Android デバイスで高品質のゲーム エクスペリエンスを提供するには、スムーズで安定したフレームレートが不可欠です。ゲームのパフォーマンスを測定する際は、エクスペリエンスの基本的な理解を得るための ベースラインとして平均 FPS を測定する必要があります。優れたゲーム エクスペリエンスを実現するには、平均フレームレートが 60 FPS になるようにゲームを最適化する必要があります。

安定性のための P90 と P99 の FPS

平均 60 FPS でスムーズに動作するゲームでも、断続的な引っ掛かり、マイクロスタッタリング、予測不可能な入力遅延が発生し、プレーヤー エクスペリエンスが低下する可能性があります。

そのため、フレームの安定性は平均フレームレートの追跡と同じくらい重要です。 ここでは、P90 と P99 のフレームレート指標を、それぞれ一貫したベースラインとスタッタリング インジケーターとして測定する必要があります。これらの指標は、プレーヤー エクスペリエンスのスムーズさを最適化するためのパフォーマンスの「末尾」を捉えます。

指標

  • 平均 FPS(ベースライン): この基本的な指標は、ゲームのパフォーマンスの一般的な ベースラインを示します。標準的なベンチマークですが、平均値の計算では断続的なフレームの低下やマイクロスタッタリングを検出できないため、プレーヤー エクスペリエンスを単独で表すには不十分です。
  • P90 FPS(10 パーセンタイルの安定したベースライン): これは、フレームの 90% がこの一貫したベースラインを超えており、レンダリングに時間がかかったのは最も遅い 10% のフレームのみであることを示します。P90 フレームレートが高く、平均値に近い場合、ゲームはセッションの大部分で一貫して良好に動作しています。
  • P99 FPS(1 パーセンタイルのスタッタリング インジケーター): これは、フレームの 99% が このスタッタリング インジケーターを超えており、最も遅い 1% のフレームが 分離されていることを示します。この指標は、マイクロスタッタリング、アセット読み込みの遅延、目に見える引っ掛かりの原因となるアセット負荷の高いレンダリングの急増を捉えるために不可欠です。

平均 FPS を P90 と P99 の指標と比較することで、ゲームの根本的な動作を正確に診断できます。

シナリオ 1: 最適な曲線(最適化されたゲーム)

  • 平均: 60 FPS(16.6 ミリ秒)
  • P90: 58 FPS(17.2 ミリ秒)
  • P99: 52 FPS(19.2 ミリ秒)
  • 分析: 指標が密にクラスタ化されています。ゲームは非常にスムーズで一貫性があります。マイクロスタッタリングはなく、最悪の 1% のフレームでも人間の目にはほとんど気づきません。

シナリオ 2: 負荷のボトルネック(CPU/GPU バウンド)

  • 平均: 45 FPS(22.2 ミリ秒)
  • P90: 40 FPS(25.0 ミリ秒)
  • P99: 38 FPS(26.3 ミリ秒)
  • 分析: 平均フレームレートは低いですが、一貫しています。P99 は平均値と比較して大幅に低下していません。これは、システムがグラフィック設定または解像度の制約によって基本的に圧倒されていることを示しています。 ゲームはスタッタリングしているようには感じられませんが、動作が遅くなります。通常、グラフィック設定を下げると、これらの指標は均一にスケールアップします。

シナリオ 3: 不安定な 60 FPS(シェーダー コンパイル / アセット ストリーミング のスタッタリング)

  • 平均: 60 FPS(16.6 ミリ秒)
  • P90: 45 FPS(22.2 ミリ秒)
  • P99: 15 FPS(66.6 ミリ秒)
  • 分析: これは最悪のシナリオです。平均フレームレートは優れているように見えますが、P99 には重大な問題があります。P99 が 66.6 ミリ秒の場合、ゲームは一度に複数のフレームで完全にフリーズします。これは、通常は CPU のボトルネック、アセット ストリーミングの遅延(RAM やストレージの速度が遅いなど)、またはシェーダー コンパイルによる引っ掛かりが原因で発生する、重大な外れ値を示しています。

測定

平均 FPS、P90、P99 の FPS を効果的に測定するには、次の 2 つの方法を使用できます。1 つ目の方法は、パフォーマンス プロファイリング ツールである Android Performance Analyzer(APA) を使用してシステム トレースを分析する方法です。2 つ目の方法は、既存の adb dumpsys SurfaceFlinger --timestats コマンドを使用する方法です。

1. APA を使用して測定する

APA を使用すると、システム トレースを記録し、SQL クエリを使用してフレームデータを正確に分析できます。指標を測定する手順は次のとおりです。

  1. APA でトレースをキャプチャする: ゲームを実行し、APA を使用して、分析するセグメント(フレームの低下が疑われるゲームプレイ中のポイントなど)の システム トレースをキャプチャします。デバイスが接続され、トレースの記録が完了すると、トレースデータが APA インターフェースに読み込まれます。

    トレース キャプチャ画面または読み込まれたトレース画面
  2. APA で [SQL] タブをクリックする: トレース分析画面が開いたら、UI の上部またはサイド ナビゲーション領域にある [SQL] タブをクリックして トレース プロセッサ環境を開き、データを直接クエリできます。

  3. **APA の [SQL] タブに SQL クエリを貼り付ける**: 次の SQL クエリをコピーして、 クエリ入力フィールドに貼り付けます。このクエリは、SurfaceFlinger プロセスを特定し、実際の表示更新タイムスタンプに基づいてフレーム間隔を計算し、平均 FPS、下位 10%(P90)FPS、下位 1%(P99)FPS を導出します。

    WITH target_process AS (
    -- 1. Get SurfaceFlinger process ID where frames were identified in debugging step 3
    SELECT upid
    FROM process
    WHERE name = '/system/bin/surfaceflinger'
    ),
    actual_present_times AS (
    -- 2. Calculate the hardware display timestamps when SurfaceFlinger actually updated the screen
    SELECT
        (ts + dur) AS present_ts
    FROM actual_frame_timeline_slice
    WHERE upid IN (SELECT upid FROM target_process)
        AND dur > 0
    ),
    present_intervals AS (
    -- 3. Calculate intervals between physical screen refreshes
    SELECT
        (LEAD(present_ts) OVER (ORDER BY present_ts ASC) - present_ts) / 1000000.0 AS p2p_ms
    FROM actual_present_times
    ),
    valid_intervals AS (
    -- 4. Filter for valid frame intervals
    SELECT p2p_ms
    FROM present_intervals
    WHERE p2p_ms IS NOT NULL AND p2p_ms > 0
    ),
    ordered_frames AS (
    -- 5. Sort in ascending order to calculate percentiles
    SELECT
        p2p_ms,
        ROW_NUMBER() OVER (ORDER BY p2p_ms ASC) AS row_num,
        COUNT(1) OVER () AS total_frames
    FROM valid_intervals
    )
    -- 6. Output final metrics
    SELECT
    (SELECT COUNT(1) FROM valid_intervals) AS total_presented_frames,
    ROUND(1000.0 / NULLIF((SELECT AVG(p2p_ms) FROM valid_intervals), 0), 2) AS average_fps,
    ROUND(1000.0 / NULLIF((SELECT p2p_ms FROM ordered_frames WHERE row_num = CAST(total_frames * 0.90 AS INT)), 0), 2) AS low_10_fps,
    ROUND(1000.0 / NULLIF((SELECT p2p_ms FROM ordered_frames WHERE row_num = CAST(total_frames * 0.99 AS INT)), 0), 2) AS low_1_fps;
    
  4. [クエリを実行] をクリックする: クエリ入力フィールドの近くにある [クエリを実行] ボタン(または実行アイコン)をクリックします。クエリの実行が完了すると、測定された合計フレーム数(total_presented_frames)、平均フレームレート(average_fps)、下位 10% FPS(low_10_fps)、下位 1% FPS(low_1_fps)が結果ペインのテーブルに表示されます。

    実行された SQL クエリと、テーブルに表示された 4 つの結果の指標を示す画面

2. adb(dumpsys SurfaceFlinger)を使用して測定する

平均 FPS、P90、P99 を効果的に測定するには、Android dumpsys surfaceflinger timestats コマンドを使用します。このツールは、レンダリングされているすべてのレイヤの平均 FPS と presentToPresent タイミング ヒストグラムを提供します。フレームの presentToPresent 時間は、現在のフレームと描画された前のフレームの間隔です。

ゲームのこれらの指標を収集して計算する手順は次のとおりです。

  1. キャプチャを開始する: enable フラグと clear フラグを指定して次のコマンドを実行し、情報のキャプチャを開始します。

    adb shell dumpsys SurfaceFlinger --timestats -clear -enable
    
  2. 情報をダンプする: ゲームを十分にプレイしたら、 dump フラグを指定してコマンドを再度実行し、情報を出力します。

    adb shell dumpsys SurfaceFlinger --timestats -dump
    
  3. レイヤでフィルタする: ダンプされた情報には、SurfaceFlinger によってレンダリングされたすべてのレイヤ のデータが含まれています。layerName(layerName = SurfaceView[com.example.yourgame...] など)に基づいてフィルタして、ゲームに対応するセクションを見つける必要があります。

    layerName = SurfaceView[com.google.test/com.devrel.MainActivity]@0(BLAST)#132833
    
  4. 平均 FPS を特定する: 各レイヤの平均 FPS は自動的に計算され、ダンプ出力に直接表示されます(averageFPS = 30.179 など)。

    ...
    averageFPS = 30.179
    ...
    
  5. P90 と P99 の FPS を計算する: P90 と P99 の指標を見つけるには、ダンプで提供される totalFrames と presentToPresent タイミング ヒストグラムを 分析する必要があります。

    totalFrames = 1000
    ...
    presentToPresent histogram is as below:
    0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=0 9ms=0 10ms=0 11ms=0 12ms=0
    13ms=0 14ms=0 15ms=0 16ms=850 17ms=0 18ms=0 19ms=0 20ms=0 21ms=0 22ms=0 23ms=0
    24ms=0 25ms=0 26ms=0 27ms=0 28ms=0 29ms=0 30ms=0 31ms=0 32ms=0 33ms=100 34ms=0
    36ms=0 38ms=0 40ms=0 42ms=0 44ms=0 46ms=0 48ms=0 50ms=35 54ms=0 58ms=0 62ms=0
    66ms=10 70ms=0 74ms=0 78ms=0 82ms=0 86ms=0 90ms=0 94ms=0 98ms=0 102ms=5 106ms=0
    110ms=0 114ms=0 118ms=0 122ms=0 126ms=0 130ms=0 134ms=0 138ms=0 142ms=0 146ms=0
    150ms=0 200ms=0 250ms=0 300ms=0 350ms=0 400ms=0 450ms=0 500ms=0 550ms=0 600ms=0
    650ms=0 700ms=0 750ms=0 800ms=0 850ms=0 900ms=0 950ms=0 1000ms=0
    

    A. 概念的な例(累積分布テーブル) ゲーム セッションで totalFrames のカウントが 1,000 と記録されたとします。P90 と P99 を見つけるには、累積フレーム数がそれぞれ 900 フレーム(90%)と 990 フレーム(99%)に達するミリ秒のしきい値を、最も低いミリ秒のバケットから数えて計算します。

    フレーム時間(ミリ秒) フレーム数(ヒストグラム) 累積フレーム数 パーセンタイルのステータス / 計算
    16 ミリ秒 850 850 85.0%
    33 ミリ秒 100 950 95.0%
    (P90 の目標値 900 に到達しました。→ 1000/33 = 30.3 FPS
    50 ミリ秒 35 985 98.5%
    66 ミリ秒 10 995 99.5%
    (P99 の目標値 990 に到達しました。→ 1000/66 = 15.1 FPS
    102 ミリ秒 5 1,000 100%

    B. 実装ロジック(疑似コード) Python スクリプトまたはログ パーサーを使用してこの分析を自動化する場合は、ヒストグラムから P90 と P99 の値を抽出するロジックを次のように実装できます。

    # Define target thresholds based on total frame count
    p90_target = totalFrames * 0.90
    p99_target = totalFrames * 0.99
    
    cumulative_frames = 0
    p90_fps = None
    p99_fps = None
    
    # Iterate through the parsed SurfaceFlinger histogram data (sorted by millisecond)
    for ms_bucket, frame_count in present_to_present_histogram:
        cumulative_frames += frame_count
    
        # Capture P90 when cumulative frames cross the 90% threshold
        if p90_fps is None and cumulative_frames >= p90_target:
            p90_fps = 1000 / ms_bucket
    
        # Capture P99 when cumulative frames cross the 99% threshold
        if p99_fps is None and cumulative_frames >= p99_target:
            p99_fps = 1000 / ms_bucket
            break # Optimization: stop iterating once both targets are found
    
  6. キャプチャを停止する: 必要な情報をすべて収集したら、 disable フラグを使用して timestats を無効にする必要があります。

    adb shell dumpsys SurfaceFlinger --timestats -disable
    

速度の遅いセッション

速度の遅いセッションは、広範囲にわたる実際のパフォーマンスの問題を特定します。25% を超えるフレームがしきい値(20 FPS など)を下回ると、セッションは「速度が遅い」と見なされます。 この指標はビルドの重大な問題を特定するのに役立ちますが、この指標だけでは高品質で持続可能なエクスペリエンスを保証することはできません。ゲームは速度の遅いセッションのしきい値を回避しても、スムーズな 60 FPS エクスペリエンスを損なうマイクロスタッタリングが発生する可能性があります。

どちらもフレーム時間から派生していますが、「速度の遅いセッション」と「フレームレート」は異なる役割を果たします。平均、P90、P99 の FPS 指標は、パフォーマンスの品質と持続可能性を測定し、速度の遅いセッションの指標では見落とされる可能性のある瞬間的な低下や一貫性のないペーシングを検出します。

まとめ

パフォーマンスの最適化を成功させるには、包括的な戦略が必要です。 デベロッパーは、速度の遅いセッションを主要なレーダーとして使用して、パフォーマンスの重大な低下を捉え、平均 FPS、P90、P99 を調べて根本原因を診断し、ゲームプレイの実際のスムーズさを確認する必要があります。これらの指標を統合することで、アプリケーションが一貫して持続可能で優れたユーザー エクスペリエンスを提供できるようになります。

参考情報

高度なプロファイリング手法、Frame Pacing API の実装、エンジン固有の最適化戦略について詳しくは、Android デベロッパーの公式ドキュメントをご覧ください。

  • Android Vitals: 速度の遅いセッション: Google Play が、ユーザー エクスペリエンスに直接 影響する、レンダリングの遅延が続く期間を測定してレポートする方法について説明します。「速度の遅いセッション」は、25% を超えるフレームの速度が遅い(50 ミリ秒以上、20 FPS 相当)ユーザー セッションとして定義されます。
  • Android デベロッパー: ゲームのパフォーマンスを最適化する: Android ゲームの最適化の中心となる ハブをご覧ください。この包括的なガイドでは、ゲームの全体的なパフォーマンスを最大限に高めるためのベスト プラクティス、プロファイリング ツール(APAPerfetto など)について説明します。