Administrador de NPU

Android 17 y versiones posteriores admiten el administrador de la unidad de procesamiento neuronal (NPU) (com.android.npumanager), que coordina la asignación y la programación de los recursos de la NPU en los servicios del sistema y las cargas de trabajo de las aplicaciones. Al trasladar el arbitraje de recursos de los daemons personalizados del proveedor a la plataforma de Android, NPU Manager aumenta la previsibilidad, evita la falta de recursos, administra los límites térmicos y mejora el rendimiento general del dispositivo.

Antecedentes y motivación

Antes del NPU Manager, las apps y los módulos del sistema enviaban cargas de trabajo directamente a los controladores del proveedor o a los servicios propietarios. Este enfoque tenía varias desventajas:

  • Competencia ineficiente por los recursos: Las cargas de trabajo pesadas de aprendizaje automático (como los motores de inferencia de modelos de lenguaje grandes [LLM] o los sistemas de visión integrados en el dispositivo) competían directamente con otros sistemas de alta prioridad por los recursos finitos de la NPU (como la SRAM, la memoria de pesos y los canales de ejecución).
  • Inestabilidad del sistema: Las cargas de trabajo no coordinadas podrían activar la regulación térmica, errores de página de memoria o el daemon de eliminación de memoria baja (LMKD) si las demandas superan la capacidad del hardware.
  • Priorización ineficiente: El servidor del sistema no puede ajustar la prioridad de la NPU en respuesta a los cambios de contexto, como una tarea en segundo plano que carga un modelo masivo mientras una canalización de cámara sensible a la latencia o un asistente del usuario está activo en primer plano.

El NPU Manager aborda estos desafíos actuando como un árbitro a nivel del sistema que controla la carga del modelo y ajusta de forma dinámica las prioridades de ejecución según el estado actual del dispositivo y los estados de la app.

Arquitectura del sistema

El NPU Manager se implementa como un servicio del sistema llamado npu que se ejecuta dentro del framework de Android. El NPU Manager aísla la coordinación de alto nivel de las políticas de programación de la implementación del controlador del proveedor de bajo nivel.

En el siguiente diagrama, se ilustran las capas del entorno de NPU Manager:

Capas del entorno de NPU Manager

Figura 1: Son las capas del entorno de NPU Manager.

Componentes clave

  • Cliente de la API del framework (android.npumanager.NpuManager): Es el punto de entrada que usan los clientes para solicitar reservas de carga del modelo.
  • Servicio del sistema (npu): Es un servicio del sistema que controla las aprobaciones de carga del modelo y administra los comandos de interrupción según las reglas de prioridad de programación.
  • HAL de programación de la NPU (android.hardware.npu): Es una interfaz basada en AIDL que retransmite las devoluciones de llamada de prioridades de las apps para Android entre el framework y el controlador.
  • Controlador del proveedor: Es un controlador de bajo nivel que controla los bloques de ejecución de hardware y que implementa mecanismos de priorización de bajo nivel.

API del SDK y del framework

Antes de llamar a las bibliotecas de redes neuronales de bajo nivel o cargar archivos de modelos, los clientes del framework deben interactuar con el servicio NpuManager. Para ello, los clientes primero definen una solicitud de carga del modelo y, luego, ejecutan el flujo de aprobación y solicitud.

Solicitud de carga del modelo

Una solicitud de carga del modelo se representa con ModelLoadRequest. Este objeto contiene lo siguiente:

  • ID de solicitud único
  • Clase de tamaño del modelo estimada, como NPU_MODEL_SIZE_LESS_THAN_1GB o NPU_MODEL_SIZE_GREATER_THAN_2G
  • Prioridad prevista, como NPU_MODEL_PRIORITY_BACKGROUND, NPU_MODEL_PRIORITY_NORMAL o NPU_MODEL_PRIORITY_OPPORTUNISTIC

En el siguiente ejemplo de código, se compila un ModelLoadRequest con un límite de tamaño superior a 2 GB y una prioridad de ejecución normal:

ModelLoadRequest request = new ModelLoadRequest.Builder(requestId)
        .setSize(NPU_MODEL_SIZE_GREATER_THAN_2G)
        .setPriority(NPU_MODEL_PRIORITY_NORMAL)
        .build();

Flujo de solicitud y aprobación

Los clientes invocan requestCanLoadModel de forma asíncrona:

npuManager.requestCanLoadModel(request, callback, executor);

Cuando los recursos de la NPU están disponibles, el framework responde con ModelLoadRequestCallback y los siguientes eventos:

  • onCanLoadModel(request, status, listener): Se activa cuando se aprueba la solicitud. El cliente recibe un token de NpuManager.ModelLoadStatusListener. Después de que el cliente cargue por completo el modelo en la memoria del controlador, debe llamar a listener.notifyModelLoaded(request).
  • onRequestUnloadModel(request) o onRequestUnloadModel(request, reason): Se activa cuando el sistema experimenta presión de recursos (como una solicitud entrante en primer plano o un aumento repentino de la temperatura) y requiere que el cliente libere su modelo. Después de recuperar los recursos de la NPU, el cliente llama a listener.notifyModelUnloaded(request).
  • onModelLoadRequestComplete(request, status): Informa al cliente sobre los cambios finales en el ciclo de vida de la solicitud, como la cancelación.

Los clientes pueden cancelar las invitaciones pendientes con cancelModelLoad(request).

Integración del HAL y del proveedor

Para admitir NPU Manager, las implementaciones específicas del proveedor para cada dispositivo deben cumplir con las interfaces de servicio de AIDL de android.hardware.npu.

Configuración de la programación

El sistema retransmite la prioridad de la app con el AIDL de SchedulingConfig, la estructura de AIDL de SchedulingConfig definida en IScheduling.aidl:

package android.hardware.npu;

@VintfStability
parcelable SchedulingConfig {
    int minPriority;
    int maxPriority;
    int uid;
    int appPriority;
    boolean hasDirectAccess;
    boolean canAttributeOtherUid;
}

Con esta estructura, el Administrador de la NPU coordina las alineaciones de prioridad. Por ejemplo, si una app en segundo plano envía un trabajo de alta prioridad, la prioridad se ajusta a la baja para evitar interferencias con los gráficos en primer plano.

Estado y generación de perfiles de la tarea

Los drivers del proveedor deben informar al administrador el estado del ciclo de vida de los grupos de ejecución de la NPU. WorkInfo hace un seguimiento de las tareas (definidas en WorkInfo.aidl):

package android.hardware.npu;

import android.hardware.npu.NpuUuid;

@VintfStability
parcelable WorkInfo {
    int id;
    @nullable NpuUuid groupId;
    int uid;
    int debugPid;
    int originalUid;
    @nullable String debugFeatureId;
    int jobPriority;
    int effectivePriority;
    long timestampMs;
    int deviceNumber;
}

Eliminación de rebotes de eventos

El framework de programación admite la eliminación de rebotes de eventos con el parámetro debounce_duration_ms dentro del registro de devolución de llamada de programación. Esto evita la saturación de registros y suprime las notificaciones rápidas, por ejemplo, los eventos consecutivos de inicio y finalización para los modelos repetitivos.

Los estados del ciclo de vida de la devolución de llamada se informan de la siguiente manera:

  • onWorkRequested: El servicio del proveedor pone en cola la carga de trabajo.
  • onWorkStarted: Comienza la ejecución de la carga de trabajo.
    • NPU_START_REASON_INITIAL: Es la primera ejecución.
    • NPU_START_REASON_RESUMED: Se reanudó la ejecución después de la interrupción.
  • onWorkEnded: Finalizó la ejecución de la carga de trabajo.
    • NPU_END_REASON_COMPLETED: Se completó la ejecución correctamente.
    • NPU_END_REASON_CANCELLED_USER: El cliente canceló la solicitud.
    • NPU_END_REASON_CANCELLED_SYSTEM: Se interrumpió por la política del sistema.
    • NPU_END_REASON_FAILED: Error de ejecución o falla del controlador.
    • NPU_END_REASON_PAUSED: Se suspende temporalmente para tareas de mayor prioridad.

Preparación y pruebas de dispositivos

Asegúrate de que estas configuraciones estén vigentes antes de verificar el estado del dispositivo.

Declaraciones de la aplicación

Los clientes que deseen priorizar la programación de la NPU deben declarar la función de hardware de la NPU en su AndroidManifest.xml:

<uses-feature android:name="android.hardware.npu" android:required="false" />

En el caso de los modelos implementados en generaciones más recientes de hardware de socios, es posible que esta declaración sea necesaria para la creación óptima del motor.

Pruebas de integración de VTS

Las implementaciones de HAL de la NPU se pueden validar con pruebas funcionales de VTS, por ejemplo, VtsHalNpuSchedulingTargetTest.