Blazing Rust
在保持行為不變的前提下,改善測量到的效能。保留最簡單的變更,使其能在代表性輸入上產生可重複的增益。
在編輯前先測量
- 識別工作負載、目標指標和正確性約束。閱讀熱路徑及其呼叫者。尊重專案的工具鏈、最低支援的 Rust 版本、功能特性和部署目標。請求解釋會授權測量和剖析,而非編輯。
- 使用專案的最佳化生產設定檔(通常是
release)擷取基準。記錄輸入、確切指令、工具鏈、旗標、CPU 和執行緒數。使用實際的輸入大小和分佈,包括小型和不利情況。 - 找出限制效能的瓶頸。視情況分析 CPU 時間、分配、I/O 或鎖等待。對於非同步停滯,請使用具執行時期感知的追蹤來檢查任務排程和佇列增長。優先使用現有工具;剖析章節列舉了常見工具以及如何在發行版本中保留符號。如果無法進行剖析,請使用目標測量並說明證據的限制。
- 提出一個假設並進行一項可測量的變更。執行針對性的正確性測試並重複相同的基準測試。在聲稱有使用者可見的改進之前,請驗證完整工作負載下的結果。
- 保留有支援的增益。僅撤銷不成功的編輯,保留無關的工作。當達到目標或進一步的變更缺乏證據時停止。
讓基準測試可信
- 將設定、編譯、輸入生成和程序啟動與操作分開,除非它們屬於目標指標。消耗結果。對於微基準測試,請使用基準測試函式庫的最佳化屏障或
std::hint::black_box作用於輸入和輸出。這些屏障是盡力而為的,因此請檢查不合理的結果。 - 比較等效的工作和輸出。保持工具鏈、設定檔、功能特性、分配器、CPU 設定和執行緒數固定,除非其中一個是要測試的變數。在測量穩定狀態時進行預熱。在相關時單獨測量冷啟動。
- 重複執行並報告樣本數、中位數和變異性。在漂移重要時交替執行基準和候選程式。在雜訊範圍內的差異不能證明勝出。
- 將指標與任務匹配。對於服務,請在指定的負載下測量 p95/p99 延遲、吞吐量、錯誤和資源使用。檢查延遲降低是否不是因為丟棄工作或佇列增長所致。
- 重用現有的基準測試。當新邏輯需要時,新增一個小的回歸測試用例。未經任務授權,請勿安裝工具、新增依賴項或變更建置設定。切勿發明測量方式。
根據證據選擇變更
從不必要的工作和演算法開始。僅當剩餘的瓶頸需要時,才考慮較低層級的變更。當測量到的瓶頸需要更多細節時,請閱讀技術指南的對應章節。
| 觀察到的成本 | 候選變更與檢查事項 |
|---|---|
| 重複掃描或計算 | 改進演算法或集合選擇。移除重複的解析、排序、序列化和查詢。如果快取有幫助,請考慮快取失效和記憶體。 |
| 分配或複製 | 借用 &str 和切片,移動擁有所有權的值,重用緩衝區,並保留可信的容量。在替換已分配的值時嘗試 clone_from。避免中間集合。對於共享的 handle,clone 可能很便宜,因此請測量其成本。 |
| 集合查詢 | 使用借用鍵和條目 API,以避免重複工作。當存取模式適合時,比較密集向量或排序資料。在變更 hasher 時,為不受信任的鍵保留碰撞攻擊防護。 |
| 排序或移除 | 使用 select_nth_unstable 進行選擇,當相等元素的順序無關時使用 sort_unstable,並對昂貴的鍵使用 sort_by_cached_key。僅在元素順序無關時使用 swap_remove。 |
| 快取未命中或大值 | 比較結構陣列與陣列結構。檢查 size_of、align_of 和快取未命中。內聯儲存可能會增加複製。考慮對罕見的大型枚舉有效載荷進行 Boxing,並考慮分配和間接定址。 |
| 小型熱呼叫或迴圈 | 偏好普通迭代。透過切片、迭代或範圍斷言幫助編譯器移除邊界檢查。在內聯或展開之前檢查最佳化後的組合語言。測試空輸入、尾部、溢位和程式碼大小。 |
| 文字搜尋 | 重用編譯後的正規表達式,並僅請求所需的匹配資訊。當編碼語義允許時,比較專門的位元組搜尋。避免在熱迴圈內重建搜尋狀態。 |
| 可向量化的計算 | 在明確使用 SIMD 之前檢查自動向量化。檢查產生的程式碼。在必要時保護目標特定的指令,並保留純量後備方案。測試尾部和代表性的 CPU。保持對齊、邊界和數值行為。 |
| 獨立 CPU 工作 | 比較序列執行與有界的並行。測量排程成本、爭用、頻寬、執行緒數和總 CPU 消耗。僅在開銷重要時調整任務大小。保留歸約語意。 |
| I/O 或非同步停滯 | 重用行緩衝區,批次處理小型 I/O,並處理 flush 錯誤。保留延遲、換行處理和持久性。將阻塞或大量 CPU 工作保留在非同步工作者之外。限制並行和佇列。保留順序、背壓和取消。 |
| 建置或程式碼生成限制 | 比較現有設定與 thin LTO。在合併之前分別測試 fat LTO 和 codegen-units = 1。包含建置時間和二進位檔大小。僅在部署硬體允許時使用 CPU 特定的旗標。 |
保持正確性
保持公有 API、錯誤處理、驗證、排序、序列化和 FFI 合約不變。保留整數溢位和浮點數行為。列舉表示法或變體順序可能會改變佈局和鑑別子;兩者都不能保證更小或更快的列舉。
偏好安全 Rust 和現有依賴項。引入不安全程式碼需要測量到的需求、明確的安全性不變量以及針對性的測試。在支援且相關的情況下使用 Miri 或 sanitizers。切勿為了基準測試速度而犧牲驗證或健全性,也不要將通過測試視為健全性的證明。
報告結果
說明瓶頸、變更以及保留或復原的決定。包含可重現的指令、前後結果及變異性、相關的分配或記憶體數據、正確性檢查和權衡取捨。區分多核心 wall-clock 增益與單核心效率。提及未經測量的聲明和未檢查的平台。