GPGPU、CUDA Fortran、UVA, GPUdirect
マルチGPUを備えたシステム上で、CUDA 4.0 からの機能である Unified Virtual Addressing(UVA) を使用する場合、ホスト側メモリ空間の設定の仕方も重要となる。いわゆる、pinned memory とか mapped memory と言ったメモリ・エリアの属性について解説する。
2011年10月12日 Copyright © 株式会社ソフテック 加藤
前々回のコラム、CUDA Fortran による CUDA 4.0 Multi-GPU プログラミング (1)(GPUdirect™ V2.0 / peer-to-peer Access) や前回のコラム、CUDA Fortran による CUDA 4.0 Multi-GPU プログラミング (2)(Unified Virtual Addressing の使用法) において、ホスト側のメモリ空間の属性に関して詳しくは説明をしませんでした。CUDA 4.0 以降になってから、デバイス、ホストを問わず同一のメモリアドレス空間を仮想的に使用できるようになったため、ホスト側のメモリエリアに関して、きちんと理解しておく必要があります。ここでは、いわゆる、Pinned Memory (page-locked) と Zero-copy Memory (mapped) について解説します。
Pinned Memory 形式とは、ホスト側 OS で制御されている仮想メモリ管理下でアドレッシングするエリアではなく、メモリ内の一つの空間をプログラムが占有して使用する形態を言います。一般のOSの仮想メモリ管理では、ページングと称して実行プログラムで使用するメモリイメージはディスクに書き出されて(ページングされ)、仮想的なメモリ領域で管理されます。実際の実行においては、こうしたページングされたディスク上の仮想メモリ領域が、その度に物理メモリ上にマッピングされて動作しています。cudaHostAlloc() CUDA API 関数で pinned 属性によるメモリ割付を行うと、そのホスト側のメモリ空間がページングされない領域となり、GPU との間で占有して使用できます。これは、CUDA 4.0 の UVA 配下でホスト側のメモリを使用する時などは、こうした占有状態でホスト側メモリを使用することが必要となります。CUDA プログラミングにおいて、pinned memory 属性にすることによる利点と欠点は、次の通りです。
integer function cudaHostAlloc(hostptr, size, flags) type(C_PTR) :: hostptr integer :: size, flags
cudaHostAlloc 関数の引数である hostptr は、C 言語型のポインタで指定します。size は、バイト単位で指定します。flags にメモリ割付の属性を指定します。デフォルトは cudaHostAllocDefault ですが、pinned 割付を行う場合は、cudaHostAllocPortable を指定します。また、以下で説明する mapped(pinned) memory の場合は、cudaHostAllocMapped フラグを指定します。
Pinned memory を割り付ける istat = cudahostalloc( local_ha, sizeof(1.0)*n, cudaHostAllocPortable ) type(C_PTR) :: hostptr = local_ha C言語型ポインタ引数であることに注意 cudaHostAlloc allocates pinned memory on the host. It returns in hostptr the address o the pagelocked allocation, or returns an error if the memory is unavailable. Size is in bytes. The flags argument enables different options to be specified that affect the allocation. The normal iso_c_binding subroutine c_f_pointer can be used to move the type(c_ptr) to a Fortran pointer.
Mapped Memory 形式とは、pinned memory の割付状態で、かつ、CUDA デバイスから直接、ホスト側のその pinned memory エリアへアクセス可能な割付状態を言います。CUDA プログラミングにおいて、mapped memory 属性にすることによる注意点は、次の通りです。
ホスト側のメモリに mapped(pinned) ホストメモリを割り付けることを指示する istat = cudasetdeviceflags(cudaDeviceMapHost) Mapped memory(local_haポインタ)を割り付けて、UVA 下の「一つのデバイス」領域として認識し、 UVA上のポインタ(local_da) に付け替える istat = cudahostalloc( local_ha, sizeof(1.0)*n, cudaHostAllocMapped ) istat = cudahostgetdevicepointer( local_da, local_ha, 0 )