実際には2種類あることに注意してください。バッファを割り当てるときにとがありますがCL_MEM_READ_ONLY
、カーネル コードでポインタを装飾するためにともあります。CL_MEM_WRITE_ONLY
CL_MEM_READ_WRITE
__read_only
__write_only
__read_write
これらは、最適化とエラー チェックの両方に使用できます。まずは性能を見てみましょう。書き込み専用バッファが検出された場合、書き込みをキャッシュする必要がなく (ライト スルー キャッシュのように)、読み取り用により多くのキャッシュを節約できます。これは GPU ハードウェアに大きく依存し、少なくとも NVIDIA ハードウェアには、これを実際に実装するために必要な命令 (.cs
および.lu
修飾子) があります。PTX ISAを参照できます。コンパイラが実際にこの最適化を実行しているという証拠は見たことがありません。
__kernel void Memset4(__global __write_only unsigned int *p_dest,
const unsigned int n_dword_num)
{
unsigned int i = get_global_id(0);
if(i < n_dword_num)
p_dest[i] = 0; // this
}
次のようにコンパイルされます。
st.global.u32 [%r10], %r11; // no cache operation specified
CUDA にはこれらの修飾子に相当するものがないため、これは理にかなっているため、コンパイラはそれらを黙って無視する可能性が最も高いです。しかし、それらをそこに置いても害はありません。将来的にはもっと幸運になるかもしれません. CUDA では、__ldg
関数を使用し、コンパイラ フラグを使用して、L1 でのグローバル メモリ転送のキャッシュをオプトイン/オプトアウトすることで、この機能の一部が公開されます ( -Xptxas -dlcm=cg
)。asm
キャッシュをバイパスすると大きな利点が得られる場合は、いつでも使用できます。
const
エラーチェックに関しては、カーネル宣言で指定子を使用して、読み取り専用バッファーへの書き込みを簡単に回避できます。純粋な「C」では、書き込み専用バッファからの読み取りを禁止することはできません。
これらのバッファをホストメモリにマッピングするときに、別の最適化が行われる可能性があります。バッファをマッピングするときCL_MEM_READ_ONLY
、ホストはそのメモリに書き込むだけで、デバイスはそれを読み取るだけなので、マッピングされた領域は初期化されていないままになる可能性があります。同様に、CL_MEM_WRITE_ONLY
バッファーのマッピングを解除する場合、ドライバーは (ホストによって変更される可能性がある) 内容をホスト メモリからデバイス メモリにコピーする必要はありません。私はこれを測定しませんでした。
補足として、私は使用してみました:
inline unsigned int n_StreamingLoad(__global __read_only const unsigned int *p_src)
{
#ifdef NVIDIA
unsigned int n_result;
asm("ld.global.cs.u32 %r0, [%r1];" : "=r" (n_result) : "r" (p_src));
return n_result;
#else // NVIDIA
return *p_src; // generic
#endif // NVIDIA
}
inline void StreamingWrite(__global __write_only unsigned int *p_dest, const unsigned int n_value)
{
#ifdef NVIDIA
asm("st.global.cs.u32 [%r0], %r1;" : : "r" (p_dest), "r" (n_value) : "memory");
#else // NVIDIA
*p_dest = n_value; // generic
#endif // NVIDIA
}
sm_35
これにより、デバイスを備えた単純な memcpy カーネル (GTX 780 および K40 でテスト済み)でも、約 15 GB/秒余分に使用できます。目立ったスピードアップは見られませんでしたsm_30
(そこでサポートされることを意味するかどうかはわかりませんが、命令は ptx から削除されていません)。自分で定義する必要があることに注意してNVIDIA
ください (または、カーネル コードで OpenCL デバイス ベンダーを検出する を参照してください)。