使用 about:tracing 旗標分析 WebGL 遊戲

Lilli Thompson
Lilli Thompson

如果無法評估,就無法改善。

凱文

為了讓 HTML5 遊戲執行速度更快,您必須先找出效能瓶頸,但這並不容易。評估每秒影格數 (FPS) 資料只是第一步,但如果您想掌握全局,就必須熟悉 Chrome 活動的細微差異。

關於:追蹤工具可提供深入分析資料,幫助您避免因思索提升效能而缺少問題之替代方案,但這基本上就是出於意料之外的猜測。這麼做可省下大量時間和精力,讓您更清楚瞭解 Chrome 在每個頁框的執行動作,並利用這些資訊改進遊戲。

Chrome 的 about:Chrome 的許多功能都可以讓您直接追蹤,因此您不必進行任何手動操作,仍可使用 about:trac 追蹤應用程式效能。(詳情請參閱後續章節,瞭解如何手動檢測 JS)。

如要查看追蹤記錄檢視畫面,請輸入「about:tracing」。貼到 Chrome 的網址列

Chrome 網址列
輸入「about:tracing」插入 Chrome 的網址列

透過追蹤工具,您可以開始錄製、執行遊戲幾秒鐘,然後查看追蹤資料。資料的範例如下:

簡易追蹤記錄結果
簡單的追蹤記錄結果

沒錯,這真的令人困惑。我們來談談讀取方式

每列代表一個正在進行剖析的程序,右軸表示時間,每個彩色方塊都是檢測設備呼叫。某些資源會有不同的資料列。對遊戲剖析作業最感興趣的項目為 CrGpuMain,其中顯示圖形處理器 (GPU) 和 CrRendererMain,在追蹤期間,每個追蹤記錄都包含每個開啟分頁的 CrRendererMain 行 (包括 about:tracing 分頁本身)。

讀取追蹤記錄資料時,第一步是決定與遊戲對應的 CrRendererMain 資料列。

醒目顯示簡易追蹤記錄結果
醒目顯示的簡易追蹤記錄結果

在這個範例中,兩位候選人為:2216 和 6516。可惜的是,目前沒有完善的選擇應用程式方式,除了尋找定期更新的行 (或者您已使用追蹤點手動檢測程式碼,尋找含有追蹤記錄資料的行)。在這個例子中,6516 的執行頻率是執行與更新頻率有關的主要迴圈。如果您在開始追蹤記錄前關閉所有其他分頁,要找出正確的 CrRendererMain 就會比較容易。但除了遊戲,其他程序可能仍有 CrRendererMain 資料列。

正在尋找影格

在追蹤工具中找出正確的遊戲資料列後,下一步就是找出主要迴圈。主迴圈在追蹤資料中看起來像重複模式。您可以使用 W、A、S、D 鍵 (A 和 D 鍵) 來左右移動 (來回移動),W 和 S 鍵則可放大和縮小資料。如果遊戲以 60Hz 為單位執行,主要迴圈應為每 16 毫秒重複一次的模式。

執行框架似乎有三個
執行框架是三個

找出遊戲的心跳後,您就可以深入瞭解程式碼在每個影格中執行的動作。使用 W、A、S、D 來放大檢視,直到您可以閱讀功能方塊中的文字。

深入執行執行影格
深入瞭解執行影格

這組方塊會顯示一系列函式呼叫,每個呼叫都以一個顏色方塊表示。上面的方塊會呼叫每個函式,因此在這個例子中,您會看到 MessageLoop::RunTask 稱為 RenderWidget::OnSwapBuffersComplete,而它叫做 RenderWidget::DoDeferredUpdate,依此類推。讀取這項資料,可讓您全盤掌握每次執行作業所花費的時間和所需時間。

但這裡有一點黏著度。about:tracing 所公開的資訊為 Chrome 原始碼的原始函式呼叫。您可以從名稱中推測每個函式的用途,但資訊未必會讓使用者一目瞭然。瞭解影格的整體流程確實很有幫助,但您需要更清晰易讀的資訊,才能確實瞭解影格本身。

新增追蹤記錄標記

幸好,您可以在程式碼中新增手動檢測方法,建立追蹤記錄資料:console.timeconsole.timeEnd

console.time("update");
update();
console.timeEnd("update");
console.time("render");
update();
console.timeEnd("render");

上述程式碼會在追蹤檢視畫面名稱中以指定標記建立新方塊,因此如果您重新執行應用程式,就會看到「更新」和「顯示」方塊,顯示每個廣告代碼開始和結束呼叫所經過的時間。

手動新增的標記
手動新增的標記

您可以運用這個方法,建立人類可讀的追蹤資料,在程式碼中追蹤熱點。

還是 CPU?

使用硬體加速圖形時,您在剖析時最常提出的問題之一是:這個程式碼是否受到 GPU 限制?在每個影格中,您需要在 GPU 及 CPU 上執行某些邏輯轉譯作業;為了瞭解導致遊戲速度緩慢的原因,您需要查看兩種資源之間的工作平衡。

首先,在追蹤記錄檢視畫面中找出名為 CrGPUMain 的線條,這代表 GPU 在特定時間是否忙碌。

GPU 和 CPU 追蹤記錄

您可以看到遊戲的每個影格都會在 CrRendererMain 和 GPU 上執行 CPU。上述追蹤記錄相當簡單的用途,其中 CPU 和 GPU 都處於閒置狀態,因此每個 16 毫秒影格中的大部分時間都處於閒置狀態。

當您的遊戲運作速度緩慢,而且您無法確定哪個資源最大化時,追蹤檢視畫面就相當實用。瞭解 GPU 和 CPU 行間的關聯是偵錯的關鍵。採用與先前相同的範例,但在更新迴圈中增加一些額外工作。

console.time("update");
doExtraWork();
update(Math.min(50, now - time));
console.timeEnd("update");

console.time("render");
render();
console.timeEnd("render");

現在,您會看到如下所示的追蹤記錄:

GPU 和 CPU 追蹤記錄

這個追蹤記錄提供了什麼資訊?我們可以看見顯示影格大約需要 2270 毫秒至 2320 毫秒,也就是每個影格大約需要 50 毫秒 (20 Hz 的畫面更新率)。您可在更新方塊旁看到代表轉譯功能的彩色方塊和色塊,但影格本身都是以更新方式呈現。

與 CPU 中的內容相比,您可以看到 GPU 在大多數影格上都處於閒置狀態。如要最佳化這段程式碼,請尋找可在著色器程式碼中完成的作業,並將這些作業移至 GPU,充分運用資源。

如果著色器程式碼本身速度緩慢,但 GPU 過載,該怎麼辦?如果從 CPU 移除不必要的工作,改為在片段著色器程式碼中新增工作,會發生什麼事。以下是不需要昂貴的片段著色器:

#ifdef GL_ES
precision highp float;
#endif
void main(void) {
  for(int i=0; i<9999; i++) {
    gl_FragColor = vec4(1.0, 0, 0, 1.0);
  }
}

使用該著色器的程式碼追蹤記錄會是什麼樣子?

使用慢速 GPU 程式碼時的 GPU 和 CPU 追蹤記錄
使用慢速 GPU 程式碼時的 GPU 和 CPU 追蹤記錄

再次注意影格的時間長度。這裡的重複模式從 2750 毫秒到 2950 毫秒,持續時間是 200 毫秒 (約 5Hz)。CrRendererMain 行幾乎完全空白,意味著 CPU 在大部分時間處於閒置狀態,而 GPU 超載。這代表著色器過重。

如果您無法確實掌握造成影格速率低落的具體原因,可以觀察 5 Hz 更新作業的發生原因,而想嘗試對遊戲程式碼進行最佳化或移除遊戲邏輯。在這種情況下,這種做法絕對沒有問題,因為遊戲迴圈中的邏輯並不是耗費時間。事實上,這項追蹤記錄顯示執行更多 CPU 工作,基本上是「免費」是因為 CPU 會在閒置狀態下等待,因此,多餘的工作就不會影響影格所需的時間。

實際範例

現在,我們來看看實際遊戲中的追蹤資料是什麼樣子。針對採用開放網路技術所建構的遊戲,其中一項酷炫之處,就是您可以看到喜愛產品中的動靜。如要測試剖析工具,請在 Chrome 線上應用程式商店中挑選喜愛的 WebGL 標題,並使用「 about:tracing」。這就是從優良 WebGL 遊戲競速選手取得的追蹤記錄範例。

追蹤真實遊戲
模擬真實遊戲

看來每個影格大約需要 20 毫秒,也就是影格速率約為 50 FPS。您可以看到工作在 CPU 和 GPU 之間達到平衡,但 GPU 則是需求最多的資源。若想看看分析 WebGL 遊戲的實際實例,可以試試使用 WebGL 建構的部分 Chrome 線上應用程式商店遊戲,包括:

結論

如果希望遊戲以 60Hz 的速度執行,所有作業都必須搭配 16 毫秒的 CPU 和 16 毫秒的 GPU 時間。兩項資源可並行運用,並可在兩者之間切換作業以提高成效。Chrome 的關於:

後續步驟

除了 GPU,還可以追蹤 Chrome 執行階段的其他部分。Chrome Canary 是 Chrome 的早期階段版本,可用來追蹤 IO、IndexedDB 和其他多項活動。如要進一步瞭解追蹤事件目前的狀態,請參閱這篇 Chromium 文章

如果您是網頁遊戲開發人員,請務必觀看以下影片。這是 Google 遊戲開發人員服務代表團隊 2012 年遊戲開發人員服務代表團隊的簡報,內容旨在分享 Chrome 遊戲的效能最佳化相關資訊: