マガジン

何もしていないのにCPUが熱くなる:描画の無駄を測る

遊びをつくる

執筆にClaudeを使用しています。

小さな迷路の壁を一か所取り外し、通り道を確かめる模型。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

自作のゲームをタイトル画面のまま放っておいたら、ノートPCのファンが回り始めた。そんな場面を考えてみます。ボタンは押していませんし、アニメーションもありません。画面は静止しているように見えます。それでもCPUが仕事をしているなら、見えないところで何かが動き続けています。 多くの場合の疑わしい点は、画面が変わっていないのに毎フレーム描画をやり直していることです。ブラウザゲームでは、requestAnimationFrame で描画関数を呼び続けるループが定番です。作るときは便利ですが、「状態が変わったときだけ描く」という判断を入れ忘れると、静止中も毎秒数十回の再描画が続きます。 この記事で確かめるのは、描画が走っているか、走っているなら内容が変わっているのかを、自分の手で測る方法です。結果は書きません。測る環境と作品によって答えが変わるため、手順と読み方を示します。

この記事の目次
  1. 無駄は「回っている」と「変わっている」の差にある
  2. 測定の設計書:三つの数字を同じ条件で取る
  3. 結果の読み方と、起こりやすい誤り
  4. 公式作品の設計から、測る場所を探す
  5. 次の行動
  6. 参考資料

無駄は「回っている」と「変わっている」の差にある

描画の周りで起きていることは、三つの層に分けて考えると整理できます。

  1. ループが回っている(毎フレーム、関数が呼ばれる)
  2. 描画関数が実際に呼ばれ、描き直しの処理が走っている
  3. 画面のピクセルが前回と違っている

アクションゲームの戦闘中は、三つとも成立するのが普通です。問題になるのは、1と2が成立しているのに3が成立していない時間です。描いた結果が前回と同じなら、その作業は丸ごと無駄だったことになります。

ここでいう「何もしていない」状態も、先に決めておきます。この記事では次の条件がそろった状態とします。

  • 入力(キー、マウス、タッチ)が一切ない
  • 進行中の演出やアニメーションがない
  • ゲームの状態が変わるタイマーが動いていない

タイトル画面、一時停止中、ターン制ゲームで自分の手番を考えている間などが当てはまります。ここが、無駄を見つけるのに最も向いた場所です。

測定の設計書:三つの数字を同じ条件で取る

問いと準備

問いは一つです。「操作しない状態で、CPU使用率は何もないページと比べて高いか。高いなら、その原因は描画か」。

準備するものは次のとおりです。

  • 測りたいゲームの index.html(自作のもの)
  • 何も書かれていない空のHTMLファイル(基準用)
  • ブラウザのタスクマネージャ、またはOSのCPU監視ツール
  • ブラウザの開発者ツール(パフォーマンスの記録機能)

他のタブとアプリはできるだけ閉じます。ノートPCは、電源接続の有無を毎回そろえてください。

手順

  1. 空のHTMLを開き、操作せず30秒置きます。10秒ごとにそのタブのCPU使用率を読み取ります。これが基準です。
  2. 測りたいゲームを開き、タイトル画面のまま60秒置きます。10秒ごとにCPU使用率を読みます。
  3. 描画関数の先頭に、呼ばれた回数を数える変数を足します。1秒ごとに回数を表示し、0に戻します。
  4. 同じ場所で、今回描こうとする状態が前回と同じかどうかも数えます。状態をまるごと文字列にして前回の文字列と比べる方法が、手軽です。同じだった回数を「同一回数」とします。
  5. 開発者ツールのパフォーマンス記録を、静止状態のまま5秒間とります。フレームを示す帯が途切れず並んでいれば、描画が続いています。

記録の取り方

  • CPU使用率、単位:10秒ごとの読み値、回数:1条件につき3セット、見るもの:基準との差
  • 描画関数の呼び出し、単位:1秒あたり、回数:60秒分を3セット、見るもの:ループが回っているか
  • 同一回数、単位:1秒あたり、回数:同上、見るもの:描画が無駄か
  • パフォーマンス記録、単位:5秒の記録、回数:各条件1回以上、見るもの:描画以外の処理の有無

一度の測定では、バックグラウンドの処理に引きずられて値がぶれます。3セットとって中央値で比べてください。

結果の読み方と、起こりやすい誤り

数字そのものに「何%なら危険」という決まりはありません。見るのは基準との差と、カウンタ同士の関係です。

  • CPUが基準とほぼ同じで、描画の呼び出しが0に近い:静止中は描画が止まっています。この点では健全です。
  • CPUが基準より高く、描画の呼び出しが多く、同一回数も同じくらい多い:求めている状態です。画面が変わらないのに描き続けています。
  • 描画の呼び出しは多いが、同一回数が少ない:画面は実際に変わっています。背景がゆっくり動くなど、意図した演出かもしれません。その場合は、描画を止めるのではなく処理を軽くする方向で考えます。
  • 描画の呼び出しは少ないのにCPUが高い:原因は別にあります。パフォーマンス記録で、描画以外の長い処理(タイマー内の計算、音の生成、DOMの大量更新など)を探してください。

誤りやすい点もいくつかあります。

  • 状態の比較が不正確:オブジェクトを参照で比べると、中身が同じでも毎回「違う」と判定されます。文字列にして比べるか、項目ごとに比べてください。
  • 画面に出ない値が状態に混ざっている:経過秒のように毎フレーム変わる値が状態に入っていると、見た目が同じでも「違う」と数えられます。画面に関係する値だけを比べる必要があります。
  • 開発者ツールの影響:ツールを開いているだけで負荷が変わることがあります。CPU使用率を読むときはツールを閉じ、パフォーマンス記録は別の回に行ってください。
  • 背面のタブ:背面のタブは、ブラウザが描画のタイミングを絞ったり止めたりするのが一般的です。測るタブは前面に出したままにします。
  • 拡張機能の影響:拡張機能が負荷を足している場合があります。拡張機能を無効にしたウィンドウでも測ると、切り分けられます。
  • プラットフォーム上との差:アソバースの投稿作品は、sandbox付きのiframeの中で、メインサイトとは別のオリジンから配信されて動きます。ファイルを直接開いたときと、サイト上で開いたときの数字が違うかもしれません。両方で測って比べると、ゲーム自身の負荷と周りの影響を分けて考えられます。なお、アップロードしたゲームにはSDKが自動で追加されます。差が出たときの原因が何かは、この記事の範囲では断定できません。

公式作品の設計から、測る場所を探す

公式の13作品は、独立したHTMLとして動きます。ここからは確認済みの機能だけを根拠に、「設計から読み取れること」として、どこで測ると効率がよいかを考えます。個々の実装は、ここでは確認できません。測定結果は、各自の環境で作品を開いて確かめてください。

静止する時間が設計に組み込まれている作品

  • こだまの森には、一時停止があります。
  • 小さな軌道は、一時停止から同じ位置で再開できます。
  • かたちのあいだには、時計の一時停止があります。

一時停止中は、ゲームの状態が止まる時間が設計上存在します。だからこそ、その間に描画が止まっているのか、続いているのかを比べる価値があります。「一時停止にして60秒置いた状態」と「進行中の状態」を、同じ手順で測ってみてください。

考える時間が長い作品

  • 潮目のオセロと灯りのチェスは、ひとり対局に「ヒント」と「一手戻す」があります。自分の手番でじっと考えている間は、盤面が変わりません。対局の待機画面は、測定に向いています。オンライン対戦は通信や相手の手番が絡むため、まずはひとり対局で測るのが整理しやすいでしょう。
  • 余白の庭は時間制限がなく、四季と昼夜があります。何も置かずに放置した状態で見た目が変わり続けるのか、止まっているのかは、作品を開いて確かめる部分です。変わる場合は、先ほどの分類で「画面は実際に変わっている」側に入ります。
  • 時計じかけの台所の見習いモードは、時間制限なしです。本番の秒数が進む状態と見習いの待機状態を比べると、描画の続き方の違いが見えるかもしれません。

「動きを抑える」設定との組み合わせ

13作品は、「動きを抑える」設定に対応しています。この設定を入れた状態と切った状態で、同じ画面を同じ手順で測ってみてください。待機中のCPU使用率や描画の呼び出し回数に差があれば、演出が描画負荷に関わっている手がかりになります。差がなければ、待機中の負荷はほかの要因だと分かります。どちらの結果になるかは、実際に測るまで分かりません。

見つけたあとの直し方

描画の無駄が見つかったら、方向性はおおよそ三つです。

  • 状態が変わったことを示す印(フラグ)を持ち、印が立っているフレームだけ描きます。描き終えたら印を下ろします。
  • アニメーションが終わったらループを止めます。入力や状態の変化があったときに、ループを再開します。
  • 一時停止中やタブが背面になったときは、ループを止めます。再開のときに、時間の差が一度に反映されないよう、経過時間の扱いに注意してください。

直したら、最初と同じ条件、同じ手順、同じ回数で測り直します。条件を変えてしまうと、改善したのかどうかが比べられなくなります。

次の行動

まず、自作ゲームのタイトル画面を、空のHTMLと並べて60秒ずつ測ってください。そのうえで、描画関数の呼び出し回数と同一回数を数え、「回っている」と「変わっている」の差を確認します。公式作品の一時停止中や待機画面でも、同じ手順で測ってみてください。

参考資料

  • MDN Web Docs「Window.requestAnimationFrame()」
  • MDN Web Docs「Page Visibility API」
  • Chrome DevTools ドキュメント「パフォーマンス機能リファレンス」