天窗

回報問題 查看來源 夜間 7.2 7.1 7.0 6.5 6.4

Bazel 的平行評估和成效增幅模型。

資料模型

資料模型由下列項目組成:

  • SkyValue。也稱為節點。SkyValues 是不可變動的物件, 包含建構期間建立的所有資料,以及 建構過程例如:輸入檔案、輸出檔案、目標和設定 目標。
  • SkyKey。參照 SkyValue 的簡短不可變名稱,例如 FILECONTENTS:/tmp/fooPACKAGE://foo
  • SkyFunction。依據金鑰和相依節點建構節點。
  • 節點圖表。內含依附元件關係的資料結構 節點。
  • Skyframe。漸進式評估架構 Bazel 的程式碼名稱是 本產品

評估

藉由評估代表建構要求的節點來達成建構。

Bazel 會先找出與頂層金鑰對應的 SkyFunction SkyKey。然後,函式會要求評估需要的節點 評估頂層節點,進而產生其他 SkyFunction 呼叫 直到到達分葉節點為止節能綠葉節點通常是 輸入檔案最後,Bazel 會將 頂層 SkyValue,有一些副作用 (例如檔案中的輸出檔案) 系統) 以及節點之間依附元件的有向非循環圖 和建構作業的關聯

如果 SkyFunction 無法在多張票證中要求 SkyKeys, 然後推進工作需要的所有節點有一個簡單的例子是評估 變成符號連結的輸入檔案節點:函式會嘗試讀取 並得知這是符號連結,因此擷取檔案系統節點 代表符號連結的目標但這本身可能是符號連結 如此一來,原始函式也必須擷取本身的目標。

函式在程式碼中,會由介面 SkyFunction 和 由名為 SkyFunction.Environment 的介面提供給 API 的服務。這些 函式可執行的動作:

  • 呼叫 env.getValue 來要求對其他節點的評估。如果 節點可用,且會傳回其值,否則會傳回 null 函式本身應該會傳回 null。如果是後者 評估相依節點後,原始節點建構工具會 但這次相同的 env.getValue 呼叫會傳回 非 null 的值。
  • 呼叫 env.getValues() 可要求評估其他多個節點。 上述操作基本上相同 只是相依節點 系統會同時評估多個項目
  • 在叫用期間執行運算
  • 有副作用,例如將檔案寫入檔案系統。醫療照護需求 是因為兩個不同函式都避免分步 腳印一般而言,寫入副作用 (資料從 Bazel 向外流出) 在沒有問題的情況下,讀取副作用 (也就是資料流入 Bazel 時 未註冊的依附元件) 則無效,因為這些是未註冊的依附元件。 以免造成錯誤的漸進式建構。

適度採行 SkyFunction 措施,避免以其他方式存取資料 要求依附元件 (例如直接讀取檔案系統) 這樣 Bazel 就不會在檔案上註冊資料依附元件 因此導致錯誤的漸進式建構作業

當函式累積足夠的資料可以執行工作後,應傳回非 null

這項評估策略有許多好處:

  • 密封設計。如果函式只要求輸入資料, Bazel 就能保證輸入狀態相同時 會傳回相同的資料如果所有天體函數具有確定性,那麼 整個建構作業也會具有確定性
  • 正確且完美的成效增幅。如果所有函式的所有輸入資料 Bazel 只能將所需節點 在輸入資料變更時失效。
  • 平行處理工作數量由於函式只能透過 要求依附元件、不依附的函式 且 Bazel 可以保證結果會與 依序執行

成效增幅

由於函式只能依據其他節點存取輸入資料,因此 Bazel 可以建立從輸入檔案到輸出的 檔案,然後使用這項資訊,只重新建構實際需要的節點 即將重新建構:一組已變更的輸入檔案之反向遞移。

具體來說,有兩種可能的成效增幅策略:由下而上策略 和從上往下一探究竟依據依附關係圖的方式,判斷何者最為合適 就像這樣

  • 在底標失效期間,建立圖表並變更組合後 所有節點都會失效,連帶使所有節點失效 已變更檔案。如果您打算建構相同的頂層節點,則這是最佳的做法 可以選取「重新建立」,再次生成新的提示請注意,如要撤銷底部該變更,則必須對所有用戶端執行 stat() 判斷檔案是否遭到變更。這個 可以使用 inotify 或類似機制來學習 已變更檔案。

  • 在由上而下撤銷作業時,頂層節點的遞移性關閉 且只有這些節點能保留遞移性關閉內容。 如果節點圖較大,此選項會更好,但下一個版本只需要 一小部分: 與「由上而下無效」不同 第二個版本的圖表

Bazel 只會執行由上而上的撤銷作業。

為了進一步取得增量,Bazel 會使用「變更修剪」:如果節點 失效,但重新建構時發現新值相同 視為舊值,因這個節點變更而失效的節點 就會被「復活」。

這種做法非常實用,例如當有人變更 C++ 檔案中的註解時,就會產生以下效果: 因此產生的 .o 檔案會相同,因此不必呼叫 連結器。

增量連結 / 編譯

這個模型的主要限制在於撤銷節點時 全無關聯:當依附元件變更時,依附節點一律會變更 重新建構,即便有更好的演算法可以變更 變更節點的舊值以下舉例說明 有幫助:

  • 增量連結
  • 當 JAR 檔案中的單一類別檔案變更時, 在原地修改 JAR 檔案,而不是從頭開始建構。

Bazel 為何無法依據原則支援這些特性 是兩倍

  • 獲得的成效提升有限。
  • 難以驗證變異的結果 而且 Google 重視的是 可重複執行。

直到目前為止,只要分解 執行成本高昂的建構步驟及進行部分重新評估例如: 您可以在 Android 應用程式中將所有類別分割成多個群組,以及 dex 所以需要分開管理如此一來,當群組中的類別維持不變時 其實不必重做

對應 Bazel 概念

這是金鑰 SkyFunctionSkyValue 的概略摘要 Bazel 用來執行建構的實作:

  • FileStateValue.lstat() 的結果。如果是現有檔案, 函式也會計算其他資訊,以便偵測 檔案。這是 SkyFrame 圖表中最低層級的節點,因此沒有 依附元件
  • FileValue。使用任何與實際內容無關的項目 檔案的解析路徑取決於對應的 FileStateValue 和 任何需要解析的符號連結 (例如 a/bFileValue 需要 a 的解析路徑和 a/b 的解析路徑)。 FileValueFileStateValue 之間的區別非常重要 後者可以在檔案內容沒有的情況下使用 但其實不然舉例來說,如果檔案內容不相關 評估檔案系統 glob (例如 srcs=glob(["*/*.java"]))。
  • DirectoryListingStateValue.readdir() 的結果。喜歡 FileStateValue,這是最低層級的節點,沒有依附元件。
  • DirectoryListingValue.使用任何與項目相關的項目 檔案。視對應的 DirectoryListingStateValue 而定,: 以及與目錄相關聯的 FileValue
  • PackageValue。代表 BUILD 檔案的剖析版本。取決於 相關 BUILD 檔案的 FileValue,並間接用於任何 用於解析套件中的 glob 的 DirectoryListingValue (在內部代表 BUILD 檔案內容的資料結構)。
  • ConfiguredTargetValue.代表已設定的目標,也就是元組 一組動作產生的這組動作 提供給相依設定的目標取決於 PackageValue:對應目標位於 ConfiguredTargetValues 以及代表建構作業的特殊節點 此外還會從 0 自動調整資源配置 您完全不必調整資源調度設定
  • ArtifactValue。代表建構中的檔案,可以是來源或 然後輸出構件構件幾乎等於檔案,可以 請參考實際執行建構步驟中的檔案。來源檔案 取決於相關聯節點的 FileValue,以及輸出構件 取決於任何動作的 ActionExecutionValue 構件。
  • ActionExecutionValue.代表動作的執行。取決於 其輸入檔案的 ArtifactValues。它執行的操作包含在 這與 SkyKeys 應該 小型請注意,如果符合以下條件,則不會使用 ActionExecutionValueArtifactValue 執行階段就不會執行

這張示意圖為視覺輔助,這張圖表展示了 在建構 Bazel 本身之後實作 SkyFunction:

SkyFunction 實作關係圖表