效能分析器
你在 Godot 裡執行遊戲測試,內容越來越完整,感覺快可以發行了。
但突然你打開技能樹時,遊戲卡住了,像放投影片一樣慢。這種體驗不能接受。是技能樹排版、UI 還是繪圖的問題?
你可以盲目優化所有東西反覆測試,但更聰明的做法是用 Godot 的效能分析器來定位問題。
效能分析器總覽
在下方 除錯器 面板點選 效能分析 分頁可開啟分析器。
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 (含巢狀)會將所有巢狀呼叫一併計算在內,例如:
get_neighbors、find_nearest_neighbor、move_subject 都耗時較久,乍看之下可能誤以為三者都很慢。
但切換為 Self 模式後,只計算函式本身內容,不含呼叫他人函式的耗時。
此時 get_neighbors 與 move_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 測量法,你就能有效找出需優化的程式碼區段。