Kepler GPUでのUnified Memoryの問題
それは、x86 CPUの1ページは4KBであるのに対して、NVIDIAのGPUの1ページは8KBであったからである。前の例のように、GPUにあるページをCPUに移す場合はGPU側のページテーブルエントリをInvalidに変えれば、その8KBページへのGPUのアクセスを禁止することができる。しかし、逆にCPU側にあるページをGPUに移す場合は、CPUのページは4KBであるので、2つのページテーブルエントリを同時にInvalidにする必要がある。この「同時にInvalid」がx86 CPUでは行えない。
このため、CUDA 6では、CPUはアクセス要求を出せば、そのVAを含む8KBページがGPUから移動されるが、その逆はできないということになっている。
そのため、Pascal以前のGPUでは、CPUのシステムメモリからGPUメモリへのデータの移動は、GPUでカーネルを起動する前に行っておく必要がある。これは、カーネルが必要とするすべてのメモリをGPUメモリに確保して置く必要があるということである。
この状況を図示したのが次の図で、GPUメモリにありシステムメモリにはないデータをCPUがアクセスするとページフォールトが発生して、そのページをPCI Express経由で、GPUメモリからシステムメモリに自動的に移動する。
Pascalでは双方向のページ移動が可能になった
Pascal GPUでは、GPUのメモリアクセスがページフォールトを起こした場合、逆方向のシステムメモリからGPUメモリへのページの移動ができるようになった。
このため、カーネルが必要とするデータがシステムメモリにあったとしても、カーネルが起動されると、そのデータをアクセスし、システムメモリからGPUメモリへのページの移動が自動的に行われる。
そのため、カーネル起動の前にGPUメモリに必要なデータを入れて置くという必要性が無く、プログラミングがずっと楽になる。
Pascalでは、GPU側のページフォールトでシステムメモリからGPUメモリへのページの移動ができるようになり、双方向のページ移動ができるようになった。また、PascalではPCI Expressより高速なNVLINKがサポートされ、NVLINKをサポートするPOWER CPUが出てくれば、より高速にページの移動ができるようになる。
この後に述べるように、双方向のデマンドページングができるようになり、使い勝手が向上するのであるが、このために、PascalでNVIDIAが行ったのは、Pascal GPUのページサイズを4KBにしてx86 CPUと同じにするという変更である。ページサイズが同じであるので、CPU側で2つのページテーブルエントリを同時にInvalidにする必要が無くなったので、これが可能になった。
このために必要となるハードの変更は僅かであるが、8KBページを前提として作られているコードがあると動かなくなってしまう可能性があるので、過去のGPUコードをチェックして必要に応じて修正を行うというのは、大変な作業であったのではないかと思われる。
しかし、その結果、双方向のオンデマンドのページ移動が可能になり、必要となった時点でシステムメモリからデータを持ってくることができるので、GPU側にカーネルが使うすべてのメモリを確保して置く必要が無くなった。このため、GPUメモリの容量より大きなメモリを必要とするカーネルを実行することができるようになった。
また、CPUとGPUのメモリの間でページ粒度のコヒーレンシが保たれるようになり、使い勝手が向上した。