Bazel 在建構過程中會進行許多複雜的工作,而且其中有許多不同,可能會影響建構效能。本頁面會嘗試將部分 Bazel 概念對應至這些建構對效能的影響。在本文中,我們並未參考一些範例,說明如何透過擷取指標來偵測建構效能問題,以及如何加以修正。因此,我們希望您在建構建構效能迴歸時可運用這些概念。
清理與漸進式建構
簡潔的建構作業是從頭開始建構的建構作業,漸進式建構作業會重複使用部分已完成的工作。
建議您分別查看簡潔和漸進式建構作業,特別是當您收集 / 匯總依附 Bazel 快取狀態的指標 (例如建構要求大小指標) 時,這兩個指標代表兩個不同的使用者體驗。與從冷快取開始啟動清理作業相比,從頭開始啟動清理作業需要較長的時間,因為開發人員在處理程式碼疊代時,執行頻率會較快 (通常快取速度更快,這是因為快取通常較暖)。
您可以使用 BEP 中的 CumulativeMetrics.num_analyses
欄位將建構作業分類。如果 num_analyses <= 1
是簡潔的建構;否則,我們大致可以將其歸類為漸進式建構,使用者可以切換至不同標記或不同的目標,以有效率地執行建構作業。任何更嚴謹的增量定義可能必須採用經驗法則的形式,例如查看已載入的套件數量 (PackageMetrics.packages_loaded
)。
確定性建構指標做為建構效能的 Proxy
由於某些指標具有不確定性特性 (例如 Bazel 的遠端 CPU 時間或遠端叢集的佇列時間),因此難以測量建構效能。因此,使用確定性指標做為 Bazel 處理的量量,這對於 Bazel 所做的工作量,也會影響其效能。
建構要求的大小可能會對建構效能產生重大影響。較大型的建構可能代表在建構和建構建構圖時有更多工作。由於建構作業的新增/建立越多,建構的自然成長也自然而然,開發作業自然而然會增加,因此建構的複雜性也會越來越高。
我們可以將這個問題分成不同的建構階段,並使用以下指標做為各階段作業的 Proxy 指標:
PackageMetrics.packages_loaded
:已成功載入的套件數量。這裡的迴歸代表需要完成更多工作,以便在讀取階段中讀取及剖析每個額外的 BUILD 檔案。TargetMetrics.targets_configured
:代表建構中設定的目標和方面數量。迴歸代表建構及掃遍已設定的目標圖形。- 這通常是因為新增依附元件,且需要建構其轉換性封閉圖。
- 使用 cquery 找出可能新增依附元件的位置。
ActionSummary.actions_created
:代表建構中建立的動作,迴歸代表建構動作圖的更多工作。請注意,這也包含可能尚未執行的未使用動作。- 使用 aquery 對迴歸進行偵錯;建議您先使用
--output=summary
開始,再進一步使用--skyframe_state
。
- 使用 aquery 對迴歸進行偵錯;建議您先使用
ActionSummary.actions_executed
:執行的動作數,迴歸則代表執行這些動作的更多工作。- BEP 會寫入動作統計資料
ActionData
,顯示執行次數最多的動作類型。根據預設,系統會收集前 20 個動作類型,但您可以傳入--experimental_record_metrics_for_all_mnemonics
來收集執行的所有動作類型的資料。 - 這應該有助於您瞭解已執行哪些類型的動作 (另外)。
- BEP 會寫入動作統計資料
BuildGraphSummary.outputArtifactCount
:執行動作所建立的構件數量。- 如果執行的動作數量並未增加,那麼規則實作可能已變更。
這些指標都受到本機快取的狀態影響,因此您應確保從這些指標擷取的建構都是乾淨的建構。
我們注意到,這些指標中的任何迴歸也可能造成在牆壁時間、CPU 時間和記憶體用量中的迴歸。
使用本機資源
Bazel 會在本機本機電腦上耗用各種資源 (用於分析建構圖表和執行執行作業,以及執行本機動作),這可能會影響機器在建構期間的效能 / 可用性,以及其他工作。
使用時間
或許最容易受噪音影響的指標 (可能從建構到建構之間有很大的差異) 為時間,尤其是壁時間、CPU 時間和系統時間。您可以使用 bazel-bench 來取得這些指標的基準,並擁有足夠的 --runs
即可增加測量的統計顯著程度。
實際時間是指經過了的實際時間。
- 如果只有牆壁時間迴歸,建議您收集 JSON 追蹤記錄設定檔並尋找差異。否則,調查其他迴歸指標可能會比較有效率地影響,因此對調查時間造成影響。
CPU 時間是執行使用者程式碼的 CPU 所花費的時間。
- 如果 CPU 作業時間會在兩個專案修訂版本之間迴歸,建議您收集 Starlark CPU 設定檔。建議您也使用
--nobuild
將建構作業限制為分析階段,因為這是大部分 CPU 繁重工作的地方。
- 如果 CPU 作業時間會在兩個專案修訂版本之間迴歸,建議您收集 Starlark CPU 設定檔。建議您也使用
系統時間是指核心的 CPU 使用時間。
- 如果系統時間迴歸,則當 Bazel 從檔案系統讀取檔案時,主要與 I/O 有關。
系統層級的負載剖析
使用 Bazel 6.0 中導入的 --experimental_collect_load_average_in_profiler
標記,JSON 追蹤記錄分析器會在叫用期間收集系統負載平均值。
圖 1. 包含系統負載平均值的設定檔。
Bazel 叫用期間的負載量偏高,可能代表 Bazel 為您的機器平行安排許多本機動作。建議您查看 --local_cpu_resources
和 --local_ram_resources
的相關調整,特別是在容器環境中 (至少合併至 #16512)。
監控 Bazel 記憶體用量
有兩個主要來源可取得 Bazel 的記憶體使用量:Bazel info
和 BEP。
bazel info used-heap-size-after-gc
:呼叫System.gc()
後已使用的記憶體量 (以位元組為單位)。BEP 的
MemoryMetrics.peak_post_gc_heap_size
:GC 之後的尖峰 JVM 堆積大小 (以位元組為單位,需要設定--memory_profile
以強制強製完整 GC)。
記憶體用量的迴歸通常是建構要求大小指標中的迴歸,這通常是因為新增依附元件或規則實作的改變所致。
如要更精細地分析 Bazel 的記憶體足跡,建議您使用內建記憶體分析器來當做規則。
持續性工作站的記憶體剖析
雖然永久工作站可協助大幅加快建構速度 (尤其是翻譯語言),但記憶體用量可能並不容易。Bazel 會特別收集工作站上的指標,特別是 WorkerMetrics.WorkerStats.worker_memory_in_kb
欄位會說明工作站使用的記憶體用量 (以助力法)。
JSON 追蹤記錄分析器也會在叫用期間收集 --experimental_collect_system_network_usage
標記 (Bazel 6.0 的新功能),以收集持續性工作站記憶體用量。
圖 2:包含工作站記憶體用量的設定檔。
降低 --worker_max_instances
的值 (預設值 4) 可能有助於減少永久工作站使用的記憶體量。我們正積極努力讓 Bazel 的資源管理員和排程器變得更聰明,因此日後需要大幅減少這類微調作業。
監控遠端建構作業的網路流量
在遠端執行中,Bazel 會下載因執行動作而產生的構件。因此,您的網路頻寬可能會影響建構的效能。
如果您要針對建構作業使用遠端執行功能,則可考慮在叫用期間使用 BEP 的 NetworkMetrics.SystemNetworkStats
proto 監控網路流量 (必須傳遞 --experimental_collect_system_network_usage
)。
此外,JSON 追蹤記錄設定檔可讓您傳遞 --experimental_collect_system_network_usage
標記 (Bazel 6.0 的新功能),可在建構期間查看整個系統的網路用量。
圖 3:包含整個系統網路的設定檔。
使用遠端執行時,網路用量偏高但平坦時,可能表示網路是建構中的瓶頸;如果尚未使用,請考慮通過 --remote_download_minimal
來啟用 Build 而不使用位元組。這樣可避免下載不必要的中繼成果,進而加快建構速度。
另一種做法是設定本機磁碟快取,以節省下載頻寬。