共有ローカルメモリ(単純にローカルメモリと呼ぶ事が多い)は、物理的に見ればプロセッサの近辺に配置されているため、キャッシュと類似したパフォーマンスを得ることができます。そのためグローバルメモリ(又はコンスタントメモリ)の10倍以上早く処理が可能となります。キャッシュと異なる点としては、アプリケーションが確保するメモリ領域で使用可能なことです。
ローカルメモリの最大値はOpenCLのデバイス情報取得関数で知ることができます。
一応補足しますが、ローカルメモリをキャッシュとしても定義上は問題はないと考えられますが、OpenCLはデバイスを抽象化したフレームワークであり、通常こうした物理層のマッピングを開発者が直接行なうことは稀です。
Intelの第3世代、第4世代以降のCPUアーキテクチャでは、同一のダイにCPUコアとGPUコアが集積・併存します。CPUとGPUで効率的にリソースを割り当てるために、LLC(ラストレベルキャッシュ)というCPUとGPUで共有するキャッシュがあり、CPUとGPUコアのLLCはリングバス(ショートカットという最適パスも存在)で接続されています。
IntelのOpenCL実装がグローバルメモリーにアクセスする場合LLC(Last Level Cache: 2-8MBが目安)またはEDRAM(128MBが目安)を通じておこないます。
IntelのiGPUでは、共有ローカルメモリはL3キャッシュに存在します。共有ローカルメモリとよぶときはL3キャッシュの一領域を意味します。
使用されるSIMDレーン数は、コンパイルされたSIMD幅とローカルワークサイズで決定されます。
clGetKernelWorkGroupInfo関数の引数で、CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLEフラグを指定すると、コンパイルされたSIMD幅を取得できます。
この値が32の時はSIMD-32、16のときはSIMD-16、8のときはSIMD-8を使うことが指定されます。ローカルワークサイズはこの数値の倍数としないと、SIMDレーンの使用率はフル稼働されないことになります。
前項で取得するコンパイルしたSIMD幅は、プライベートメモリの数値が閾値をこえると変動します。以下の表に閾値をまとめました。
SIMD幅 | プライベートメモリの閾値 |
SIMD-8 | 512バイト |
SIMD-16 | 256バイト |
SIMD-32 | 128バイト |
プライベートメモリで容量を超える処理をワークアイテムですると、グローバルメモリを使うことになり、これをスピル(こぼれる、溢れ出る)と呼ぶことがあります。
メモリのスピルは、キャッシュに収まりきらないデータがメインメモリで処理されることの一般的な現象なので、SIMD幅に限定されるわけではありません。メモリのスピルで代表的なものを次の項目で解説します。
NVIDIAデバイスでコーディングする際にはよくあるのですが、良く仕様を読んで理解していないと、デバイス情報取得関数で戻ってきたローカルメモリサイズの数値が想定より低いケースがあります。
第2世代Maxwell(GM204)は、第1世代(GM107)に比べて50%増えた共通ローカルメモリを持ちます。GM107が64KBだったのに対して、96KBの共有メモリに増量されています。
しかしスレッドブロックで使えるローカルメモリは、GM204もGM107も48KBとなります。規格と違うではないかと憤慨した技術者も多いかもしれませんが、そもそもOpenCLのデバイス情報取得関数でローカルメモリサイズを確認してから規格書をよんでいれば、無駄な時間を使わずに開発ができたかもしれません。
もちろん規格を先によんだ方がいいケースもあります。Fermiアーキテクチャでは、16KBか48KBの選択ができ、L1キャッシュ(16KBか48KB)とメモリ領域の区分けを変えることができます。こうしたレアケースもあることは念頭においたほうがいいでしょう。
今後もアーキテクチャの世代が更新されるたびにSLMのサイズが変化するのは間違いなく、ローカルメモリサイズは新しいプロセッサを使うたびにOpenCL APIを通じて確認することを推奨します。
Copyright 2018-2019, by Masaki Komatsu