CUDA最佳内存访问布局:全局内存合并和共享内存库冲突

CUDA最佳内存访问布局:全局内存合并和共享内存库冲突,cuda,Cuda,我对CUDA中最方便的全局和共享内存访问布局有一些疑问 全局存储器 1 CPU内存和GPU内存中以下内存地址0,0,0,1,1,0和1,1是如何排列的?换句话说,它们的存储顺序是什么 2在m,n中,哪个是行索引,哪个是列索引 3全局内存合并是通过按列主顺序还是按行主顺序访问元素来实现的 共享内存 1银行冲突是如何产生的?请使用示例/案例让我知道 2配置共享内存和总共64K中的L1的命令是什么?该命令的位置是哪里?您的问题的大部分已经在上面的评论中得到了回答。我只想提供一些关于合并内存访问的规则,

我对CUDA中最方便的全局和共享内存访问布局有一些疑问

全局存储器

1 CPU内存和GPU内存中以下内存地址0,0,0,1,1,0和1,1是如何排列的?换句话说,它们的存储顺序是什么

2在m,n中,哪个是行索引,哪个是列索引

3全局内存合并是通过按列主顺序还是按行主顺序访问元素来实现的

共享内存

1银行冲突是如何产生的?请使用示例/案例让我知道


2配置共享内存和总共64K中的L1的命令是什么?该命令的位置是哪里?

您的问题的大部分已经在上面的评论中得到了回答。我只想提供一些关于合并内存访问的规则,一些关于共享内存库冲突的示例,以及一些关于避免共享内存库冲突的规则,这些规则对您和其他用户都很有用

合并内存访问

1D阵列-1D线程网格

二维阵列-二维螺纹网格

共享内存库冲突

为了实现高带宽,共享内存被划分为独立的存储组。通过这种方式,共享内存可以服务于线程的同时访问。每个流式多处理器SM都有32个内存库中组织的共享内存。每个存储组的带宽为每两个时钟周期32位,承载4个字节的字32位:连续的32位字地址分配给连续的存储组

当两个不同的线程访问同一个库中的不同单词时,会发生库冲突。银行冲突会对性能产生负面影响,因为它们强制硬件序列化对共享内存的访问。请注意,如果不同线程访问同一单词中的任何字节,则不会发生冲突。还要注意的是,双方之间没有银行冲突 属于不同经纱的线

快速访问

如果一个warp的所有线程访问不同的组,则不存在组冲突; 如果一个warp的所有线程都访问一个相同的地址来执行提取操作,则没有 银行冲突广播。 慢速访问

32个线程访问同一个库中的32个不同的字,因此所有的访问都是序列化的; 一般来说,访问共享内存的成本与同时访问单个银行的最大次数成正比。 例1

如果warp中的第三个线程访问myShMem[50],而warp中的八个线程访问myShMem[178],则会出现双向银行冲突,这两个事务会被序列化

例2

考虑以下类型的访问

__shared__ float smem[256];
smem[b + s * threadIdx.x]
若要使同一经纱的两条螺纹t1和t2之间存在排列冲突,必须满足以下条件

b + s * t2 = b + s * t1 + 32 * k, with k positive integer
0 <= t2 - t1 < 32
如果smem是32位数据类型,则不会导致冲突。而且

extern __shared__ char smem[];
foo = smem[baseIndex + threadIdx.x];


不会导致银行冲突,因为访问了一个字节/线程,因此访问了同一单词的不同字节。

您的问题的大部分已经在上面的评论中得到了回答。我只想提供一些关于合并内存访问的规则,一些关于共享内存库冲突的示例,以及一些关于避免共享内存库冲突的规则,这些规则对您和其他用户都很有用

合并内存访问

1D阵列-1D线程网格

二维阵列-二维螺纹网格

共享内存库冲突

为了实现高带宽,共享内存被划分为独立的存储组。通过这种方式,共享内存可以服务于线程的同时访问。每个流式多处理器SM都有32个内存库中组织的共享内存。每个存储组的带宽为每两个时钟周期32位,承载4个字节的字32位:连续的32位字地址分配给连续的存储组

当两个不同的线程访问同一个库中的不同单词时,会发生库冲突。银行冲突会对性能产生负面影响,因为它们强制硬件序列化对共享内存的访问。请注意,如果不同线程访问同一单词中的任何字节,则不会发生冲突。还要注意的是,双方之间没有银行冲突 属于不同经纱的线

快速访问

如果一个warp的所有线程访问不同的组,则不存在组冲突; 如果一个warp的所有线程都访问一个相同的地址来执行提取操作,则没有 银行冲突广播。 慢速访问

32个线程访问同一个库中的32个不同的字,因此所有的访问都是序列化的; 一般来说,访问共享内存的成本与同时访问单个银行的最大次数成正比。 例1

如果warp中的第三个线程访问myShMem[50],而warp中的八个线程访问myShMem[178],则存在双向银行冲突,两个事务 n将被序列化

例2

考虑以下类型的访问

__shared__ float smem[256];
smem[b + s * threadIdx.x]
若要使同一经纱的两条螺纹t1和t2之间存在排列冲突,必须满足以下条件

b + s * t2 = b + s * t1 + 32 * k, with k positive integer
0 <= t2 - t1 < 32
如果smem是32位数据类型,则不会导致冲突。而且

extern __shared__ char smem[];
foo = smem[baseIndex + threadIdx.x];


不会导致银行冲突,因为访问了一个字节/线程,因此访问了同一单词的不同字节。

请每个问题问一个问题:好的,但实际上我缩小了对问题的描述范围,以便更具体,所有这些都是概念的子问题;所以我想用这种方式写。对于C中的二维数组:第一个索引是行索引,第二个索引是列索引。相邻列中的元素存储在内存中的相邻位置。对于CUDA中的二维线程阵列,x中的相邻线程将分组为扭曲。因此,为了实现合并访问,我们可能希望以C[threadIdx.y][threadIdx.x]或类似形式访问二维数组。有关多维示例,请参阅我发布的第一个示例。它应该结合在一起。对于共享内存,您可能对幻灯片35-44感兴趣。有关共享内存配置命令,请参阅C编程指南示例中的计算体系结构部分:。实际的cuda运行时函数是cudaFuncSetCacheConfig,你也可以用谷歌搜索它。共享内存的文档在cuda C编程指南中。链接到计算能力和设备部分。网络研讨会可能也会有帮助。请每个问题问一个问题:好的,但实际上我缩小了我对问题的描述范围,以便更具体,所有这些都是概念的子问题;所以我想用这种方式写。对于C中的二维数组:第一个索引是行索引,第二个索引是列索引。相邻列中的元素存储在内存中的相邻位置。对于CUDA中的二维线程阵列,x中的相邻线程将分组为扭曲。因此,为了实现合并访问,我们可能希望以C[threadIdx.y][threadIdx.x]或类似形式访问二维数组。有关多维示例,请参阅我发布的第一个示例。它应该结合在一起。对于共享内存,您可能对幻灯片35-44感兴趣。有关共享内存配置命令,请参阅C编程指南示例中的计算体系结构部分:。实际的cuda运行时函数是cudaFuncSetCacheConfig,你也可以用谷歌搜索它。共享内存的文档在cuda C编程指南中。链接到计算能力和设备部分。网络研讨会也可能会有所帮助。
smem[b + threadIdx.x]
extern __shared__ char smem[];
foo = smem[baseIndex + threadIdx.x];
extern __shared__ short smem[];
foo = smem[baseIndex + threadIdx.x];