メインコンテンツまでスキップ

メモリモデル

Neatフレームワークのランタイムは、エンコードされたビデオフレーム、デコードされたYUVプレーン、FP32入力テンソル、INT8量子化されたタイル、MLAスクラッチパッド画像など、大量のバイトを移動させます。明示的なメモリモデルなしでこれを行うと、各ステージの境界でコピーが発生することになります。このページでは、フレームワークがこれらのコピーを回避する方法について説明します。

バッファトリプル:(buffer_id, paddr, vaddr)

フレームワークが移動させるすべてのバッファは、次の3つの要素によって識別されます。

  • buffer_id — ランタイムがバッファのライフサイクル(参照カウント、セグメントの所有権)を追跡するために使用する安定した整数。
  • paddr — 物理アドレス。IOMMUから見たバッファのアドレス。MLA / EV74 / DMAハードウェアはこのアドレスを参照します。
  • vaddr — 仮想アドレス。アプリケーションから見たアドレス。CPUコードはこのアドレスを逆参照します。

このトリプルにより、バッファはコピーなしで、CPUまたはアクセラレータのいずれか一方のアドレスで参照できます。単一の割り当ては、カーネルのページテーブル(ソフトウェアが読み取れるようにするため)とIOMMUのページテーブル(ハードウェアがDMAできるようにするため)の両方に表示されます。

ステージ間のデータ受け渡しでは、バイトではなくトリプルが渡されます。

セグメント

バッファは、名前付きのセグメントから取得されます。セグメントは、特定のメモリ割り当て器(DMA-BUF、CMA、ION、プレーンヒープ)によってバックアップされ、誰がアクセスできるかに関するメタデータがタグ付けされた、連続したメモリ領域です(CPUのみ、MLAのみ、両方など)。ランタイムは、どのステージがバッファにアクセスするかに基づいて、各バッファに適切なセグメントを選択します。

例:

  • nv12_decodeセグメントには、H.264からデコードされたYUVが格納されます。CPUから読み取り可能で、診断用のタップに使用され、IOMMUから読み取り可能で、リサイズノードで使用されます。
  • mla_inputセグメントには、MLAに渡されるテッセレーションされたテンソルが格納されます。MLAハードウェアのみが読み取ります。CPUからのアクセスには、明示的なマップが必要です。
  • model_outputセグメントには、デテッセレーション後のFP32テンソルが格納されます。CPUから読み取り可能で、アプリケーションがそれらを取り出すことができます。

Tensorは、トリプルとともにセグメントを運びます。これにより、フレームワークはCPUコードからのピーク/ポークが有効かどうかを判断できます。

キャッシュコヒーレンス

MLA、EV74、およびCPUはそれぞれ独自のキャッシュを持っています。バッファが一方によって書き込まれ、もう一方によって読み取られる場合、フレームワークは境界でキャッシュフラッシュ/無効化の呼び出しを挿入します。アプリケーションコードは、これについて考える必要はありません。これは、バッファがステージをまたぐときに、セグメントレベルで処理されます。

アプリケーションコードがこれについて考える必要があるのは、Mappingを使用して、TensorBufferを直接CPUで読み書きするためにマップする場合だけです。フレームワークは、アンマップ時に適切な無効化(読み取りマップ)またはフラッシュ(書き込みマップ)を挿入します。MapModeTensorBuffer::map()を参照してください。

実際のゼロコピー

典型的な推論パイプライン:

file → demux → H.264 decode → resize → preproc → MLA → postproc → app

ゼロコピーを使用しない場合、7回のコピーが発生します。バッファーのトリプルとセグメントを使用すると、ゼロになります。つまり、各ステージで(buffer_id, paddr, vaddr)を次のステージに渡し、次のステージでその場で処理を行います。

フレームワークのプランナーは、連続するステージ間で共有できるようにセグメントを選択する役割を担います。隣接する2つのステージで互換性のないセグメント要件がある場合、プランナーはTransfer ConversionKindを挿入し、アクティブなConversionTraceCollectorに記録します。これに注意してください。これらは、ランタイム中に実際のバイトが移動する唯一の場所です。

カメラソースとアダプティブメモリ

ライブカメラフレームは、プラットフォームのカメラスタックを介して入力されるため、そのメモリタイプは、インストールされているカーネル、ドライバー、およびlibcamerasrcパスによって異なります。CameraInputは、まずデバイス/SiMaAIのゼロコピーメモリを要求します。そのプライベートブリッジは、GST_QUERY_ALLOCATIONを通じて標準プールを提案します。プールは、検証済みのプレーンを1つのパックされたSiMaAI割り当てから割り当て、DMA-BUFとしてエクスポートします。libcamerasrcは、これらのDMA-BUFをISPにインポートし、ブリッジは同じパックされた割り当てをアンラップして、下流のCVU/MLAステージに渡します。

カメラスタックがOS/libcameraバッファーのみを提供し、allow_cpu_fallbackが有効になっている場合、Neatはプライベートカメラメモリブリッジを挿入します。ブリッジは、各フレームをプールされたSiMaAIバッファーにコピーし、予想されるメタデータをスタンプし、そのバッファーをモデル管理のCVUプリ処理に渡します。このコピーは互換性ブリッジです。リサイズ、カラー変換、正規化、量子化、およびテッセレーションは、CVU/EV74で実行される必要があります。

MIPIカメラ入力を動作させるために、パブリックなOsToSimavideoconvert、またはvideoscaleステージを追加しないでください。CameraInputを使用し、ソースパスにメモリアダプテーションを任せてください。

関連する型

  • TensorBuffer — バッファーのトリプルコンテナ。
  • Segment — セグメントハンドル。
  • Mapping — 直接CPUアクセス用のRAIIマップハンドル。
  • MemoryContract — ノードがメモリを割り当てる方法。
  • ConversionKind::Transfer — セグメント間でコピーする唯一の変換の種類。

詳細

  • 「テンソルとバッファー」— デザインの詳細な解説の§0.10、§18、§19、§20。
  • 「TensorBuffer ABI」— デザインの詳細な解説の§20。