Gas 用量剖析 (Gas Profiling)
瞭解 gas 消耗情況有助於最佳化 Move 程式碼,並估算交易成本。Move 測試框架提供內建工具,可在測試執行期間測量 gas 用量。此外,也提供特殊工具 sui analyze-trace,可更徹底地分析 gas 用量。
-s 顯示的統計資料僅反映計算單位,不包含儲存 成本。此外,編譯器計算單位不會直接對應至實際鏈上 gas 費用; 它們顯示的是相對計算複雜度,適合用於相互比較不同實作。 若要取得實際 gas 成本,請將套件發布至 testnet 並測量真實交易。
簡易測量:測試統計資料 (Simple Measurement: Test Statistics)
搭配 sui move test 使用 -s 或 --statistics 旗標,即可查看每個測試的執行時間和 gas 消耗量:
sui move test -s
輸出會顯示包含三個欄位的表格:
Test Statistics:
┌────────────────────────────────────────────────────────┬────────────┬───────────────────────────┐
│ Test Name │ Time │ Gas Used │
├────────────────────────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::my_module::test_simple_operation │ 0.006 │ 998001 │
├────────────────────────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::my_module::test_complex_operation │ 0.007 │ 998068 │
├────────────────────────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::my_module::test_with_objects │ 0.006 │ 998001 │
└────────────────────────────────────────────────────────┴────────────┴───────────────────────────┘
Test result: OK. Total tests: 3; passed: 3; failed: 0
- 測試名稱:測試函式的完整限定名稱
- 時間:以秒為單位的執行時間
- 已使用的 Gas:測試消耗的 gas 單位
每個測試的總計都包含一筆很大的固定基本成本;即使空白測試也會顯示約 998000 個 gas 單位。比較測試時,應查看總計之間的差異,而非 絕對值。
CSV 輸出 (CSV Output)
若要進行程式化分析或匯入試算表,請使用 csv 選項:
sui move test -s csv
這會產生以逗號分隔的輸出:
name,nanos,gas
book::my_module::test_simple_operation,5992125,998001
book::my_module::test_complex_operation,6870583,998068
book::my_module::test_with_objects,6022917,998001
時間單位為奈秒,可在比較相似操作時進行更精確的測量。
Gas 限制 (Gas Limits)
使用 -i 或 --gas-limit 旗標,可為測試設定最大 gas 預算。超過此限制的測試 將會逾時:
sui move test -i 1000
此限制以內部執行 gas 單位衡量,與 Gas Used 欄位中的值並非一對一對應; 顯示約 998000 gas 的簡單測試,在限制為 1000 時仍可輕鬆 通過。
測試超出 gas 限制時的輸出:
[ TIMEOUT ] book::my_module::test_complex_operation
[ PASS ] book::my_module::test_simple_operation
[ PASS ] book::my_module::test_with_objects
Test failures:
Failures in book::my_module:
┌── test_complex_operation ──────
│ Test timed out
└──────────────────
Test result: FAILED. Total tests: 3; passed: 2; failed: 1
這適用於:
- 識別高成本操作:找出消耗超出預期 gas 數量的測試
- 強制實施 gas 預算:確保關鍵路徑維持在可接受的限制內
- 測試 gas 耗盡:驗證你的程式碼能正確處理 gas 耗盡情境(請參閱 預期失敗)
比較實作 (Comparing Implementations)
使用統計資料比較不同實作之間的 gas 消耗量:
module book::comparison;
use std::unit_test::assert_eq;
public fun sum_loop(n: u64): u64 {
let mut sum = 0;
n.do!(|i| sum = sum + i);
sum
}
public fun sum_formula(n: u64): u64 {
n * (n - 1) / 2
}
#[test]
fun test_sum_loop() {
let result = sum_loop(1000);
assert_eq!(result, 499500);
}
#[test]
fun test_sum_formula() {
let result = sum_formula(1000);
assert_eq!(result, 499500);
}
搭配統計資料執行可顯示差異:
sui move test comparison -s
┌────────────────────────────────────┬────────────┬───────────────────────────┐
│ Test Name │ Time │ Gas Used │
├────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::comparison::test_sum_loop │ 0.003 │ 998078 │
├────────────────────────────────────┼────────────┼───────────────────────────┤
│ book::comparison::test_sum_formula │ 0.001 │ 998001 │
└────────────────────────────────────┴────────────┴───────────────────────────┘
迴圈在基本成本之外需額外花費 77 個 gas 單位,而公式沒有增加可測量的成本。
追蹤分析 (Trace Analysis)
若要進行更深入的剖析,可以從測試產生執行追蹤,並使用 speedscope 將其視覺化。這會顯示依函式 呼叫細分的 gas 消耗火焰圖,讓你能輕易找出 gas 的確切花費位置。
步驟 1:產生追蹤 (Step 1: Generate Traces)
使用 --trace 旗標執行測試,以產生追蹤文件:
sui move test --trace
追蹤文件會寫入套件根目錄中的 traces/ 目錄(位於 Move.toml 旁)。
步驟 2:產生 Gas 設定檔 (Step 2: Generate a Gas Profile)
使用 sui analyze-trace 的 gas-profile 子命令,將追蹤轉換為設定檔:
sui analyze-trace -p traces/<TRACE_FILE> gas-profile
這會在目前目錄輸出 gas_profile_<TRACE_FILE>.json 文件。你可以使用 -o 旗標指定不同的輸出目錄;該旗標必須位於 gas-profile 子命令之前:
sui analyze-trace -p traces/<TRACE_FILE> -o ./profiles gas-profile
步驟 3:使用 Speedscope 視覺化 (Step 3: Visualize with Speedscope)
安裝 speedscope 並開啟設定檔:
npm install -g speedscope
speedscope gas_profile_<TRACE_FILE>.json
Speedscope 提供三種檢視方式:
- 時間順序:依呼叫順序由左至右顯示呼叫堆疊。長條寬度對應 gas 消耗量。
- 左重:將重複呼叫分組,並依總 gas 消耗量排序,適合用於 找出成本最高的程式碼路徑。
- 三明治:列出每個函式的 gas 消耗量,包含總計(含被呼叫函式)與 自身(僅函式本身)欄位。