動態執行

回報問題 查看原始碼

動態執行是 Bazel 中的功能,會在執行相同動作的本機和遠端的同時,使用完成的第一個分支版本的輸出內容,同時取消其他分支版本。它結合了遠端建構系統的執行能力和/或大型共用快取,且能縮短本機執行時間,為簡潔和漸進式建構作業提供最佳的使用體驗。

本頁面說明如何啟用、調整及偵錯動態執行。如果您同時設定了本機和遠端執行,並嘗試調整 Bazel 設定以獲得更優異的效能,可以參考本頁資訊。如果您尚未設定遠端執行,請先前往 Bazel 的 Remote Execution 總覽

要啟用動態執行功能嗎?

動態執行模組是 Bazel 的一部分,但如要使用動態執行,您必須已經能夠在本機和遠端執行編譯作業,以相同的 Bazel 設定進行編譯。

如要啟用動態執行模組,請將 --internal_spawn_scheduler 標記傳遞至 Bazel。這會新增名為 dynamic 的執行策略。您現在可以使用此策略做為要動態執行的助聽器策略,例如 --strategy=Javac=dynamic。請參閱下一節,瞭解如何選擇要啟用動態執行作業的記憶機制。

針對使用動態策略的任何記憶,遠端執行策略是透過 --dynamic_remote_strategy 標記使用,並從 --dynamic_local_strategy 標記採用本機策略。傳遞 --dynamic_local_strategy=worker,sandboxed 會設定本機動態執行分支版本的預設值,以按照該順序嘗試工作站或沙箱執行作業。傳遞 --dynamic_local_strategy=Javac=worker 只會覆寫 Javac 記憶體的預設值。遠端版本的運作方式相同。您可以多次指定這兩個標記。如果動作無法在本機執行,則會照常遠端執行,反之亦然。

如果遠端系統具有快取,--dynamic_local_execution_delay 旗標會在遠端系統指出快取命中後,針對本機執行作業加上延遲時間 (以毫秒為單位)。這樣可以避免在快取命中機率較高時執行本機執行作業。預設值為 1000 毫秒,但調整方式不會比在快取中找到了快取資料需要稍長一點。實際時間取決於遠端系統和往返所需時間。一般而言,如果特定遠端系統的所有使用者,其值都會相同,除非其中有些使用者距離多遠,以增加往返延遲時間。您可以使用 Bazel 剖析功能來查看一般快取命中需要多久時間。

動態執行可以搭配本機沙箱策略和永久工作站使用。與動態執行搭配使用時,永久工作站會自動以沙箱機制執行,且無法使用多個工作站。在 Darwin 和 Windows 系統上,沙箱策略可能較為緩慢,您可以傳遞 --reuse_sandbox_directories 來減少在這些系統上建立沙箱的負擔。

動態執行也可搭配 standalone 策略執行,不過由於 standalone 策略必須在開始執行時採用輸出鎖定,因此實際上會封鎖遠端策略,無法先完成。--experimental_local_lockfree_output 旗標可讓本機執行作業直接寫入輸出內容,但遭到遠端執行作業取消 (應先完成) 取消,藉此解決這個問題。

如果動態執行作業的某個分支先完成但失敗,整個動作就會失敗。這是刻意採取的選擇,以避免在本機和遠端執行之間出現差異。

如要進一步瞭解動態執行和鎖定的運作方式,請參閱 Julio Merino 的出色網誌文章

何時該使用動態執行?

動態執行需要某種形式的遠端執行系統。目前無法使用僅快取的遠端系統,因為在快取失敗時,系統會將其視為失敗的動作。

並非所有動作類型都適合遠端執行。建議的執行速度是在本機上運作更快的工作站 (例如透過使用永久工作站),或在執行速度夠快的情況下,導致遠端執行作業的負擔大幅增加。由於每個本機執行的動作會鎖定部分 CPU 和記憶體資源,因此執行不屬於這些類別的動作,只會延遲執行這些類別的動作。

5.0.0-pre.20210708.4 版本起,效能剖析包含工作站執行作業相關資料,包括在失去動態執行競賽後完成工作要求所花費的時間。如果您看到動態執行工作站執行緒耗用大量資源,或在 async-worker-finish 中發現大量時間,表示可能有部分本機動作延遲背景動作執行緒。

剖析動態執行效能不佳的資料

在上述使用 8 個 Javac 工作站的設定檔中,我們發現許多 Javac 工作站在 async-worker-finish 執行緒上完成了競賽,並完成他們的工作。這是由於非工作站工作站因花費足夠的資源來延遲工作站所導致。

以更出色的動態執行效能剖析資料

如果只有 Javac 以動態執行執行,則只有大約一半的工作站在開始工作後會失去競賽。

先前建議的 --experimental_spawn_scheduler 旗標已淘汰,這項功能會開啟動態執行,並將 dynamic 設為所有記憶法的預設策略,這種策略經常會導致這類問題。

效能

動態執行方法會假設本機和遠端有足夠的可用資源,值得花一些額外資源來改善整體效能。但過度使用資源可能會使 Bazel 本身或執行應用程式的機器變慢,或是遠端系統承受非預期的壓力。有數種選項可以變更動態執行的行為:

--dynamic_local_execution_delay 會在遠端分支版本啟動時,以毫秒數延遲本機分支版本的開始時間,但只有在目前的建構作業發生遠端快取命中的情況下。如此一來,對於遠端快取受益的建構作業,在最有可能可以於快取中找到的輸出內容時,就不會浪費本機資源。視快取的品質而定,減少這類做法或許能改善建構速度,但耗用更多本機資源。

--experimental_dynamic_local_load_factor 是實驗性進階資源管理選項。需要 0 到 1 的值,0 則關閉此功能。設為大於 0 的值時,Bazel 會在許多等待排程動作時,調整本機排程動作的數量。設為 1 可排程的動作數量,因為有可用 CPU 數量不多 (根據 --local_cpu_resources 的規定)。值越低的值,排程動作的數量會對應的數量較少,因為可執行的動作數量較多。這聽起來可能違反直覺,但搭配完善的遠端系統,當執行許多動作時,本機執行作業並無法提供實質幫助,而本機 CPU 較適合用於管理遠端動作。

如果遠端分支版本已執行至少這段時間,--experimental_dynamic_slow_remote_time 會優先啟動本機分支版本。一般來說,最近期排定的動作會優先執行,因為這樣最有可能贏得競賽,但如果遠端系統有時會停止運作或耗時較長,這樣建構就可能會跟進。這項功能預設為停用,因為可能會隱藏遠端系統內應修正的問題。如果啟用此選項,請務必監控遠端系統的效能。

--experimental_dynamic_ignore_local_signals 可用於在本機因特定信號而產生出口時,讓遠端支線接手。這主要適合搭配工作站資源限制 (請參閱 --experimental_worker_memory_limit_mb--experimental_worker_sandbox_hardening--experimental_sandbox_memory_limit_mb) 使用,因為當工作站程序使用過多資源時,可能會終止工作站程序。

JSON 追蹤記錄設定檔包含許多效能相關圖表,可協助您找出改善效能和資源用量的方法。

疑難排解

動態執行的問題可能不太容易偵錯,因為這類問題只能在本機和遠端執行作業的特定組合中顯示。--debug_spawn_scheduler 會新增動態執行系統提供的額外輸出內容,協助對這些問題進行偵錯。您也可以調整 --dynamic_local_execution_delay 旗標以及遠端與本機工作的數量,以便更輕鬆地重現問題。

如果您在使用 standalone 策略的動態執行時遇到問題,請嘗試在沒有 --experimental_local_lockfree_output 的情況下執行,或透過沙箱機制執行本機動作。這可能會減慢建構速度 (如果使用的是 Mac 或 Windows,請參閱上方說明),但會移除一些可能導致失敗的原因。