本頁面說明 Android 12 中推出的各種記憶體計算改善功能。
sysfs 中的 DMA-BUF 統計資料
在 Android 11 和 Android 12 中,debugfs
無法在使用者版本中掛載。因此,DMA-BUF 統計資料已新增至 Android 12 中 /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 的核心驅動程式必須設定 exp_name
的 struct dma_buf_export_info
欄位正確轉換為匯出程式名稱
叫用 dma_buf_export()
API 來建立 DMA-BUF。
這項功能是 libdmabufinfo
和 dmabuf_dump
工具用來擷取每個匯出工具的統計資料,並在 bugreport 中公開這些資料。
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 計算準確度
先前的記憶體損失計算方式如下:
最終長 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
因此,記憶體對應至 GPU 位址空間的 DMA-BUF 則減去了 RAM 遺失的兩倍。Android 12 執行解決方案來計算對應至 GPU 的 DMA-BUF 大小 位址空間,因此在「LOST 檔案」中只會計為一次 RAM 計算。
解決方案的詳細資料如下:
- Memtrack HAL API
getMemory()
只有在呼叫 PID 0 時,系統才會回報全域的 GPU 私有記憶體總量, MemtrackType::GL 和 MemtrackRecord::FLAG_SMAPS_UNACCOUNTED。 - 針對
GL
以外的MemtrackType
,使用PID
0
呼叫 getMemory() 時,不得發生失敗。而是必須傳回 0。 - Android 12 中新增的 GPU 記憶體追蹤點/eBPF 解決方案會計算 GPU 記憶體總量。將 GPU 私有記憶體總和減去 GPU 記憶體總容量 對應至 GPU 位址空間的 DMA-BUF 大小。接著,您可以使用這個值 以便正確計算 GPU 記憶體用量
- 在大多數 Memtrack HAL 實作中,私人 GPU 記憶體會納入
totalPss
,因此必須先去除重複項目,才能從lostRAM
中移除。
實作解決方案的詳細資訊請見下一節。
從遺失的 RAM 中移除 Memtrack 變化
Memtrack HAL 實作項目可能因合作夥伴而異,因此 GPU 記憶體容量
HAL 中納入的 totalPSS
不一定一致。如要移除
lostRAM
的變異性,記憶體在 MemtrackType::GRAPHICS
中所佔的比例
和 MemtrackType::GL
則會在計算 lostRAM
期間從 totalPss
中移除。
已從 totalPss
中移除 MemtrackType::GRAPHICS
記憶體,並替換成
計算 lostRAM
計算的 totalExportedDmabuf
記憶體
ActivityManagerService.java
如下所示:
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 緩衝區記憶體總量
包含在從 lostRAM
中移除的 kernelUsed + totalPss
中。這麼做可避免重複計算,並消除 Memtrack 在計算遺失的 RAM 時出現的變化。
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
驗證
VTS 測試會強制執行裝置在 Android 12 中啟動的規則 Linux kernel 5.4 以上版本支援 getGpuDeviceInfo() 也能使用 Google Cloud CLI 或 Compute Engine API
新的 Memtrack HAL API getGpuDeviceInfo()
必須傳回目前使用的 GPU 裝置相關資訊。
如此一來,就能更妥善地瞭解指定行銷區域緩衝區和 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,以便在使用 MemtrackType::GL 和 MemtrackRecord::FLAG_SMAPS_UNACCOUNTED 的 PID 0 呼叫時,正確傳回全球 GPU 私有記憶體總量。