Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

メモリプール

このページでは、ドライバとフレームワークの間でオペランドバッファを効率的に通信するために使用されるデータ構造とメソッドについて説明します。

モデルのコンパイル時に、フレームワークは定数オペランドの値をドライバーに提供します。定数オペランドの有効期間に応じて、その値はHIDLベクトルまたは共有メモリプールのいずれかに配置されます。

  • 有効期間がCONSTANT_COPY場合、値はモデル構造のoperandValuesフィールドにあります。 HIDLベクトルの値はプロセス間通信(IPC)中にコピーされるため、これは通常、スカラーオペランド(たとえば、 ADDのアクティブ化スカラー)や小さなテンソルパラメーター(たとえば、 RESHAPEの形状テンソル)。
  • 有効期間がCONSTANT_REFERENCE場合、値はモデル構造のpoolsフィールドにあります。共有メモリプールのハンドルのみが、生の値をコピーするのではなく、IPC中に複製されます。したがって、HIDLベクトルよりも、共有メモリプールを使用して大量のデータ(畳み込みの重みパラメーターなど)を保持する方が効率的です。

モデルの実行時に、フレームワークは入力オペランドと出力オペランドのバッファーをドライバーに提供します。 HIDLベクトルで送信される可能性のあるコンパイル時定数とは異なり、実行の入力データと出力データは常にメモリプールのコレクションを介して通信されます。

HIDLデータ型hidl_memoryは、コンパイルと実行の両方で使用され、マップされていない共有メモリプールを表します。ドライバは、 hidl_memoryデータ型の名前に基づいてメモリを使用できるように、それに応じてメモリをマップする必要があります。サポートされているメモリ名は次のとおりです。

  • ashmem :Android共有メモリ。詳細については、メモリを参照してください。
  • mmap_fdmmap介してファイル記述子でバックアップされた共有メモリ。
  • hardware_buffer_blob :AHARDWARE_BUFFER_FORMAT_BLOB形式のAHARDWARE_BUFFER_FORMAT_BLOBによってバックアップされた共有メモリ。 Neural Networks(NN)HAL1.2から入手できます。詳細については、 AHardwareBufferを参照してください。
  • hardware_buffer :フォーマットAHARDWARE_BUFFER_FORMAT_BLOB使用しない一般的なAHardwareBufferによってサポートされる共有メモリ。非BLOBモードのハードウェアバッファは、モデルの実行でのみサポートされます。NNHAL1.2から利用できます。詳細については、 AHardwareBufferを参照してください。

NN HAL 1.3以降、NNAPIは、ドライバー管理バッファー用のアロケーターインターフェイスを提供するメモリドメインをサポートします。ドライバ管理のバッファは、実行の入力または出力としても使用できます。詳細については、メモリドメインを参照してください。

NNAPIドライバーは、 ashmemおよびmmap_fdメモリ名のマッピングをサポートする必要があります。 NN HAL 1.3以降、ドライバーはhardware_buffer_blobマッピングもサポートする必要がありhardware_buffer_blob 。一般的な非BLOBモードのhardware_bufferおよびメモリドメインのサポートはオプションです。

AHardwareBuffer

AHardwareBufferは、 Grallocバッファーをラップする共有メモリの一種です。 Android 10では、ニューラルネットワークAPI(NNAPI)がAHardwareBufferの使用をサポートしているため、ドライバーはデータをコピーせずに実行できるため、アプリのパフォーマンスと消費電力が向上します。たとえば、カメラHALスタックは、カメラNDKおよびメディアNDK APIによって生成されたAHardwareBufferハンドルを使用して、機械学習ワークロード用にAHardwareBufferオブジェクトをNNAPIに渡すことができます。詳細については、 ANeuralNetworksMemory_createFromAHardwareBuffer参照してください。

NNAPIで使用されるAHardwareBufferオブジェクトは、 hardware_bufferまたはhardware_buffer_blobという名前のhidl_memory構造体を介してドライバーに渡されhardware_buffer_blobhidl_memory構造体hardware_buffer_blobは、 AHARDWAREBUFFER_FORMAT_BLOB形式のAHardwareBufferオブジェクトのみを表します。

フレームワークに必要な情報は、 hidl_memory構造体のhidl_handleフィールドにエンコードされます。 hidl_handleフィールドはhidl_handleラップしnative_handle 。これは、AHardwareBufferまたはGrallocバッファーに関する必要なすべてのメタデータをエンコードします。

ドライバが適切に提供される復号しなければならないhidl_handleフィールドとアクセスによって説明したメモリhidl_handle 。場合getSupportedOperations_1_2getSupportedOperations_1_1 、又はgetSupportedOperationsメソッドが呼び出され、運転者は、それが提供デコードできるかどうかを検出する必要がありhidl_handleとアクセスによって説明したメモリhidl_handle 。定数オペランドに使用されるhidl_handleフィールドがサポートされていない場合、モデルの準備は失敗する必要があります。実行の入力または出力オペランドに使用されるhidl_handleフィールドがhidl_handleされていない場合、実行は失敗する必要があります。モデルの準備または実行が失敗した場合、ドライバーはGENERAL_FAILUREエラーコードを返すことをお勧めします。

メモリドメイン

Android 11以降を実行しているデバイスの場合、NNAPIは、ドライバー管理のバッファーにアロケーターインターフェイスを提供するメモリドメインをサポートします。これにより、実行間でデバイスのネイティブメモリを渡すことができ、同じドライバでの連続した実行間の不要なデータのコピーと変換を抑制できます。このフローを図1に示します。

メモリドメインがある場合とない場合のバッファデータフロー
図1.メモリドメインを使用したバッファデータフロー

メモリドメイン機能は、ほとんどがドライバーの内部にあり、クライアント側で頻繁にアクセスする必要のないテンソルを対象としています。このようなテンソルの例には、シーケンスモデルの状態テンソルが含まれます。クライアント側で頻繁にCPUアクセスを必要とするテンソルの場合、共有メモリプールを使用することをお勧めします。

メモリドメイン機能をサポートするには、 IDevice::allocate実装して、フレームワークがドライバー管理のバッファー割り当てを要求できるようにします。割り当て中に、フレームワークはバッファに次のプロパティと使用パターンを提供します。

  • BufferDescは、バッファの必要なプロパティを記述します。
  • BufferRoleは、準備されたモデルの入力または出力として、バッファーの潜在的な使用パターンを記述します。バッファの割り当て中に複数のロールを指定でき、割り当てられたバッファは指定されたロールとしてのみ使用できます。

割り当てられたバッファはドライバの内部にあります。ドライバーは、任意のバッファー位置またはデータレイアウトを選択できます。バッファーが正常に割り当てられると、ドライバーのクライアントは、返されたトークンまたはIBufferオブジェクトを使用して、バッファーを参照または操作できます。

IDevice::allocateからのトークンは、実行のRequest構造でMemoryPoolオブジェクトの1つとしてバッファーを参照するときに提供されます。プロセスが別のプロセスに割り当てられたバッファーにアクセスしようとするのを防ぐために、ドライバーはバッファーを使用するたびに適切な検証を適用する必要があります。ドライバは、バッファの使用が割り当て中に提供されたBufferRoleロールの1つであることを検証する必要があり、使用が違法である場合はすぐに実行に失敗する必要があります。

IBufferオブジェクトは、明示的なメモリコピーに使用されます。特定の状況では、ドライバーのクライアントは、共有メモリプールからドライバー管理バッファーを初期化するか、バッファーを共有メモリプールにコピーする必要があります。ユースケースの例は次のとおりです。

  • 状態テンソルの初期化
  • 中間結果のキャッシュ
  • CPUでのフォールバック実行

これらのユースケースをサポートするには、ドライバーは、メモリドメイン割り当てをサポートしている場合、 ashmemmmap_fd 、およびhardware_buffer_blob使用してIBuffer::copyToおよびIBuffer::copyFromを実装する必要があります。ドライバーが非BLOBモードのhardware_bufferをサポートすることはオプションです。

バッファ割り当ての際に、バッファの大きさは、で指定されたすべてのロールの対応するモデルオペランドから推定することができるBufferRole 、及びに設け寸法BufferDesc 。すべてのディメンション情報を組み合わせると、バッファのディメンションまたはランクが不明になる可能性があります。このような場合、バッファは柔軟な状態にあり、モデル入力として使用されると寸法が固定され、モデル出力として使用されると動的状態になります。同じバッファーをさまざまな実行でさまざまな形状の出力で使用でき、ドライバーはバッファーのサイズ変更を適切に処理する必要があります。

メモリドメインはオプション機能です。ドライバーは、いくつかの理由で、特定の割り当て要求をサポートできないと判断できます。例えば:

  • 要求されたバッファは動的サイズです。
  • ドライバにはメモリの制約があり、大きなバッファを処理できません。

複数の異なるスレッドがドライバー管理バッファーから同時に読み取る可能性があります。書き込みまたは読み取り/書き込みのために同時にバッファーにアクセスすることは定義されていませんが、ドライバーサービスをクラッシュさせたり、呼び出し元を無期限にブロックしたりしてはなりません。ドライバはエラーを返すか、バッファの内容を不確定な状態のままにする可能性があります。