メモリモデル
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で読み書きするためにマップする場合だけです。フレームワークは、アンマップ時に適切な無効化(読み取りマップ)またはフラッシュ(書き込みマップ)を挿入します。MapModeとTensorBuffer::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カメラ入力を動作させるために、パブリックなOsToSima、videoconvert、またはvideoscaleステージを追加しないでください。CameraInputを使用し、ソースパスにメモリアダプテーションを任せてください。
関連する型
TensorBuffer— バッファーのトリプルコンテナ。Segment— セグメントハンドル。Mapping— 直接CPUアクセス用のRAIIマップハンドル。MemoryContract— ノードがメモリを割り当てる方法。ConversionKind::Transfer— セグメント間でコピーする唯一の変換の種類。
詳細
- 「テンソルとバッファー」— デザインの詳細な解説の§0.10、§18、§19、§20。
- 「TensorBuffer ABI」— デザインの詳細な解説の§20。