nVidia RDMA GPUDirect は常に (CPU の物理アドレス空間内の) 物理アドレスのみを操作しますか?

StackOverflow https://stackoverflow.com/questions/19841815

質問

みなさんご存じのとおり: http://en.wikipedia.org/wiki/IOMMU#利点

ペリフェラル メモリ ページングは​​、 イオム. 。PCI-SIG PCIEアドレス翻訳サービス(ATS)ページリクエストインターフェイス(PRI)拡張機能を使用した周辺機器は、メモリマネージャーサービスの必要性を検出および信号することができます。

enter image description here

ただし、CUDA >= 5.0 で nVidia GPU を使用する場合、RDMA GPUDirect を使用できるため、次のことがわかります。

http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#how-gpudirect-rdma-works

従来、Bar Windowsなどのリソースは、メモリマッピングI/O(MMIO)アドレスとしてCPUのMMUを使用して、ユーザーまたはカーネルアドレススペースにマッピングされています。ただし、 現在のオペレーティングシステムには、ドライバー間でMMIO領域を交換するための十分なメカニズムがありません, 、NVIDIAカーネルドライバーが関数をエクスポートして、必要なアドレスの翻訳とマッピングを実行します。

http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#supported-systems

GPUDirect の RDMA は現在、すべての物理アドレスに依存していますPCI デバイスの観点からは同じです。これにより、IOMMUSと互換性がなくなるため、GPudirectが機能するためにRDMAを無効にする必要があります。

そして、次のように CPU-RAM を UVA に割り当ててマッピングすると、次のようになります。

#include <iostream>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

int main() {
    // Can Host map memory
    cudaSetDeviceFlags(cudaDeviceMapHost);  

    // Allocate memory
    unsigned char *host_src_ptr = NULL;
    cudaHostAlloc(&host_src_ptr, 1024*1024, cudaHostAllocMapped);
    std::cout << "host_src_ptr = " << (size_t)host_src_ptr << std::endl;

    // Get UVA-pointer
    unsigned int *uva_src_ptr = NULL;
    cudaHostGetDevicePointer(&uva_src_ptr, host_src_ptr, 0);
    std::cout << "uva_src_ptr  = " << (size_t)uva_src_ptr << std::endl;

    int b;  std::cin >> b;
    return 0;
}

Windwos7x64 では等しいポインタが得られます。つまり、 cudaHostGetDevicePointer() 何もしない:

host_src_ptr = 68719476736

uva_src_ptr = 68719476736

「ドライバー間で MMIO 領域を交換するための十分なメカニズム」とはどういう意味ですか、ここでのメカニズムはどのような意味ですか、また、仮想アドレスを使用して PCIe 経由で BAR の物理領域 (PCIe 経由の別のメモリ マップド デバイス) にアクセスすることで IOMMU を使用できない理由は何ですか? ?

これは、RDMA GPUDirect が常に (CPU の物理アドレス空間内の) 物理アドレスのみを操作することを意味しますが、なぜカーネル関数に送信するのでしょうか? uva_src_ptr に等しい host_src_ptr - CPU の仮想アドレス空間内の単純なポインタ?

役に立ちましたか?

解決

IOMMU は、マッピング レジスタのセットを提供するという点で非常に便利です。デバイスがアクセスできるアドレス範囲内に物理メモリが表示されるように調整でき、物理的に分散したバッファがデバイスにとって連続して見えるようにすることもできます。これは、nVidia GPU の生の物理オフセットにアクセスしようとするサードパーティの PCI/PCI-Express カードやリモート マシンには適していません。 実は IOMMU ユニットによるメモリの意図された領域へのアクセス、またはカードごとのアクセスの禁止/制限。したがって、これを無効にする必要があります。

「GPUDirect の RDMA は現在依存しています すべての物理アドレスは、PCIデバイスの観点から同じです."

-nVidia、 rDMA と GPUDirect の設計上の考慮事項

ドライバーが CPU の MMU を利用し、カーネル空間内で使用するためにメモリー マップド I/O (MMIO) の領域をマップしようとすると、ドライバーは通常、メモリー マッピングから返されたアドレスをドライバー自身に保持します。各ドライバーは独自のコンテキストまたは名前空間内で動作するため、nVidia のドライバーと、rDMA+GPUDirect のサポートを希望する他のサードパーティ ベンダーのドライバーとの間でこれらのマッピングを交換することは非常に困難であり、ベンダー固有のソリューション (おそらく製品でも) が必要になります。 -ドライバーがサードパーティの製品間で大きく異なる場合に固有)。また、現在のオペレーティング システムにはドライバー間で MMIO マッピングを交換するための適切なソリューションがありません。そのため、nVidia は、サードパーティ ドライバーがカーネル空間自体からこの情報に簡単にアクセスできるようにするいくつかの関数をエクスポートします。

nVidia は、GPUDirect の rDMA 経由で各カードにアクセスするために「物理アドレス指定」の使用を強制します。これにより、仮想アドレス指定に関連する問題 (例:仮想アドレスを物理アドレスに解決します)。各カードには物理アドレスがあり、このオフセットでアクセスできます。rDMA 操作を実行しようとするサードパーティ ドライバーに追加する必要があるロジックはほんの少しだけです。また、これらの 32 ビットまたは 64 ビットのベース アドレス レジスタは標準の PCI 構成空間の一部であるため、カードの物理アドレスは、nVidia のドライバが取得したマップされたアドレスを取得するのではなく、BAR から読み取るだけで簡単に取得できます。カードに貼り付けると。nVidia のユニバーサル仮想アドレス指定 (UVA) は、一見連続しているように見えるメモリ領域への前述の物理アドレス マッピングを処理します。 ユーザースペース アプリケーションは次のようになります。

CUDA Virtual Address Space

これらのメモリ領域はさらに 3 つのタイプに分類されます。CPU、GPU、FREE、すべて文書化されています ここ.

ただし、使用例に戻ります。あなたがいるから ユーザースペース, 、システムの物理アドレス空間に直接アクセスすることはできず、使用しているアドレスはおそらく nVidia の UVA によって提供される仮想アドレスです。以前に割り当てが行われていないと仮定すると、メモリ割り当てはオフセット +0x00000000 に存在するはずで、その結果、GPU 自体の同じオフセットが表示されることになります。2 番目のバッファを割り当てる場合、このバッファは最初のバッファの終了直後 (ベースからのオフセット +0x00100000 で開始される) が表示されると思います。 仮想アドレス 1 MB 割り当ての場合の GPU)。

もしあなたが入っていたら カーネルスペース, ただし、GPUDirect に rDMA を利用するために会社のカードのドライバーを作成していた場合、システムの BIOS や OS によって GPU に割り当てられた 32 ビットまたは 64 ビットの物理アドレスを使用して、rDMA データを直接やり取りすることになります。 GPU、それ自体。

さらに、すべての DMA エンジンが転送用の仮想アドレスを実際にサポートしているわけではないことも注目に値します。実際、ほとんどの DMA エンジンは DMA エンジンからの仮想アドレス指定を処理するため、物理アドレスを必要とします。 複雑になる可能性があります (7 ページ)、したがって、多くの DMA エンジンはこれをサポートしていません。

ただし、投稿のタイトルからの質問に答えるには、次のようにします。nVidia は現在、rDMA+GPUDirect の物理アドレス指定のみをサポートしています。 カーネル空間内. 。のために ユーザースペース アプリケーションでは、CPU の仮想アドレス空間にある nVidia の UVA によって与えられる GPU の仮想アドレスを常に使用することになります。


アプリケーションに関連して、rDMA 操作で実行できるプロセスの簡略化された内訳を次に示します。

  1. あなたの ユーザースペース アプリケーションは、nVidia が提供する統合仮想アドレス空間 (仮想アドレス) の範囲内にあるバッファを作成します。
  2. に電話をかける cuPointerGetAttribute(...) P2Pトークンを取得するため。これらのトークンは、CUDA のコンテキスト内のメモリに関係します。
  3. このすべての情報を次の宛先に送信してください カーネルスペース どういうわけか(例:IOCTL、ドライバーへの読み取り/書き込みなど)。少なくとも、これら 3 つは最終的に必要になります。 カーネルスペース 運転者:
    • によって返された P2P トークン cuPointerGetAttribute(...)
    • バッファの UVA 仮想アドレス
    • バッファのサイズ
  4. 次に、nVidia のカーネル空間関数を呼び出して、これらの仮想アドレスを対応する物理アドレスに変換します。これらのアドレスは nVidia のページ テーブルに保持されており、関数の nVidia のエクスポートでアクセスできるためです。 nvidia_p2p_get_pages(...), nvidia_p2p_put_pages(...), 、 そして nvidia_p2p_free_page_table(...).
  5. 前の手順で取得したこれらの物理アドレスを使用して、これらのバッファを操作する DMA エンジンを初期化します。

このプロセスのより詳細な説明は、こちらをご覧ください。 ここ.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top