判定の読み方
フレームのインターバル(次のフレームまでの時間)が予算を超えると、そのフレームはヒッチです。予算のデフォルトはディスプレイのフレーム間隔の 1.5 倍で、60 Hz なら 25 ms、120 Hz なら 12.5 ms、165 Hz なら 9.1 ms です。Myaku はフレームからディスプレイを測り、30 フレームごとに測り直し、見えた中でいちばん速いレートを保持し、間引かれた区間は無視します。起動が遅くても予算が倍になることはありません。
ヒッチにはそれぞれ判定が付きます。
{
"frame": 1204,
"intervalMs": 79,
"budgetMs": 9.1,
"cause": "script",
"confidence": "high",
"summary": "Frame 1204 took 79 ms (budget 9.1 ms). 80 ms was script: `spawnWave` in src/enemies.ts:88.",
"hint": "This ran inside the game loop. Profile the function in the Performance panel, or spread the work over several frames.",
"where": { "source": "http://localhost:5173/src/enemies.ts", "fn": "spawnWave", "line": 88, "char": -1 }
}confidence は、直接の証拠が原因を示すときは high、強く示唆されるときは medium、答えではなく確かめるべき手がかりのときは low です。判定には evidence も含まれます。フレームのコードの時間、描画、アップロードとそのバイト数、コンパイル、ヒープの減少、レイアウトの時間、スクリプト、スパンです。
Myaku は次の順に原因をチェックし、最初に当てはまったところで止まります。
hidden
フレームの途中でタブがバックグラウンドに回りました。ゲームの問題ではありません。長い空白のあとにゲームが動き続けるべきでないなら、visibilitychange で一時停止してください。
throttled
ゲームがほとんど何もしておらず、ブラウザも長い処理を報告していないのに、遅いフレームが続いた状態です。ウィンドウが隠れていた、最小化されていた、省電力モードだったなどの理由で、ブラウザがフレームを間引いていました。計測するときは前面に出してください。
compile
プレイ中にシェーダーがコンパイルされたか、プログラムがリンクされました。マテリアルやエフェクトを初めて使うときによく起きます。シェーダーはロード中にウォームアップしておきましょう。
upload
1 フレームで 1 MB 以上が GPU に送られました。新しいテクスチャ、canvas テクスチャ(テキストがよくある犯人です)、大きなバッファなどです。アップロードはロード時に済ませるか複数フレームに分散し、テクスチャは使い回しましょう。
script
ゲームのコードの実行が長引きました。Chromium では、Long Animation Frames のエントリーが関数とファイルを示します。遅いコードがフレームコールバックなら、Myaku はゲームがそれを登録した場所を指します。
エンジンがループを持っている場合、遅いコールバックはエンジンのステップ関数なので、判定はエンジンのファイルを示します。そのときは Myaku のエンジンのスパンが、update と render のどちらが時間を使ったか、Phaser ならどのシーンかを教えてくれます。
原因を特定できない場合(ほかのブラウザ)でも、コードが予算の大半を使ったフレームは script の判定になり、時間のかかったスパンが示されます。
layout
スタイルの再計算とレイアウトがフレームの大きな割合を占めました。canvas の上の DOM を毎フレーム更新していないか、スタイルを変えた直後にレイアウトを読む(offsetWidth、getBoundingClientRect)コードがないかを探してください。
gc
ゲームのコードがほぼ暇なあいだにヒープが 1 MB 以上縮みました。ガベージコレクションです。フレームあたりのメモリ確保を減らしましょう。ベクトルや配列は使い回し(プール)、ホットループではクロージャや map/filter を避けます。Chromium 専用で、ブラウザがヒープを十分細かく報告するときだけ有効です。Myaku はそれを確かめ、GC が見えないときは unknown の判定でそう伝えます。
gpu
myaku record --trace のときだけ出ます。ゲームのコードは速かったのに、Chrome の GPU プロセスがフレームのあいだずっと忙しく、ゲームの canvas を待っていました。しかも直前のフレームでもゲームが GPU を忙しくさせていました。フレームあたりの描画を減らしましょう。方法は、ピクセルを減らすこと(解像度を下げる・フルスクリーンのパスを減らす)、シェーダーを軽くすること、オーバードローを減らすことです。GPU の負荷が軽いときの単発のストールは unknown のままで、そのサマリーにはドライバー、OS、ほかのアプリがおそらく原因だと書かれます。
compositor
myaku record --trace のときだけ出ます。ゲームのコードは速かったのに、Chrome のコンポジターが canvas を待つのではなく、ページのレイヤーの描画に時間を使いました。よくある原因は、ブラー、フィルター、トランスフォーム、不透明度のアニメーションを使った DOM を canvas の上に重ねていることです。合成レイヤーを減らすか、canvas をページで唯一の大きな要素にしてください。
unknown
ゲームのコードは速く、ほかに時間を説明できるものがありません。GPU の仕事、コンポジター、ほかのアプリであることが多く、myaku record --trace でどれかを見分けられます。ドローコールが多い(2,000 超)ときは、ヒントがバッチ処理を提案します。単発の unknown フレームは、たいていゲームの手の届かないところが原因です。
予算内のフレーム
遅くなかったフレームをクリックしたり explain したりすると、そのフレームの時間と予算つきで ok が返ります。