Реализовать учет памяти 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_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 могли получать статистику по каждому экспортёру, которая затем отображается в отчёте об ошибках.

Инструмент 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

Повысить точность расчета потерянной оперативной памяти

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

окончательный длинный lostRAM = memInfo.getTotalSizeKb( ) - ( totalPss - totalSwapPss )

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

- kernelUsed - memInfo.getZramTotalSizeKb() ;

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

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

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

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

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

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

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

Поскольку реализации Memtrack HAL могут различаться у разных партнёров, объём памяти графического процессора, включённый в 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 и заменяется частной памятью графического процессора ( 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;

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

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

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 и памяти графического процессора. Реализуйте 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 .