Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Grupos de memoria

Esta página describe las estructuras de datos y los métodos utilizados para comunicar de manera eficiente los búferes de operandos entre el controlador y el marco.

En el momento de la compilación del modelo, el marco proporciona los valores de los operandos constantes al controlador. Dependiendo de la vida útil del operando constante, sus valores se ubican en un vector HIDL o en un grupo de memoria compartida.

  • Si el tiempo de vida es CONSTANT_COPY , los valores se encuentran en el operandValues campo de la estructura del modelo. Debido a que los valores en el vector HIDL se copian durante la comunicación entre procesos (IPC), este se usa típicamente sólo para mantener una pequeña cantidad de datos, tales como operandos escalares (por ejemplo, el escalar de activación en ADD ) y pequeñas parámetros tensoriales (por ejemplo, el tensor de la forma en RESHAPE ).
  • Si el tiempo de vida es CONSTANT_REFERENCE , los valores se encuentran en el pools campo de la estructura del modelo. Solo los identificadores de los grupos de memoria compartida se duplican durante el IPC en lugar de copiar los valores sin procesar. Por lo tanto, es más eficiente almacenar una gran cantidad de datos (por ejemplo, los parámetros de peso en convoluciones) utilizando grupos de memoria compartida que los vectores HIDL.

En el momento de la ejecución del modelo, el marco proporciona los búferes de los operandos de entrada y salida al controlador. A diferencia de las constantes de tiempo de compilación que pueden enviarse en un vector HIDL, los datos de entrada y salida de una ejecución siempre se comunican a través de una colección de grupos de memoria.

El tipo de datos HIDL hidl_memory se utiliza tanto en la compilación y ejecución para representar un grupo de memoria compartida sin asignar. El conductor debe asignar la memoria en consecuencia para que sea utilizable basa en el nombre de la hidl_memory tipo de datos. Los nombres de memoria admitidos son:

  • ashmem : Android memoria compartida. Para más detalles, véase la memoria .
  • mmap_fd : memoria compartida con el respaldo de un descriptor de archivo a través de mmap .
  • hardware_buffer_blob : memoria compartida respaldada por una AHardwareBuffer con el formato AHARDWARE_BUFFER_FORMAT_BLOB . Disponible en Neural Networks (NN) HAL 1.2. Para más detalles, véase AHardwareBuffer .
  • hardware_buffer : memoria compartida respaldada por una AHardwareBuffer general, que no utiliza el formato AHARDWARE_BUFFER_FORMAT_BLOB . El búfer de hardware en modo no BLOB solo se admite en la ejecución del modelo. Disponible en NN HAL 1.2. Para más detalles, véase AHardwareBuffer .

Desde NN HAL 1.3, NNAPI admite dominios de memoria que proporcionan interfaces de asignación para búferes administrados por controladores. Los búferes administrados por el controlador también se pueden utilizar como entradas o salidas de ejecución. Para más detalles, ver los dominios de memoria .

NNAPI conductores deben admitir la asignación de ashmem y mmap_fd nombres de memoria. De NN HAL 1.3, los conductores también deben admitir la asignación de hardware_buffer_blob . Soporte para el modo generales no BLOB hardware_buffer y memoria dominios es opcional.

AHardwareBuffer

AHardwareBuffer es un tipo de memoria compartida que envuelve un búfer Gralloc . En Android 10, la API de Redes Neuronales (NNAPI) utilizando soportes AHardwareBuffer , que permite al conductor para llevar a cabo ejecuciones sin copiar datos, lo que mejora el rendimiento y consumo de energía para aplicaciones. Por ejemplo, una pila HAL de cámara puede pasar objetos AHardwareBuffer a la NNAPI para cargas de trabajo de aprendizaje automático utilizando identificadores AHardwareBuffer generados por las API de NDK de cámara y NDK de medios. Para obtener más información, consulte ANeuralNetworksMemory_createFromAHardwareBuffer .

AHardwareBuffer objetos utilizados en NNAPI se pasan al controlador a través de un hidl_memory struct llamado ya sea hardware_buffer o hardware_buffer_blob . El hidl_memory estructura hardware_buffer_blob representa sólo los objetos AHardwareBuffer con el AHARDWAREBUFFER_FORMAT_BLOB formato.

La información requerida por el marco se codifica en la hidl_handle campo de la hidl_memory struct. El hidl_handle campo envuelve native_handle , que codifica todos los metadatos necesarios sobre AHardwareBuffer o tampón Gralloc.

El conductor debe decodificar adecuadamente el proporcionado hidl_handle campo y el acceso de la memoria descrita por hidl_handle . Cuando el getSupportedOperations_1_2 , getSupportedOperations_1_1 , o getSupportedOperations se llama al método, el conductor debe detectar si se puede decodificar el proporcionado hidl_handle y acceder a la memoria descrita por hidl_handle . La preparación modelo debe fallar si el hidl_handle campo utilizado para un operando constante no es compatible. La ejecución debe fallar si el hidl_handle campo utilizado para un operando de entrada o salida de la ejecución no es compatible. Se recomienda para el conductor para devolver un GENERAL_FAILURE código de error si el modelo de preparación o ejecución falla.

Dominios de memoria

Para dispositivos que ejecutan Android 11 o superior, NNAPI admite dominios de memoria que proporcionan interfaces de asignación para búferes administrados por controladores. Esto permite pasar las memorias nativas del dispositivo a través de ejecuciones, suprimiendo la copia y transformación de datos innecesarias entre ejecuciones consecutivas en el mismo controlador. Este flujo se ilustra en la Figura 1.

Flujo de datos en búfer con y sin dominios de memoria
Datos de la Figura 1. Buffer de flujo usando dominios de memoria

La función de dominio de memoria está destinada a tensores que son en su mayoría internos del controlador y no necesitan acceso frecuente en el lado del cliente. Ejemplos de tales tensores incluyen los tensores de estado en modelos de secuencia. Para los tensores que necesitan acceso frecuente a la CPU en el lado del cliente, es preferible utilizar grupos de memoria compartida.

Para apoyar la función de la memoria de dominio, implementar IDevice::allocate para permitir que el marco de solicitud de asignación de búfer controlador gestionados. Durante la asignación, el marco proporciona las siguientes propiedades y patrones de uso para el búfer:

  • BufferDesc describe las propiedades requeridas de la memoria intermedia.
  • BufferRole describe el patrón de uso potencial de la memoria intermedia como una entrada o salida de un modelo preparado. Se pueden especificar varios roles durante la asignación del búfer, y el búfer asignado solo se puede usar como esos roles especificados.

El búfer asignado es interno al controlador. Un conductor puede elegir cualquier ubicación de búfer o diseño de datos. Cuando la memoria intermedia se asigna con éxito, el cliente de que el conductor puede hacer referencia a o interactuar con el tampón utilizando el token devuelto o la IBuffer objeto.

El token de IDevice::allocate se proporciona al hacer referencia a la memoria intermedia como uno de los MemoryPool objetos en la Request estructura de una ejecución. Para evitar que un proceso intente acceder al búfer asignado en otro proceso, el controlador debe aplicar la validación adecuada en cada uso del búfer. El conductor debe validar que el uso de tampón es uno de los BufferRole funciones proporcionadas durante la asignación y debe fallar la ejecución inmediatamente si el uso es ilegal.

El IBuffer objeto se utiliza para copiar la memoria explícita. En determinadas situaciones, el cliente del controlador debe inicializar el búfer administrado por el controlador desde un grupo de memoria compartida o copiar el búfer a un grupo de memoria compartida. Los casos de uso de ejemplo incluyen:

  • Inicialización del tensor de estado
  • Almacenamiento en caché de resultados intermedios
  • Ejecución de reserva en la CPU

Para apoyar estos casos de uso, el conductor debe aplicar IBuffer::copyTo y IBuffer::copyFrom con ashmem , mmap_fd y hardware_buffer_blob si es compatible con la asignación de dominio de memoria. Es opcional para el conductor para apoyar el modo no BLOB hardware_buffer .

Durante tampón de asignación, las dimensiones de la memoria intermedia se pueden deducir de las correspondientes operandos modelo de todas las funciones especificadas por BufferRole , y las dimensiones proporcionadas en BufferDesc . Con toda la información dimensional combinada, el búfer puede tener dimensiones o rango desconocidos. En tal caso, el búfer se encuentra en un estado flexible donde las dimensiones son fijas cuando se usa como entrada del modelo y en un estado dinámico cuando se usa como salida del modelo. El mismo búfer se puede usar con diferentes formas de salidas en diferentes ejecuciones y el controlador debe manejar el cambio de tamaño del búfer correctamente.

El dominio de la memoria es una característica opcional. Un controlador puede determinar que no puede admitir una solicitud de asignación determinada por varias razones. Por ejemplo:

  • El búfer solicitado tiene un tamaño dinámico.
  • El controlador tiene limitaciones de memoria que le impiden manejar grandes búferes.

Es posible que varios subprocesos diferentes lean del búfer administrado por el controlador al mismo tiempo. El acceso al búfer simultáneamente para escritura o lectura / escritura no está definido, pero no debe bloquear el servicio del controlador ni bloquear a la persona que llama de forma indefinida. El controlador puede devolver un error o dejar el contenido del búfer en un estado indeterminado.