NPU マネージャー

Android 17 以降では、Neural Processing Unit(NPU)マネージャー(com.android.npumanager)がサポートされています。これは、システム サービスとアプリケーション ワークロード全体で NPU リソースの割り当てとスケジューリングを調整します。リソース調停をカスタム ベンダー デーモンから Android プラットフォームに移行することで、NPU マネージャーは予測可能性を高め、リソース不足を防ぎ、温度境界を管理し、デバイスの全体的なパフォーマンスを向上させます。

背景と動機

NPU マネージャーが登場する前は、アプリとシステム モジュールがワークロードをベンダー ドライバまたは独自のサービスに直接送信していました。このアプローチにはいくつかの欠点がありました。

  • 非効率的なリソース競合: 大規模言語モデル(LLM)推論エンジンやオンデバイス ビジョン システムなどの負荷の高い機械学習ワークロードは、有限の NPU リソース(SRAM、重みメモリ、実行チャネルなど)をめぐって、他の優先度の高いシステムと直接競合していました。
  • システムの不安定性: 調整されていないワークロードは、要求がハードウェア容量を超えると、サーマル スロットリング、メモリ ページ フォールト、または低メモリ キラー デーモン(LMKD)をトリガーする可能性があります。
  • 非効率的な優先順位付け: システム サーバーは、コンテキストの変更に応じて NPU の優先度を調整できません。たとえば、レイテンシの影響を受けやすいカメラ パイプラインやユーザー アシスタントがフォアグラウンドでアクティブになっているときに、バックグラウンド タスクで大規模なモデルを読み込む場合などです。

NPU マネージャーは、モデルの読み込みをゲート処理し、現在のデバイスの健全性とアプリの状態に基づいて実行の優先度を動的に調整するシステムレベルの調停者として機能することで、これらの課題に対処します。

システム アーキテクチャ

NPU マネージャーは、Android フレームワーク内で実行される npu という名前のシステム サービスとして実装されます。NPU マネージャーは、スケジューリング ポリシーの高レベルの調整を、低レベルのベンダー ドライバ実装から分離します。

次の図式は、NPU マネージャーの環境レイヤを示しています。

NPU Manager 環境レイヤ

図 1.NPU マネージャーの環境レイヤ。

主要コンポーネント

  • フレームワーク API クライアント(android.npumanager.NpuManager): クライアントがモデルの読み込み予約をリクエストするために使用するエントリ ポイント
  • システム サービス(npu): モデルの読み込み承認をゲート処理し、スケジューリング優先度ルールに基づいてプリエンプション コマンドを管理するシステム サービス
  • NPU スケジューリング HAL(android.hardware.npu): フレームワークとドライバの間で Android アプリの優先度コールバックをリレーする AIDL ベースのインターフェース
  • ベンダー ドライバ: ハードウェア実行ブロックを制御し、低レベルの優先順位付けメカニズムを実装する低レベルのドライバ

SDK とフレームワーク API

低レベルのニューラル ネットワーク ライブラリを呼び出すか、モデルファイルを読み込む前に、フレームワーク クライアントは NpuManager サービスとやり取りする必要があります。これを行うには、クライアントが最初にモデルの読み込みリクエストを定義し、リクエストと承認のフローを実行します。

モデルの読み込みリクエスト

モデルの読み込みリクエストは ModelLoadRequest で表されます。このオブジェクトには次のものが含まれます。

  • 一意のリクエスト ID
  • 推定モデルサイズクラス(NPU_MODEL_SIZE_LESS_THAN_1GBNPU_MODEL_SIZE_GREATER_THAN_2G など)
  • 目的の優先度(NPU_MODEL_PRIORITY_BACKGROUNDNPU_MODEL_PRIORITY_NORMALNPU_MODEL_PRIORITY_OPPORTUNISTIC など)

次のコード例では、サイズ上限が 2 GB を超え、実行優先度が通常の ModelLoadRequest を作成します。

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

リクエストと承認のフロー

クライアントは requestCanLoadModel を非同期で呼び出します。

npuManager.requestCanLoadModel(request, callback, executor);

NPU リソースが使用可能な場合、フレームワークは ModelLoadRequestCallback を使用して、次のイベントで応答します。

  • onCanLoadModel(request, status, listener): リクエストが承認されたときに発生します。クライアントは NpuManager.ModelLoadStatusListener トークンを受け取ります。クライアントがドライバ メモリにモデルを完全に読み込んだら、listener.notifyModelLoaded(request) を呼び出す必要があります。
  • onRequestUnloadModel(request) または onRequestUnloadModel(request, reason): システムでリソースの圧迫(フォアグラウンド リクエストの受信や温度スパイクなど)が発生し、クライアントがモデルを解放する必要がある場合に発生します。NPU リソースを再利用した後、クライアントは listener.notifyModelUnloaded(request) を呼び出します。
  • onModelLoadRequestComplete(request, status): キャンセルなど、最終的なリクエスト ライフサイクルの変更をクライアントに通知します。

クライアントは、cancelModelLoad(request) を使用して、保留中の招待をキャンセルできます。

HAL とベンダーの統合

NPU マネージャーをサポートするには、デバイス固有のベンダー実装が android.hardware.npu AIDL サービス インターフェースに準拠している必要があります。

スケジューリング構成

システムは、IScheduling.aidlで定義されている SchedulingConfig AIDL の SchedulingConfig AIDL 構造体を使用して、アプリの優先度をリレーします。

package android.hardware.npu;

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

この構造体を使用して、NPU マネージャーは優先度の調整を調整します。たとえば、バックグラウンド アプリが優先度の高いジョブを送信した場合、フォアグラウンド グラフィックとの干渉を防ぐために優先度が引き下げられます。

タスク ステータスとプロファイリング

ベンダー ドライバは、NPU 実行グループのライフサイクル ステータスをマネージャーに報告する必要があります。WorkInfo は、 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;
}

イベントのデバウンス

スケジューリング フレームワークは、スケジューリング コールバック登録内の debounce_duration_ms パラメータを使用して、イベントのデバウンスをサポートしています。 これにより、ログのフラッディングを回避し、高速通知を抑制できます。たとえば、繰り返されるモデルの連続する開始イベントと終了イベントなどです。

コールバックのライフサイクル状態は次のように報告されます。

  • onWorkRequested: ワークロードがベンダー サービスによってキューに登録されます。
  • onWorkStarted: ワークロードの実行が開始されます。
    • NPU_START_REASON_INITIAL: 最初の実行。
    • NPU_START_REASON_RESUMED: プリエンプション後に実行が再開されました。
  • onWorkEnded: ワークロードの実行が終了しました。
    • NPU_END_REASON_COMPLETED: 実行が正常に完了しました。
    • NPU_END_REASON_CANCELLED_USER: クライアントによってキャンセルされました。
    • NPU_END_REASON_CANCELLED_SYSTEM: システム ポリシーによってプリエンプトされました。
    • NPU_END_REASON_FAILED: 実行エラーまたはドライバの障害。
    • NPU_END_REASON_PAUSED: 優先度の高いタスクのために一時的に中断されました。

デバイスの準備とテスト

デバイスの状態を確認する前に、これらの構成が設定されていることを確認してください。

アプリケーションの宣言

NPU スケジューリングの優先順位付けを求めるクライアントは、AndroidManifest.xml で NPU ハードウェア機能を宣言する必要があります。

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

新しい世代のパートナー ハードウェアにデプロイされたモデルの場合、エンジンを最適に作成するにはこの宣言が必要になることがあります。

VTS 統合テスト

NPU HAL 実装は、VTS 機能テスト(VtsHalNpuSchedulingTargetTest など)で検証できます。