Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

效能分析器

你在 Godot 裡執行遊戲測試,內容越來越完整,感覺快可以發行了。

但突然你打開技能樹時,遊戲卡住了,像放投影片一樣慢。這種體驗不能接受。是技能樹排版、UI 還是繪圖的問題?

你可以盲目優化所有東西反覆測試,但更聰明的做法是用 Godot 的效能分析器來定位問題。

效能分析器總覽

在下方 除錯器 面板點選 效能分析 分頁可開啟分析器。

../../../_images/profiler.png

Godot 的效能分析器預設不會自動啟動,因為分析需即時監控所有遊戲活動並回報除錯器,會影響效能。

要開始分析,先執行遊戲,再切回編輯器,在 效能分析 分頁左上角點選 開始。你也可勾選 自動開始,讓下次執行專案自動啟動分析。注意:自動開始設定不會跨編輯器啟動保存。

備註

目前效能分析器不支援 C# 腳本。如需分析 C# 腳本,可使用 JetBrains Rider 與 JetBrains dotTrace(需安裝 Godot 支援外掛)。

隨時可點選 清除 按鈕重置分析資料。可用 測量 下拉選單切換分析項目,面板與圖表也會隨之更新。

分析數據說明

分析器介面左側為函式清單,右側為效能圖表。

主要分析項目為:幀時間、物理幀、閒置時間、物理時間。

  • 幀時間 指 Godot 執行一幀所有邏輯(自物理至繪圖)所需時間。

  • 物理幀 是 Godot 每次物理更新間隔的時間。理想情況下,幀時間由你設定,預設為 16.66 毫秒(對應 60FPS),可作為計算其他分析項目的基準。

  • 閒置時間 指 Godot 更新非物理邏輯(如 _process 內的程式碼、設為閒置更新的計時器或相機)所花費的時間。

  • 物理時間 是 Godot 執行所有物理相關任務(如 _physics_process 或設為物理更新的節點)所需時間。

備註

幀時間 也包含繪圖耗時。若你發現遊戲不明原因卡頓,但物理與腳本都執行很快,問題可能出在粒子或特效!

預設情況下,Godot 會監控幀時間與物理時間,讓你了解每幀相對於設定目標 FPS 的耗時。你可用左側勾選框啟用/停用任意分析函式。清單下方還有 Physics 2D、Physics、Audio 等系統監控,最下方則是你的腳本函式。

點擊圖表可切換左側顯示的幀資訊。右上角還有幀數計數器,可精細調整檢視的幀。

分析範圍與視窗

可用 測量 下拉選單切換分析項目。預設為幀時間(毫秒),平均時間則為某函式多次執行的平均耗時。例如某函式執行五次共 0.05 毫秒,平均為 0.01 毫秒。

若不需精確毫秒數,只重視佔用比例,可改用百分比模式。幀% 表示相對於整體幀時間,物理% 則為物理時間佔比。

最後一項是分析範圍。 Inclusive (含巢狀)會將所有巢狀呼叫一併計算在內,例如:

../../../_images/split_curve.png

get_neighborsfind_nearest_neighbormove_subject 都耗時較久,乍看之下可能誤以為三者都很慢。

但切換為 Self 模式後,只計算函式本身內容,不含呼叫他人函式的耗時。

../../../_images/self_curve.png

此時 get_neighborsmove_subject 耗時大幅下降,代表它們大部分時間都在等其它函式執行,真正耗時的是 find_nearest_neighbor

用分析器找出慢速程式碼

分析慢速程式碼時,執行遊戲並觀察效能圖表。遇到幀耗時異常飆高時,可點擊圖表暫停遊戲,並將 _Frame #_ 調至異常起點。可能需來回瀏覽不同幀與函式,才能找到根本原因。

於腳本函式區域,勾選欲監控的函式,找出耗時者。這些即是你需審查與優化的重點。

用微秒單位手動測量

若你的函式很複雜,可能很難直接判斷哪個區塊需優化。是數學運算慢,還是資料讀取方式有問題?還是迴圈、條件判斷?

你可用暫時性測量法:用 Time 物件的 get_ticks_msec (毫秒)及 get_ticks_usec (微秒),在程式區塊前後計算耗時。

這兩個函式都會回傳自引擎啟動以來的累計時間(毫秒/微秒)。

將程式區塊前後分別記錄微秒數,相減即為該區塊的執行時間。

# Measuring the time it takes for worker_function() to run
var start = Time.get_ticks_usec()
worker_function()
var end = Time.get_ticks_usec()
var worker_time = (end-start)/1000000.0

# Measuring the time spent running a calculation over each element of an array
start = Time.get_ticks_usec()
for calc in calculations:
    result = pow(2, calc.power) * calc.product
end = Time.get_ticks_usec()
var loop_time = (end-start)/1000000.0

print("Worker time: %s\nLoop time: %s" % [worker_time, loop_time])

當你成為有經驗的工程師後,這種測量法會越來越少用,你會直接知道哪些區塊容易慢,哪些語法(如迴圈、分支)需注意。這些判斷力都來自實際測量與資料研究。

善用效能分析器與 tick 測量法,你就能有效找出需優化的程式碼區段。