На этой странице описываются различные улучшения учета памяти, представленные в 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 .