Triển khai DMABUF và tính toán bộ nhớ GPU trong Android 12

Trang này mô tả nhiều cải tiến về tính toán bộ nhớ được giới thiệu trong Android 12.

Thống kê DMA-BUF trong sysfs

Trong Android 11 và Android 12, không thể gắn debugfs trong bản dựng Người dùng. Như vậy số liệu thống kê DMA-BUF đã được thêm vào sysfs trong thư mục /sys/kernel/dmabuf/buffers trong Android 12.

Con đường Sự miêu tả
/sys/kernel/dmabuf/buffers Thư mục /sys/kernel/dmabuf/buffers chứa ảnh chụp nhanh trạng thái bên trong của mọi DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> chứa số liệu thống kê cho DMA-BUF với số inode duy nhất <inode_number> .
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name Tệp chỉ đọc này chứa tên của nhà xuất khẩu DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size Tệp chỉ đọc này chỉ định kích thước của DMA-BUF tính bằng byte.

API libdmabufinfo phân tích số liệu sysfs DMA-BUF để hiển thị số liệu thống kê cho mỗi nhà xuất khẩu và mỗi bộ đệm.

Xin lưu ý rằng trình điều khiển hạt nhân xuất DMA-BUF phải đặt chính xác trường exp_name của struct dma_buf_export_info thành tên nhà xuất khẩu trước khi gọi API dma_buf_export() để tạo DMA-BUF. Điều này là bắt buộc đối với libdmabufinfo và công cụ dmabuf_dump để lấy số liệu thống kê cho mỗi nhà xuất khẩu, sau đó hiển thị trong báo cáo lỗi.

Công cụ dmabuf_dump đã được sửa đổi để xuất thông tin này với một đối số mới, -b .

Thống kê cho khung heap DMA-BUF

ION trong GKI 2.0 không còn được dùng nữa để thay thế bằng khung heap DMA-BUF , một phần của nhân linux ngược dòng.

Số liệu thống kê ION toàn cầu sau đây được theo dõi trong Android 11:

  • Tổng kích thước của DMA-BUF được xuất bởi mỗi vùng ION
  • Tổng kích thước bộ nhớ được cấp phát trước chưa sử dụng được lưu trữ bởi mỗi vùng ION

Không có giao diện nào để hiển thị số liệu thống kê về vùng nhớ heap trên mỗi ION trong Android 11.

Bảng sau đây so sánh giao diện thống kê ION với các giao diện tương ứng của chúng dành cho các thiết bị sử dụng khung vùng nhớ khối xếp DMA-BUF trong Android 12.

Android 11 hoặc Thiết bị ra mắt có hỗ trợ ION trong Android 12 Các thiết bị khởi chạy với vùng nhớ khối DMA-BUF trong Android 12
Thống kê ION trên mỗi đống Không có Được phân tích cú pháp từ số liệu thống kê hệ thống DMA-BUF
Tổng kích thước của DMA-BUF được xuất /sys/kernel/ion/total_heap_size_kb
(Không bao gồm kích thước của DMA-BUF được xuất bởi các nhà xuất khẩu không thuộc ION)
Được phân tích cú pháp từ số liệu thống kê hệ thống DMA-BUF
(bao gồm kích thước của tất cả DMA-BUF được xuất).
Tổng bộ nhớ được gộp theo đống /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Cải thiện độ chính xác tính toán RAM bị mất

Trước đây việc tính toán RAM bị mất được thực hiện như sau:

lostRAM lâu dài cuối cùngRAM = memInfo.getTotalSizeKb( ) - ( totalPss - totalSwapPss )

- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()

- kernelUsed - memInfo.getZramTotalSizeKb() ;

Thành phần totalPss bao gồm việc sử dụng bộ nhớ GPU (được trả về bởi giao diện getMemory() của Memtrack HAL). Thành phần kernelUsed bao gồm tổng mức sử dụng bộ nhớ DMA-BUF. Tuy nhiên, đối với các thiết bị Android, bộ nhớ GPU được cung cấp như sau:

  • Phân bổ trực tiếp được thực hiện bởi trình điều khiển GPU bằng cách sử dụng bộ cấp phát trang vật lý
  • DMA-BUF được ánh xạ vào không gian địa chỉ GPU

Do đó, DMA-BUF được ánh xạ bộ nhớ vào không gian địa chỉ GPU sẽ bị trừ hai lần khi tính toán lượng RAM bị mất. Android 12 triển khai giải pháp tính toán kích thước của DMA-BUF được ánh xạ vào không gian địa chỉ GPU, nghĩa là nó chỉ được tính một lần trong tính toán Mất RAM.

Chi tiết của giải pháp như sau:

  • API Memtrack HAL getMemory() khi được gọi với PID 0 phải báo cáo tổng bộ nhớ riêng tư GPU toàn cầu cho MemtrackType::GL và MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() khi được gọi với PID 0 cho MemtrackType không phải GL không được lỗi. Thay vào đó nó phải trả về 0.
  • Giải pháp tracepoint/eBPF bộ nhớ GPU được thêm vào Android 12 sẽ chiếm tổng bộ nhớ GPU. Trừ tổng bộ nhớ riêng của GPU khỏi tổng bộ nhớ GPU sẽ cung cấp kích thước của DMA-BUF được ánh xạ vào không gian địa chỉ GPU. Sau đó, giá trị này có thể được sử dụng để cải thiện độ chính xác của phép tính Mất RAM bằng cách tính toán chính xác mức sử dụng bộ nhớ GPU.
  • Bộ nhớ GPU riêng được bao gồm trong totalPss trong hầu hết các triển khai Memtrack HAL và do đó phải được loại bỏ trùng lặp trước khi xóa nó khỏi lostRAM .

Giải pháp thực hiện được trình bày chi tiết trong phần tiếp theo.

Xóa biến thể Memtrack khỏi RAM bị mất

Vì việc triển khai Memtrack HAL có thể khác nhau giữa các đối tác nên bộ nhớ GPU có trong totalPSS từ HAL không phải lúc nào cũng nhất quán. Để loại bỏ sự thay đổi khỏi lostRAM , bộ nhớ được tính trong MemtrackType::GRAPHICSMemtrackType::GL sẽ bị xóa khỏi totalPss trong quá trình tính toán lostRAM .

Bộ nhớ MemtrackType::GRAPHICS bị xóa khỏi totalPss và được thay thế bằng bộ nhớ totalExportedDmabuf trong tính toán lostRAM trong ActManagerService.java như hiển thị bên dưới:

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;

Bộ nhớ MemtrackType::GL bị xóa khỏi totalPss và được thay thế bằng bộ nhớ GPU riêng ( gpuPrivateUsage ) trong tính toán lostRAM trong ActManagerService.java như hiển thị bên dưới:

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;

Cập nhật tính toán RAM bị mất

Cả tổng bộ nhớ GPU riêng và tổng bộ nhớ đệm DMA đã xuất đều chứa trong kernelUsed + totalPss đã bị xóa khỏi lostRAM . Điều này giúp loại bỏ cả tính biến thiên của tính toán kép và Memtrack khỏi tính toán RAM bị mất.

final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();

Thẩm định

Kiểm thử VTS thực thi quy tắc rằng các thiết bị chạy Android 12 có nhân Linux phiên bản 5.4 trở lên sẽ hỗ trợ API getGpuDeviceInfo() .

API Memtrack HAL mới getGpuDeviceInfo() phải trả về thông tin về thiết bị GPU đang được sử dụng.

Điều này cung cấp khả năng tính toán bộ nhớ tốt hơn và khả năng hiển thị về mức sử dụng bộ nhớ đệm và bộ nhớ GPU. Triển khai memtrack AIDL HAL để tính toán bộ nhớ và RAM bị mất tốt hơn. Tính năng này không phụ thuộc vào các dịch vụ của Google.

Thực hiện

Tính năng này phụ thuộc vào AIDL Memtrack HAL và hướng dẫn triển khai tính năng này trong Android 12 được đưa vào mã dưới dạng nhận xét.

Tất cả các HAL HIDL đều được lên kế hoạch chuyển đổi sang AIDL trong các bản phát hành trong tương lai.

Các API sau đã được thêm vào 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();

Để đảm bảo phiên bản của bạn hoạt động như dự định, hãy tích hợp các điểm theo dõi trong trình điều khiển GPU của bạn và triển khai API AIDL memtrack HAL getMemory() để trả về chính xác tổng bộ nhớ riêng tư GPU toàn cầu khi được gọi bằng PID 0 cho MemtrackType::GL và MemtrackRecord:: FLAG_SMPS_UNACCOUNTED.