ディープコピーの問題とUnified Memory

CPUとGPUで処理を分担する場合は、CPUのメインメモリのデータをGPUのデバイスメモリにコピーする、あるいはその逆のデータのコピーが必要になる。このとき、コピーするデータが1次元の配列なら、アドレスは連続しており、簡単に転送できる。データが2次元の配列の場合は、行方向のアクセスの場合は連続アドレスになるが、列方向にアクセスする場合は、飛び飛びのメモリアクセスを行う必要が出てくる。これも、2次元DMAができるハードウェアであれば問題ないし、2次元DMAが無くても、元のデータのアドレスと転送先のアドレスは規則的に計算できるので、大きな問題は無い。

しかし、難しいのは図3-61に示すように、配列の要素が構造体で、その中にポインタが含まれているケースである。

この場合、ポインタは別の領域にあるデータを指しているので、(1)で元の配列をコピーするだけではダメで、ポインタが指しているデータの格納場所をGPU側のデバイスメモリに確保して、(2)でデータをCPUのメインメモリからコピーして格納し、(3)でGPU側にコピーした配列に格納されているポインタをGPU側にコピーしたデータのアドレスに付け替えるという操作が必要になる。このようにポインタの指しているデータまでコピーする必要があるケースはディープコピーと呼ばれる。

図3-61 ポインタの先のデータをコピーするディープコピー

図3-61ではGPU側にコピーする実データはサイズが一定で、その中にはポインタを含まないという風に書いてあるが、大規模な科学技術計算プログラムでは、実データのサイズがまちまちであったり、実データが構造体でその中に、また、ポインタが含まれているケースは珍しくない。このような多重にポインタが使われているケースでは、CPUメモリとGPUメモリの間の配列のコピーはかなり面倒である。

しかし、Unified Memoryがサポートされていれば、GPUがポインタが指している対象をアクセスしようとした時には、ページフォールトが発生して、自動的に対象を含むページがGPU側に移動される。ポインタの参照ごとにページコピーが起こるのでは実行時間はかなり遅くなってしまうが、ディープコピーに対応した特別なプログラミングをすることなしに、プログラムが正しく動くということは、非常に大きなメリットである。