RFC-0254:變更寫入頁面內文的出處

RFC-0254:變更寫入頁面內文的出處
狀態已接受
領域
  • 核心
說明

變更 Zircon 對寫入寫入頁面的 API 和語意。

問題
毛皮變化
  • 1044572
作者
審查人員
提交日期 (年-月-日)2024-08-02
審查日期 (年-月-日)2024-07-29

問題說明

Zircon 為將記憶體歸因於 VMO 時公開的行為是 以下列兩種方式驗證 Starnix 核心的問題:

首先,Zircon 目前的記憶體歸因行為只能與 在 Zircon 的 VMO 實作中使用廣泛共用的鎖定。這個共用門鎖 是許多 Starnix 程序在執行時會發生問題的原因。

Starnix 利用 VMO 返回每個 MAP_ANONYMOUS Linux 對應,並複製所有這類 發出 fork() 呼叫時,Linux 程序中的 VMO。透過許多 Linux 程序 結果導致許多 VMO 接續少數共用鎖定我們 設計了可節省記憶體最佳化的原型,Starnix 將單一大型 VMO 用於所有 共用鎖定會產生「global」CANNOT TRANSLATE 星際大戰 VMO 熱烈討論。

第二,Starnix 無法模擬 Linux 記憶體歸因的實際行為 與 Zircon 提供的 API 整合不會區分私人和共用 VMO 中寫入時複製的頁面,因此也不會公開 任何這類分享網頁。Starnix 需要這項資訊來準確計算 在不同 /proc 檔案系統項目中公開的 USSPSS 值。

我們提議變更 Zircon 記憶體歸因 API 的行為,以及 可以解決這些問題,同時維持現有的功能組工具 提供仰賴這些系統的產品資訊我們不會為瞭解決 這種模型會在使用者空間實體 (例如元件和執行器) 之間分配記憶體三 也不該將這些功能轉變為「最後一個字」進行歸因,表示 我們致力解決特定效能瓶頸和功能缺口 快來見識到 Starnix 名人。

摘要

改善 Zircon 的記憶體歸因 API 和行為,以便考量共用情形 寫入後複製的頁面

相關人員

講師:

neelsa@google.com

審查者:

  • adanis@google.com
  • jamesr@google.com
  • etiennej@google.com
  • wez@google.com

諮詢:

  • maniscalco@google.com
  • davemoore@google.com

社交功能:

此 RFC 是在與 Zircon、 《Starnix》和《Memory》團隊利益相關者也查看了設計文件 概述此 RFC 中提議的變更

需求條件

  1. 核心的記憶體歸因實作不得妨礙最佳化 讓 VMO 階層鎖定更精細地鎖定 Zircon 中的鎖定爭用情形。
  2. 如果 memory_monitor 等工具能加總系統中所有 VMO 的歸因情形, 且總量必須與系統實際的實體記憶體用量一致。這是 「加總一到一」資源。
  3. Starnix 必須能夠模擬 Linux 記憶體歸因 APIS 的 以及由 Zircon 提供的 API包括提供 USSRSSPSS 測量及相關程序檔案系統項目中的其他測量結果。

設計

我們提出的變更會影響 VMO 之間共用 Zircon 屬性頁面的方式 透過寫入時複製的方式複製。這些是 COW 私人網頁和 COW 分享的網頁。

我們不提議變更程序之間共用 Zircon 屬性頁面的方式 讀取及寫入資料這些是程序私密資料 程序共用的頁面

使用者空間負責將程序共用的網頁歸因於一或多個 程序。Zircon 通常不會考慮流程共用 但有一個例外情況請參閱「回溯相容性」的 瞭解詳情

共用類型是各自獨立的,每個網頁都可以是 COW-private、COW 共用、程序私人及程序共用

Zircon 的現有行為

Zircon 現有的歸因行為會提供單一 VM 的評估方式: 來自 VMO 的 COW-private 和 COW 共用頁面的歸因記憶體, 不重複歸因。

  • 此屬性可明確將 COW 共用的網頁歸因於現存的最舊 VMO, 參照這些 Pod同一層 VMO 有時會共用 COW 共用頁面,因此 參照頁面最古老的 VMO 不得屬於其他頁面
  • 將整個系統的 VMO 總和加總,即為系統記憶體總用量。
  • 並不會測量 VMO 的USS,因為其中可能包含「部分」COW 共用網頁。
  • 也不會測量 VMO 的 RSS, 因為其中可能不包含「所有」COW 共用的網頁。
  • 並不會測量 VMO 的 PSS,因為這項測量結果會縮放各頁面的 貢獻數。

Zircon 的新行為

Zircon 的新歸因行為提供三種每個 VMO 的評估方式:

  • USS:從 VMO 的 COW-private 頁面歸因於記憶體。這項測量結果 則只會將頁面歸因於該 VMO它會測量 如果 VMO 遭刪除
  • RSS:VMO 的 COW-private 和 COW 共用頁面歸因於記憶體。這個 測量會將 COW 共用的網頁歸給共用這些 VM 的各個 VMO, 會多次計算 COW 共用的網頁。這會測量 VMO 的記憶體總容量 參照。
  • PSS:歸因於 VMO 的 COW-private 和 COW 共用頁面所歸因的記憶體。這個 評估方式會在所有 VMO 間平均分配「COW 共用網頁」的歸因情形 共用頁面以指定的 VMO 來說,這可以是小數 因為每個 VMO 各自的共用網頁比例都一樣一個位元組這項服務 會評估 VMO 的「比例」記憶體用量限制將所有 VMO 加總 整個系統是測量系統記憶體總用量。

我們選擇公開所有USSRSS 和 我們探討了其他解決方案,因此這是 PSS 的唯一選擇 符合所有需求

對使用者空間的影響

此提案將繼續保留「總和」與現有資源 對使用者空間工具至關重要歸因查詢可能會在 新的行為,但繼續加總系統中所有 VMO 的查詢 以便提供準確的記憶體用量。這些變更不會造成程式 例如 memory_monitorps,開始超額計算或低估記憶體數量。 事實上,它們會更準確地計算 VMO 和個別工作的計數

新的 API 公開 PSS 的小數位元組值,且使用者空間必須選擇採用 來觀察這些分數的位元組_fractional_scaled 欄位包含 不部分位元組和使用者空間則會稍微低估 PSS 數量。

目前,Starnix 低估了 Linux 對應的 RSS 值,因為 目前的歸因行為只會計算 COW 共用的網頁一次。RSS 應 多次計算共用網頁。Starnix 只有在沒有辦法的情況下模擬這種行為 因此,我們變更 Zircon 歸因 API,以提供正確的 RSS 值。我們可以對另回合的 API 變更執行此操作,不過為了避免 也就是我們選擇批次處理變更

memory_monitor 會將 VMO 視為與參照任何項目的程序共用 任何子項,即使是未直接參照 VMO 的程序也一樣。 也就是將父項 VMO 的歸因記憶體平均分配給這些程序。 試圖將 COW 共用的網頁納入考量,並允許 memory_monitor : 「加總一次」,但可能會導致一些錯誤結果。舉例來說 部分未參照的父項 VMO 的 COW-private 頁面部分 因此無法參照頁面而且縮放父項時 與部分孩子分享,但不與其他人分享時,可由 COW 分享的網頁。我們的 變更便造成這個行為多餘,而我們也會將其移除。這項工具仍會 當多個程序直接參照 VMO 時 即可調整 VMO 的記憶體詳情請見 「回溯相容性」,掌握更多詳細資訊。

Syscall API 變更

Zircon 的 Attribution API 包含 zx_object_get_info 主題 變更:

  • ZX_INFO_VMO
    • 我們將透過以下方式保留 ABI 和 API 的回溯相容性:
      • ZX_INFO_VMO ->ZX_INFO_VMO_V3 重新命名,同時保留其值。
      • 正在重新命名「zx_info_vmo_t」->zx_info_vmo_v3_t
    • 我們將加入新的 ZX_INFO_VMOzx_info_vmo_t,然後改變意義 所有版本的 zx_info_vmo_t 中的兩個現有欄位:
typedef struct zx_info_vmo {
  // Existing and unchanged `zx_info_vmo_t` fields omitted for brevity.

  // These fields already exist but change meaning.
  //
  // These fields include both private and shared pages accessible by a VMO.
  // This is the RSS for the VMO.
  //
  // Prior versions of these fields assigned any copy-on-write pages shared by
  // multiple VMO clones to only one of the VMOs, making the fields inadequate
  // for computing RSS. If 2 VMO clones shared a single page then queries on
  // those VMOs would count either `zx_system_get_page_size()` or 0 bytes in
  // these fields depending on the VMO queried.
  //
  // These fields now include all copy-on-write pages accessible by a VMO. In
  // the above example queries on both VMO's count `zx_system_get_page_size()`
  // bytes in these fields. Queries on related VMO clones will count any shared
  // copy-on-write pages multiple times.
  //
  // In all other respects these fields are the same as before.
  uint64_t committed_bytes;
  uint64_t populated_bytes;

  // These are new fields.
  //
  // These fields include only private pages accessible by a VMO and not by any
  // related clones. This is the USS for the VMO.
  //
  // These fields are defined iff `committed_bytes` and `populated_bytes` are,
  // and they are the same re: the definition of committed vs. populated.
  uint64_t committed_private_bytes;
  uint64_t populated_private_bytes;

  // These are new fields.
  //
  // These fields include both private and shared copy-on-write page that a VMO
  // can access, with each shared page's contribution scaled by how many VMOs
  // can access that page. This is the PSS for the VMO.
  //
  // The PSS values may contain fractional bytes, which are included in the
  // "fractional_" fields. These fields are fixed-point counters with 63-bits
  // of precision, where 0x800... represents a full byte. Users may accumulate
  // these fractional bytes and count a full byte when the sum is 0x800... or
  // greater.
  //
  // These fields are defined iff `committed_bytes` and `populated_bytes` are,
  // and they are the same re: the definition of committed vs. populated.
  uint64_t committed_scaled_bytes;
  uint64_t populated_scaled_bytes;
  uint64_t committed_fractional_scaled_bytes;
  uint64_t populated_fractional_scaled_bytes;
} zx_info_vmo_t;
  • ZX_INFO_PROCESS_VMOS
    • 我們將透過以下方式保留 ABI 和 API 的回溯相容性:
      • 正在將「ZX_INFO_PROCESS_VMOS」->「ZX_INFO_PROCESS_VMOS_V3」重新命名 保留其值
    • 我們將會新增一個 ZX_INFO_PROCESS_VMOS
      • 這個主題重複使用 zx_info_vmo_t 結構體系列,所以變更 這裡就會顯示所有設定
  • ZX_INFO_PROCESS_MAPS
    • 我們將透過以下方式保留 ABI 的回溯相容性:
      • 正在將「ZX_INFO_PROCESS_MAPS」->「ZX_INFO_PROCESS_MAPS_V2」重新命名 保留其值
      • 正在重新命名「zx_info_maps_t」->zx_info_maps_v2_t
      • 正在重新命名「zx_info_maps_mapping_t」->zx_info_maps_mapping_v2_t
    • 在下列情況中,我們會中斷 API 相容性:
      • committed_pagespopulated_pages 重新命名屬於破壞性變更。 請參閱「回溯相容性」。
    • 我們將新增 ZX_INFO_PROCESS_MAPSzx_info_maps_t和 來使用 zx_info_maps_mapping_t,然後變更「現有」中兩個欄位的意義 zx_info_maps_mapping_t 版。但新的 此結構體的版本 (請參閱下文):
typedef struct zx_info_maps {
  // No changes, but is required to reference the new `zx_info_maps_mapping_t`.
} zx_info_maps_t;

typedef struct zx_info_maps_mapping {
  // Existing and unchanged `zx_info_maps_mapping_t` fields omitted for brevity.

  // These fields are present in older versions of `zx_info_maps_mapping_t` but
  // not this new version. In the older versions they change meaning.
  //
  // See `committed_bytes` and `populated_bytes` in the `zx_info_vmo_t` struct.
  // These fields change meaning in the same way.
  uint64_t committed_pages;
  uint64_t populated_pages;

  // These are new fields which replace `committed_pages` and `populated_pages`
  // in this new version of `zx_info_maps_mapping_t`.
  //
  // These fields are defined in the same way as the ones in `zx_info_vmo_t`.
  uint64_t committed_bytes;
  uint64_t populated_bytes;

  // These are new fields.
  //
  // These fields are defined in the same way as the ones in `zx_info_vmo_t`.
  uint64_t committed_private_bytes;
  uint64_t populated_private_bytes;
  uint64_t committed_scaled_bytes;
  uint64_t populated_scaled_bytes;
  uint64_t committed_fractional_scaled_bytes;
  uint64_t populated_fractional_scaled_bytes;
} zx_info_maps_mapping_t;
  • ZX_INFO_TASK_STATS
    • 我們將透過以下方式保留 ABI 和 API 的回溯相容性:
      • 在保留時重新命名 ZX_INFO_TASK_STATS ->ZX_INFO_TASK_STATS_V1
      • 正在重新命名「zx_info_task_stats_t」->zx_info_task_stats_v1_t
    • 我們將新增 ZX_INFO_TASK_STATSzx_info_task_stats_t,並且 變更「所有」版本中三個現有欄位的意義 zx_info_task_stats_t 結構體:
typedef struct zx_info_task_stats {
  // These fields already exist but change meaning.
  //
  // These fields include either private or shared pages accessible by mappings
  // in a task.
  // `mem_private_bytes` is the USS for the task.
  // `mem_private_bytes + mem_shared_bytes` is the RSS for the task.
  // `mem_private_bytes + mem_scaled_shared_bytes` is the PSS for the task.
  //
  // Prior versions of these fields only considered pages to be shared when they
  // were mapped into multiple address spaces. They could incorrectly attribute
  // shared copy-on-write pages as "private".
  //
  // They now consider pages to be shared if they are shared via either multiple
  // address space mappings or copy-on-write.
  //
  // `mem_private_bytes` contains only pages which are truly private - only one
  // VMO can access the pages and that VMO is mapped into one address space.
  //
  // `mem_shared_bytes` and `mem_scaled_shared_bytes` contain all shared pages
  // regardless of how they are shared.
  //
  // `mem_scaled_shared_bytes` scales the shared pages it encounters in two
  // steps: first each page is scaled by how many VMOs share that page via
  // copy-on-write, then each page is scaled by how many address spaces map the
  // VMO in the mapping currently being considered.
  //
  // For example, consider a single page shared between 2 VMOs P and C.
  //
  // If P is mapped into task p1 and C is mapped into tasks p2 and p3:
  // `mem_private_bytes` will be 0 for all 3 tasks.
  // `mem_shared_bytes` will be `zx_system_get_page_size()` for all 3 tasks.
  // `mem_scaled_shared_bytes` will be `zx_system_get_page_size() / 2` for p1
  // and `zx_system_get_page_size() / 4` for both p2 and p3.
  //
  // If P is mapped into task p1 and C is mapped into tasks p1 and p2:
  // `mem_private_bytes` will be 0 for both tasks.
  // `mem_shared_bytes` will be `2 * zx_system_get_page_size()` for p1 and
  // `zx_system_get_page_size()` for p2.
  // `mem_scaled_shared_bytes` will be `3 * zx_system_get_page_size() / 4` for
  // p1 and `zx_system_get_page_size() / 4` for p2.
  uint64_t mem_private_bytes;
  uint64_t mem_shared_bytes;
  uint64_t mem_scaled_shared_bytes;

  // This is a new field.
  //
  // This field is defined in the same way as the "_fractional" fields in
  // `zx_info_vmo_t`.
  uint64_t mem_fractional_scaled_shared_bytes;
} zx_info_task_stats_t;

實作

我們會實作結構核心 API 變更 (例如新增及重新命名 ) 做為單一初始 CL,以降低客戶流失率。我們會將這個數值 將新欄位設為 0,但 _fractional_scaled 欄位的設定除外 設為 UINT64_MAX 的禮盒值。

接下來,我們會變更有關歸因父項的 memory_monitor 行為 處理及使用 VMO 記憶體,以便處理及使用 PSS _scaled_bytes 欄位 RSS _bytes 欄位。_fractional_scaled 中的標記值 欄位會暫時限制這兩種無法回溯相容的行為。這個 其他新欄位中的值 0 表示不會發生使用者空間行為 不會有變更

接著,我們會公開核心的新歸因行為。這項異動 將會改變現有欄位 (例如 committed_bytes) 和新的 欄位可採用非零的值。_fractional_scaled 欄位不得包含 這樣就會繼續採用 Sentinel 值 以便利用新的行為和新欄位善加利用

最後,我們會將檢查工具中 _fractional_scaled 欄位的檢查移除: memory_monitor

我們變更的舊版 API 視為已淘汰。我們可以移除 之後,若我們確信二進位檔不再符合這些條件,就會發生上述情形。

成效

導入新的歸因模式可提高歸因成效 舉個簡單的例子,您可以定義情境 並指示 AI 如何回應服務中心查詢可減少處理 VMO 複製作業的次數,避免產生昂貴的檢查費用, 來區分多部 VMO 之間共享的 COW 頁面。

之後,導入精細的階層鎖定將能提升 頁面錯誤和多個 VMO 系統呼叫,包括 zx_vmo_readzx_vmo_writezx_vmo_op_rangezx_vmo_transfer_data。這些行動延續於 所有相關 VMO 共用的階層鎖定 對相關 VMO 副本執行的作業反之,如果 VMO 的虛擬機器 以便執行複製作業許多 Starnix 和啟動檔案系統 VMO 都屬於這個類別。

Zircon 會在建立及刪除子項 VMO 時執行更多工作,建立中 SNAPSHOTSNAPSHOT_MODIFIED 子項會改為 O(#parent_pages) (共 O(1) 個)。如果刪除任何類型的子項,在任何情況下都會變成 O(#parent_pages) 在某些情況下,這些可能有助於 O(#child_pages)。Zircon 目前 將這項工作延遲到更頻繁的作業,例如頁面錯誤。移動到 不常的 zx_vmo_create_child()zx_vmo_destroy() 作業將會 加快其他常用作業的商業速度我們預期 而這也成為使用者可見的效能迴歸

我們將使用現有的 Microbenchmark 和 Macrobenchmark 來驗證是否 成效差異

回溯相容性

ABI 與 API 相容性

我們會為所有核心 API 變更建立其他版本化主題,並 但會保留所有現有主題的支援這樣可保留 ABI 相容性 以及 API 相容性

正在重新命名 zx_info_maps_mapping_t 中的 committed_pagespopulated_pages 就是破壞 API這些欄位僅用於 Fuchsia-internal 由於 CL 能夠為這些欄位重新命名 變更所有通話網站的名稱。

其他變更則不需要更新現有的通話網站,除非對方願意 並利用新加入的欄位

行為相容性

Starnix、ps 和一些程式庫 (獨立 VMO 或 每項工作的 RSS 值新的歸因行為會用來計算 更準確。因為這類報表會重複計算 COW 共用的網頁。這個 會以回溯不相容的方式變更 RSS 值 所以我們不希望造成任何負面影響。

memory_monitor 為父項 VMO 歸因記憶體的方法正確無誤 新歸因行為能修正的問題我們必須變更這項工具的 無法回溯相容實作修正。為了避免 流失,我們會將新的 _fractional_scaled 欄位設為 UINT64_MAX,直到我們導入新的歸因行為為止。我們會出門 memory_monitor 以此值進行實作。一律不產生歸因 和一般的標準化值,所以看起來很不錯。

我們會保留「共用」的意思"程序共用"在「ZX_INFO_TASK_STATS」中 但運作方式與其他 Attribution API 不同這樣一來, 仰賴 ZX_INFO_TASK_STATS 行為的現有程式才能繼續 以免產生侵入式變更未來的工作可能會取代上述做法 有不同查詢,可能是 memory_monitor,時間為 ZX_INFO_TASK_STATS 我們就可以淘汰並移除 ZX_INFO_TASK_STATS

測試

核心測試套件已有許多測試來驗證記憶體歸因。

我們會新增幾項測試,驗證新歸因的極端情況 API 和行為

說明文件

我們將更新 zx_object_get_info 的 syscall 說明文件,以反映這些 並輸入變更內容

我們會在 docs/concepts/memory 下新增頁面,用來描述 Zircon 的 記憶體歸因 API 並提供範例

缺點、替代方案和未知

在開發這項技術的過程中 提案。這些大多數發布商容易導入,但成效不彰。 維護特徵

模擬目前的歸因行為

如果採用這個選項,我們會將核心變更為模擬現有的歸因 新實作上的行為

它沒有回溯相容性方面的疑慮,也不需要任何 API 變更。

但會禁止使用精細的階層鎖定功能 現有的共用階層鎖定功能就能運作這項模擬會導致 進行更精細的鎖定策略,分析查詢死結。會 也會導致歸因查詢的成效不佳這些廣告活動的成效 關注的議題最後,這個介面並未提供 Starnix 需要的資訊 計算 USSRSSPSS 等測量結果。

隻公開 USS 和 RSS

如果採用這個選項,我們會變更核心,改為歸因於寫入時共用複製功能 分享資訊,並公開提交資訊,將這項資訊提供給私人大眾和分享

這種架構與精細的階層鎖定相容。

不過,它無法提供足夠的資訊來保存使用者 「加總一到一」屬性。如要計算 PSS 測量結果,則建議使用 Starnix。核心 這個選項會為 COW 共用網頁多次屬性。每一份 COW 共用的資料 網頁分享次數可能會因寫入模式而異 的使用者空間中,需要單頁資訊才能刪除重複的 COW 共用網頁,或 平均分配到本機副本之間

顯示每個 VMO 樹狀結構的詳細資料

如果採用這個選項,我們會變更核心,改為歸因於寫入時共用複製功能 並公開每個樹狀結構和 VMO 的資訊:

  • 將 VMO 連結至其樹狀結構的樹狀結構 ID
  • 每個 VMO 的穩定 ID,適用於建立中斷事件,例如時間戳記
  • 每個 VMO 的私人頁面數
  • 每個樹狀結構的共用網頁總數
  • 每個 VMO 可見的每個樹狀結構共用頁面數量

提供使用者空間,滿足「加總一個」的需求 資源。

然而,這卻阻擋了我們想進行的鎖定爭用最佳化 需要現有的共用階層鎖定功能才能運作。無論 計算「每個樹狀結構的共用網頁總數」而且沒有這種共同的鎖這個 選項也會向使用者空間公開核心實作詳細資料 VM 程式碼日後的維護也更加困難且不提供 資訊 Starnix 需要計算 PSS 測量結果。

既有藝術品和參考資料

其他作業系統會提供 RSSUSSPSS 測量結果,用於 有時可能會使用不同的名稱Windows、MacOS 和 Linux 所有曲目 RSSUSS。Linux 型作業系統追蹤 PSS

Linux 會透過程序檔案系統公開這些測量結果。歸因工具 例如 ps 和頂端