本頁面介紹了 Android 12 中引入的各種內存統計改進。
sysfs 中的 DMA-BUF 統計信息
在 Android 11 和 Android 12 中,無法在用戶構建中掛載debugfs
。所以在 Android 12 的/sys/kernel/dmabuf/buffers
目錄下的sysfs
中添加了 DMA-BUF 統計信息。
小路 | 描述 |
---|---|
/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 堆統計信息的接口。
下表比較了在 Android 12 中使用 DMA-BUF 堆框架的設備的 ION 統計接口與對應的接口。
Android 11 或在 Android 12 中啟動並支持 ION 的設備 | 在 Android 12 中使用 DMA-BUF 堆啟動的設備 | |
---|---|---|
每堆 ION 統計信息 | 沒有 | 從DMA-BUF sysfs stats解析 |
導出的 DMA-BUF 的總大小 | /sys/kernel/ion/total_heap_size_kb (不包括非 ION 導出器導出的 DMA-BUF 的大小) | 從 DMA-BUF sysfs stats 解析 (包括所有導出的 DMA-BUF 的大小)。 |
堆池化的總內存 | /sys/kernel/ion/total_pool_size_kb | /sys/kernel/dma_heap/total_pool_size_kb |
提高丟失的 RAM 計算精度
以前丟失的 Ram 計算如下:
final long 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 的大小,這意味著它在 Lost 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 內存使用情況來提高 Lost RAM 計算的準確性。
- 在大多數 Memtrack HAL 實現中,私有 GPU 內存包含在
totalPss
中,因此必須在將其從lostRAM
中刪除之前對其進行重複數據刪除。
下一節將詳細介紹實施的解決方案。
從丟失的 RAM 中刪除 Memtrack 可變性
由於 Memtrack HAL 實施可能因合作夥伴而異,因此 HAL 的totalPSS
中包含的 GPU 內存並不總是一致的。為了消除lostRAM
的可變性, MemtrackType::GRAPHICS
和MemtrackType::GL
中佔的內存在lostRAM
計算期間從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 測試強制執行在 Android 12 中啟動且具有 Linux 內核版本 5.4 或更高版本的設備支持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。