Реализовать учет памяти DMABUF и графического процессора в Android 12.

На этой странице описываются различные улучшения учета памяти, представленные в Android 12.

Статистика DMA-BUF в sysfs

В Android 11 и Android 12 debugfs не может быть смонтирован в пользовательских сборках. Поэтому статистика DMA-BUF была добавлена ​​в sysfs в каталоге /sys/kernel/dmabuf/buffers в Android 12.

Путь Описание
/sys/kernel/dmabuf/buffers Каталог /sys/kernel/dmabuf/buffers содержит снимок внутреннего состояния каждого DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> содержит статистику для DMA-BUF с уникальным номером inode <inode_number> .
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name Этот файл, доступный только для чтения, содержит имя экспортера DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size Этот файл, доступный только для чтения, определяет размер DMA-BUF в байтах.

API libdmabufinfo анализирует статистику DMA-BUF sysfs для предоставления статистики по каждому экспортеру и буферу.

Обратите внимание, что драйверы ядра, которые экспортируют DMA-BUF, должны правильно установить поле exp_name struct dma_buf_export_info на имя экспортера перед вызовом API dma_buf_export() для создания DMA-BUF. Это необходимо для libdmabufinfo и инструмента dmabuf_dump для получения статистики по экспортерам, которая затем отображается в bugreport.

Инструмент dmabuf_dump был изменен для вывода этой информации с новым аргументом -b .

Статистика для фреймворка кучи DMA-BUF

ION в GKI 2.0 устарел в пользу фреймворка куч DMA-BUF , который является частью ядра Linux.

В Android 11 отслеживается следующая глобальная статистика ION:

  • Общий размер DMA-BUF, экспортируемых каждой кучей ION
  • Общий размер неиспользуемой предварительно выделенной памяти, хранящейся в каждой куче ION

В Android 11 нет интерфейса для отображения статистики кучи по ION.

В следующей таблице сравниваются интерфейсы статистики ION с их аналогами для устройств, использующих фреймворк кучи DMA-BUF в Android 12.

Android 11 или устройства, запускаемые с поддержкой ION в Android 12 Устройства, запускаемые с кучей DMA-BUF в Android 12
Статистика ION по куче Никто Анализируется из статистики DMA-BUF sysfs
Общий размер экспортированных DMA-BUF /sys/kernel/ion/total_heap_size_kb
(Не включает размер DMA-BUF, экспортируемых не-ION-экспортерами)
Анализируется из статистики DMA-BUF sysfs
(включая размер всех экспортированных DMA-BUF).
Общая память, объединенная в кучи /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Улучшить точность расчета потерянной оперативной памяти

Ранее расчет потерянной оперативной памяти производился следующим образом:

Final long lostRAM = memInfo.getTotalSizeKb( ) - ( totalPss - totalSwapPss )

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

- kernelUsed - memInfo.getZramTotalSizeKb() ;

Компонент totalPss включал использование памяти GPU (возвращаемое интерфейсом getMemory() Memtrack HAL). Компонент kernelUsed включал общее использование памяти DMA-BUF. Однако для устройств Android память GPU бралась из следующего:

  • Прямые выделения памяти, выполняемые драйвером графического процессора с использованием физического распределителя страниц
  • DMA-BUF, отображенные в адресное пространство графического процессора

Таким образом, DMA-BUF, которые были отображены в адресное пространство GPU, вычитались дважды при расчете потерянной RAM. Android 12 реализует решение для расчета размера DMA-BUF, отображенных в адресное пространство GPU, что означает, что он учитывается только один раз при расчете потерянной RAM.

Подробности решения следующие:

  • API Memtrack HAL getMemory() при вызове с PID 0 должен сообщать глобальный общий объем памяти GPU для MemtrackType::GL и MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() при вызове с PID 0 для MemtrackType , отличного от GL не должен завершаться ошибкой. Вместо этого он должен возвращать 0.
  • Решение GPU memory tracepoint/eBPF, добавленное в Android 12, учитывает общую память GPU. Вычитание общей частной памяти GPU из общей памяти GPU дает размер DMA-BUF, сопоставленных с адресным пространством GPU. Затем это значение можно использовать для повышения точности вычислений Lost RAM путем правильного учета использования памяти GPU.
  • В большинстве реализаций Memtrack HAL частная память графического процессора включена в totalPss и поэтому должна быть дедуплицирована перед удалением ее из lostRAM .

Реализованное решение подробно описано в следующем разделе.

Удалить изменчивость Memtrack из потерянной оперативной памяти

Поскольку реализации Memtrack HAL могут различаться у разных партнеров, память GPU, включенная в totalPSS из HAL, не всегда согласована. Чтобы устранить изменчивость из lostRAM , память, учитываемая в MemtrackType::GRAPHICS и MemtrackType::GL удаляется из totalPss во время расчета lostRAM .

Память MemtrackType::GRAPHICS удаляется из totalPss и заменяется памятью totalExportedDmabuf в расчете lostRAM в 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 и заменяется частной памятью GPU ( gpuPrivateUsage ) при вычислении lostRAM в ActivityManagerService.java , как показано ниже:

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;

Обновлен расчет потерянной оперативной памяти

Как общая частная память GPU, так и общая экспортированная память буфера DMA содержатся в kernelUsed + totalPss , которая удаляется из lostRAM . Это устраняет как двойной подсчет, так и изменчивость Memtrack из расчета потерянной RAM.

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

Проверка

Тесты VTS обеспечивают соблюдение правила, согласно которому устройства, работающие на базе Android 12 с ядром Linux версии 5.4 или выше, поддерживают API getGpuDeviceInfo() .

Новый API Memtrack HAL getGpuDeviceInfo() должен возвращать информацию об используемом устройстве GPU.

Это обеспечивает лучший учет памяти и видимость буфера DMA и использования памяти GPU. Реализуйте memtrack AIDL HAL для лучшего учета потерянной оперативной памяти и памяти. Эта функция не зависит от служб Google.

Выполнение

Эта функция зависит от AIDL Memtrack HAL , и инструкции по ее реализации в Android 12 включены в код в виде комментариев.

Планируется преобразовать все HIDL HAL в AIDL в будущих версиях.

В core/java/android/os/Debug.java добавлены следующие API:

   /**
     * 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();

Чтобы убедиться, что ваша версия работает так, как задумано, интегрируйте точки трассировки в драйверы графического процессора и реализуйте API AIDL memtrack HAL getMemory() для правильного возврата глобальной общей памяти GPU при вызове с PID 0 для MemtrackType::GL и MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.