本頁面介紹了 Android 12 中引入的各種記憶體核算改進。
sysfs 中的 DMA-BUF 統計資訊
在 Android 11 和 Android 12 中,無法在使用者版本中安裝debugfs
。因此在 Android 12 中,DMA-BUF 統計資料已新增至/sys/kernel/dmabuf/buffers
目錄中的sysfs
中。
小路 | 描述 |
---|---|
/sys/kernel/dmabuf/buffers | /sys/kernel/dmabuf/buffers 目錄包含每個 DMA-BUF 內部狀態的快照。 /sys/kernel/dmabuf/buffers/<inode_number> 包含具有唯一 inode 號碼<inode_number> 的 DMA-BUF 的統計資料。 |
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name | 此只讀檔案包含 DMA-BUF 導出器的名稱。 |
/sys/kernel/dmabuf/buffers/<inode_number>/size | 此唯讀檔案指定 DMA-BUF 的大小(以位元組為單位)。 |
libdmabufinfo
API 解析 DMA-BUF sysfs
統計資料以公開每個匯出器和每個緩衝區的統計資料。
請注意,導出 DMA-BUF 的核心驅動程式必須在呼叫dma_buf_export()
API 建立 DMA-BUF 之前將struct dma_buf_export_info
的exp_name
欄位正確地設定為導出程式名稱。這是libdmabufinfo
和dmabuf_dump
工具取得每個匯出器統計資料所必需的,然後在錯誤報告中公開這些統計資料。
dmabuf_dump工具已修改為使用新參數-b
輸出此資訊。
DMA-BUF 堆框架的統計信息
GKI 2.0 中的 ION 已被棄用,取而代之的是DMA-BUF 堆框架,它是上游 Linux 核心的一部分。
Android 11 中追蹤以下全域 ION 統計資料:
- 每個 ION 堆導出的 DMA-BUF 的總大小
- 每個 ION 堆儲存的未使用預先分配記憶體的總大小
Android 11 中沒有可用於公開每個 ION 堆統計資料的介面。
下表將 ION 統計介面與 Android 12 中使用 DMA-BUF 堆疊框架的裝置的對應介面進行了比較。
Android 11 或在 Android 12 中推出支援 ION 的設備 | 在 Android 12 中使用 DMA-BUF 堆啟動的設備 | |
---|---|---|
每堆 ION 統計訊息 | 沒有任何 | 從DMA-BUF sysfs 統計資料解析 |
導出的 DMA-BUF 的總大小 | /sys/kernel/ion/total_heap_size_kb (不包括非 ION 導出商導出的 DMA-BUF 的大小) | 從 DMA-BUF sysfs 統計資料解析 (包括導出的所有 DMA-BUF 的大小)。 |
按堆匯集的總記憶體 | /sys/kernel/ion/total_pool_size_kb | /sys/kernel/dma_heap/total_pool_size_kb |
提高遺失RAM計算精度
之前遺失的 RAM 計算如下:
最終長度lostRAM
= memInfo.getTotalSizeKb(
) - ( totalPss
totalSwapPss
)
- memInfo.getFreeSizeKb()
- memInfo.getCachedSizeKb()
- kernelUsed
- memInfo.getZramTotalSizeKb()
;
totalPss
元件包含 GPU 記憶體使用量(由 Memtrack HAL 的getMemory()介面傳回)。 kernelUsed
組件包含 DMA-BUF 記憶體使用總量。然而,對於 Android 設備,GPU 記憶體來自以下內容:
- GPU 驅動程式使用實體頁分配器進行直接分配
- 對應到 GPU 位址空間的 DMA-BUF
因此,在計算遺失的 RAM 時,記憶體映射到 GPU 位址空間的 DMA-BUF 會被減去兩次。 Android 12 實作了一種解決方案來計算映射到 GPU 位址空間的 DMA-BUF 的大小,這意味著它在遺失 RAM 運算中僅佔一次。
解決方案詳情如下:
- 當使用 PID 0 呼叫 Memtrack HAL API
getMemory()
時,必須報告 MemtrackType::GL 和 MemtrackRecord::FLAG_SMAPS_UNACCOUNTED 的全域 GPU 專用記憶體總量。 - 當使用
PID
0
對GL
以外的MemtrackType
呼叫 getMemory() 時,不得失敗。它必須返回 0。 - Android 12 中新增的GPU 記憶體追蹤點/eBPF解決方案佔 GPU 總記憶體。從總 GPU 記憶體中減去總 GPU 私有記憶體即可得到對應到 GPU 位址空間的 DMA-BUF 的大小。然後,透過正確考慮 GPU 記憶體使用情況,該值可用於提高遺失 RAM 運算的準確性。
- 在大多數 Memtrack HAL 實作中,私有 GPU 記憶體包含在
totalPss
中,因此必須先進行重複資料刪除,然後才能將其從lostRAM
中刪除。
下一節將詳細介紹所實施的解決方案。
消除丟失 RAM 中的 Memtrack 可變性
由於 Memtrack HAL 實作可能因合作夥伴而異,因此 HAL 中的totalPSS
中包含的 GPU 記憶體並不總是一致。為了消除lostRAM
的可變性,在lostRAM
計算期間, MemtrackType::GRAPHICS
和MemtrackType::GL
中佔用的記憶體將從totalPss
中刪除。
MemtrackType::GRAPHICS
記憶體從totalPss
中移除,並替換為ActivityManagerService.java中lostRAM
計算中的totalExportedDmabuf
內存,如下所示:
final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
. . .
final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;
. . .
// Account unmapped dmabufs as part of the kernel memory allocations
kernelUsed += dmabufUnmapped;
// Replace Memtrack HAL reported Graphics category with mapped dmabufs
totalPss -= totalMemtrackGraphics;
totalPss += dmabufMapped;
MemtrackType::GL
記憶體從totalPss
中移除,並在ActivityManagerService.java中的lostRAM
計算中替換為私有GPU記憶體( gpuPrivateUsage
),如下所示:
final long gpuUsage = Debug.getGpuTotalUsageKb();
. . .
final long gpuPrivateUsage = Debug.getGpuPrivateMemoryKb();
. . .
// Replace the Memtrack HAL-reported GL category with private GPU allocations.
// Count it as part of the kernel memory allocations.
totalPss -= totalMemtrackGl;
kernelUsed += gpuPrivateUsage;
更新了遺失的 RAM 運算
總的私有 GPU 記憶體和總的匯出 DMA 緩衝記憶體都包含在kernelUsed + totalPss
中,該記憶體已從lostRAM
中刪除。這消除了 RAM 計算丟失造成的重複計數和 Memtrack 可變性。
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
驗證
VTS 測試強制執行以下規則:在具有 Linux 核心版本 5.4 或更高版本的 Android 12 中啟動的裝置支援getGpuDeviceInfo() API。
新的 Memtrack HAL API getGpuDeviceInfo()
必須傳回有關正在使用的 GPU 裝置的資訊。
這可以提供更好的記憶體統計以及 DMA 緩衝區和 GPU 記憶體使用情況的可見性。實施 memtrack AIDL HAL 以更好地丟失 RAM 和記憶體統計。此功能不依賴 Google 服務。
執行
此功能取決於AIDL Memtrack HAL ,在 Android 12 中實作該功能的說明以註釋形式包含在程式碼中。
計劃在未來版本中將所有 HIDL HAL 轉換為 AIDL。
以下 API 已加入core/java/android/os/Debug.java
:
/**
* Return total memory size in kilobytes for exported DMA-BUFs or -1 if
* the DMA-BUF sysfs stats at /sys/kernel/dmabuf/buffers could not be read.
*
* @hide
*/
public static native long getDmabufTotalExportedKb();
/**
* Return memory size in kilobytes allocated for DMA-BUF heap pools or -1 if
* /sys/kernel/dma_heap/total_pools_kb could not be read.
*
* @hide
*/
public static native long getDmabufHeapPoolsSizeKb();
為了確保您的版本能如預期運作,請將追蹤點整合到 GPU 驅動程式中,並實作 AIDL memtrack HAL getMemory()
API,以便在使用PID 0 呼叫MemtrackType::GL 和MemtrackRecord:: 時正確傳回全域總GPU私有內存。FLAG_SMAPS_UNACCOUNTED。