На этой странице описаны структуры данных и методы, используемые для эффективной передачи буферов операндов между драйвером и платформой.
Во время компиляции модели платформа предоставляет драйверу значения постоянных операндов. В зависимости от времени жизни константного операнда его значения располагаются либо в векторе HIDL, либо в пуле общей памяти.
- Если время жизни равно
CONSTANT_COPY
, значения располагаются вoperandValues
структуры модели. Поскольку значения вектора HIDL копируются во время межпроцессного взаимодействия (IPC), он обычно используется только для хранения небольшого объема данных, таких как скалярные операнды (например, скаляр активации вADD
) и небольшие тензорные параметры (например, тензор формы вRESHAPE
). - Если время жизни равно
CONSTANT_REFERENCE
, значения располагаются в полеpools
структуры модели. Во время IPC дублируются только дескрипторы пулов общей памяти, а не копирование необработанных значений. Следовательно, более эффективно хранить большой объем данных (например, весовые параметры в свертках) с использованием пулов общей памяти, чем векторов HIDL.
Во время выполнения модели платформа предоставляет драйверу буферы входных и выходных операндов. В отличие от констант времени компиляции, которые могут быть отправлены в векторе HIDL, входные и выходные данные выполнения всегда передаются через набор пулов памяти.
Тип данных HIDL hidl_memory
используется как при компиляции, так и при выполнении для представления неотображенного пула общей памяти. Драйвер должен соответствующим образом сопоставить память, чтобы сделать ее пригодной для использования на основе имени типа данных hidl_memory
. Поддерживаемые имена памяти:
-
ashmem
: общая память Android. Подробнее см. Память . -
mmap_fd
: Общая память, поддерживаемая файловым дескриптором черезmmap
. -
hardware_buffer_blob
: общая память, поддерживаемая AHardwareBuffer в форматеAHARDWARE_BUFFER_FORMAT_BLOB
. Доступно в Neural Networks (NN) HAL 1.2. Дополнительные сведения см. в разделе AHardwareBuffer . -
hardware_buffer
: общая память, поддерживаемая общим AHardwareBuffer, который не использует форматAHARDWARE_BUFFER_FORMAT_BLOB
. Аппаратный буфер без режима BLOB поддерживается только при выполнении модели. Доступно начиная с NN HAL 1.2. Дополнительные сведения см. в разделе AHardwareBuffer .
Начиная с NN HAL 1.3, NNAPI поддерживает домены памяти, которые предоставляют интерфейсы распределителя для буферов, управляемых драйвером. Буферы, управляемые драйвером, также могут использоваться в качестве входов или выходов выполнения. Дополнительные сведения см. в разделе Домены памяти .
Драйверы NNAPI должны поддерживать сопоставление имен памяти ashmem
и mmap_fd
. Начиная с NN HAL 1.3, драйверы также должны поддерживать отображение hardware_buffer_blob
. Поддержка общего режима hardware_buffer
и доменов памяти, отличного от режима BLOB, является необязательной.
Аппаратный буфер
AHardwareBuffer — это тип общей памяти, которая окружает буфер Gralloc . В Android 10 API нейронных сетей (NNAPI) поддерживает использование AHardwareBuffer , позволяя драйверу выполнять действия без копирования данных, что повышает производительность и энергопотребление приложений. Например, стек HAL камеры может передавать объекты AHardwareBuffer в NNAPI для рабочих нагрузок машинного обучения с помощью дескрипторов AHardwareBuffer, созданных API-интерфейсами NDK камеры и медиа-NDK. Дополнительные сведения см. в ANeuralNetworksMemory_createFromAHardwareBuffer
.
Объекты AHardwareBuffer, используемые в NNAPI, передаются драйверу через структуру hidl_memory
с именем hardware_buffer
или hardware_buffer_blob
. Структура hidl_memory
hardware_buffer_blob
представляет только объекты AHardwareBuffer в формате AHARDWAREBUFFER_FORMAT_BLOB
.
Информация, необходимая платформе, кодируется в поле hidl_handle
структуры hidl_memory
. Поле hidl_handle
обертывает native_handle
, который кодирует все необходимые метаданные о буфере AHardwareBuffer или Gralloc.
Драйвер должен правильно декодировать предоставленное поле hidl_handle
и получить доступ к памяти, описанной hidl_handle
. Когда вызывается метод getSupportedOperations_1_2
, getSupportedOperations_1_1
или getSupportedOperations
, драйвер должен определить, может ли он декодировать предоставленный hidl_handle
и получить доступ к памяти, описанной hidl_handle
. Подготовка модели должна завершиться неудачей, если поле hidl_handle
, используемое для постоянного операнда, не поддерживается. Выполнение должно завершиться неудачно, если поле hidl_handle
, используемое для входного или выходного операнда выполнения, не поддерживается. Драйверу рекомендуется возвращать код ошибки GENERAL_FAILURE
в случае сбоя подготовки или выполнения модели.
Домены памяти
Для устройств под управлением Android 11 или более поздней версии NNAPI поддерживает домены памяти, которые предоставляют интерфейсы распределителя для буферов, управляемых драйвером. Это позволяет передавать собственную память устройства между выполнениями, подавляя ненужное копирование и преобразование данных между последовательными выполнениями на одном и том же драйвере. Этот поток показан на рисунке 1.
Рисунок 1. Буферизация потока данных с использованием доменов памяти
Функция домена памяти предназначена для тензоров, которые в основном являются внутренними для драйвера и не требуют частого доступа на стороне клиента. Примеры таких тензоров включают тензоры состояния в моделях последовательностей. Для тензоров, которым требуется частый доступ к ЦП на стороне клиента, предпочтительнее использовать пулы общей памяти.
Для поддержки функции домена памяти реализуйте IDevice::allocate
чтобы позволить платформе запрашивать выделение буфера, управляемое драйвером. Во время выделения платформа предоставляет следующие свойства и шаблоны использования буфера:
-
BufferDesc
описывает необходимые свойства буфера. -
BufferRole
описывает потенциальный шаблон использования буфера как входные или выходные данные подготовленной модели. Во время выделения буфера можно указать несколько ролей, а выделенный буфер можно использовать только в качестве указанных ролей.
Выделенный буфер является внутренним для драйвера. Драйвер может выбрать любое расположение буфера или расположение данных. Когда буфер успешно выделен, клиент драйвера может ссылаться на буфер или взаимодействовать с ним, используя возвращенный токен или объект IBuffer
.
Токен из IDevice::allocate
предоставляется при ссылке на буфер как на один из объектов MemoryPool
в структуре Request
выполнения. Чтобы предотвратить попытку процесса получить доступ к буферу, выделенному в другом процессе, драйвер должен применять правильную проверку при каждом использовании буфера. Драйвер должен проверить, что использование буфера является одной из ролей BufferRole
, предоставленных во время выделения, и должен немедленно прекратить выполнение, если использование является незаконным.
Объект IBuffer
используется для явного копирования памяти. В определенных ситуациях клиент драйвера должен инициализировать управляемый драйвером буфер из пула общей памяти или скопировать буфер в пул общей памяти. Примеры вариантов использования включают в себя:
- Инициализация тензора состояния
- Кэширование промежуточных результатов
- Резервное выполнение на ЦП
Для поддержки этих вариантов использования драйвер должен реализовать IBuffer::copyTo
и IBuffer::copyFrom
с ashmem
, mmap_fd
и hardware_buffer_blob
, если он поддерживает выделение домена памяти. Драйвер необязательно поддерживает hardware_buffer
в режиме, отличном от BLOB.
Во время выделения буфера размеры буфера можно вывести из соответствующих операндов модели всех ролей, указанных в BufferRole
, и размеров, предоставленных в BufferDesc
. При объединении всей информации о измерениях буфер может иметь неизвестные измерения или ранг. В таком случае буфер находится в гибком состоянии, когда размеры фиксированы при использовании в качестве входных данных модели, и в динамическом состоянии при использовании в качестве выходных данных модели. Один и тот же буфер может использоваться с разными формами выходных данных в разных исполнениях, и драйвер должен правильно обрабатывать изменение размера буфера.
Домен памяти является дополнительной функцией. Драйвер может определить, что он не может поддерживать данный запрос на выделение по ряду причин. Например:
- Запрошенный буфер имеет динамический размер.
- Драйвер имеет ограничения памяти, не позволяющие ему обрабатывать большие буферы.
Несколько разных потоков могут одновременно читать данные из буфера, управляемого драйвером. Одновременный доступ к буферу для записи или чтения/записи не определен, но он не должен вызывать сбой в работе службы драйвера или блокировать вызывающую сторону на неопределенный срок. Драйвер может вернуть ошибку или оставить содержимое буфера в неопределенном состоянии.