Cuda 这些方式是联合访问吗?

Cuda 这些方式是联合访问吗?,cuda,gpu,Cuda,Gpu,注意:当warp执行访问全局内存的指令时,它会将warp中线程的内存访问合并到一个或多个内存事务中 但我有一些问题 __global__ void add(double *a. double *b){ int i = blockDim.x * blockIdx.x + threadIdx.x; i = 3 * i; b[i] = a[i] + a[i + 1] + a[i + 2]; } 这三种存取方式a[i]、[i+1]、[i+2]能否仅用一条指令执行?我的意思是,这是联合访问吗? 或

注意:当warp执行访问全局内存的指令时,它会将warp中线程的内存访问合并到一个或多个内存事务中

但我有一些问题

__global__ void add(double *a. double *b){
 int i = blockDim.x * blockIdx.x + threadIdx.x;
 i = 3 * i;
 b[i] = a[i] + a[i + 1] + a[i + 2];
}
这三种存取方式a[i]、[i+1]、[i+2]能否仅用一条指令执行?我的意思是,这是联合访问吗? 或者,合并后的经纱是否只存在于经纱的不同线(横向)中?是否不存在于线中? 我读过类似的问题: 但我还是不明白,这是非合并内存访问吗

二,

它可以是非合并访问。 因此,我将代码更改为:

__global__ void add(double *a. double *b){
 int i = blockDim.x * blockIdx.x + threadIdx.x;
__shared__ double shareM[3*BLOCK_SIZE]; 
shareM[threadIdx.x] = a[i];
shareM[threadIdx.x + 1] = a[i + 10];
shareM[threadIdx.x + 2] = a[i + 12];
b[i] = shareM[threadIdx.x] + shareM[threadIdx.x + 1] + shareM[threadIdx.x + 2];
}
我发现合并访问与共享内存无关。 但这意味着这是在一个线程下合并访问的方式吗

shareM[threadIdx.x] = a[i];
shareM[threadIdx.x + 1] = a[i + 10];
shareM[threadIdx.x + 2] = a[i + 12];
或者共享内存合并访问是否只存在于不同的线程中,如FLOWING示例所示:

thread0:
shareM[0] = a[3]
thread1:
shareM[4] = a[23]
thread2:
shareM[7] = a[56]
3.我不理解合并访问与共享内存无关。 这是否意味着将数据加载到本地或从全局内存注册内存的速度比从全局内存加载到共享内存的速度慢? 如果是,为什么我们不使用共享内存作为传输站一个线程只有一个8字节的共享内存就足够了? 多谢各位

这三种存取方式a[i]、[i+1]、[i+2]能否仅用一条指令执行?我的意思是,这是联合访问吗

当使用GPU内核时,我想最好是以并行的方式思考所有问题。每一条指令都是在一组32个线程中执行的,也称为扭曲,因此它们实际上不仅仅是三个访问。在这里,access这个词也很模糊,我假设你指的是数组访问,它们总共是32 x 3=96个访问。更正确的说法是,每个线程有三次数组访问

根据[1-3],合并访问模式是一种扭曲行为:

当warp执行一条访问全局内存的指令时,它会根据每个线程访问的字的大小和线程间内存地址的分布,将warp中线程的内存访问合并为一个或多个内存事务

因此,我们需要分别考虑这三种数组访问。让我们将代码重写为:

__global__ void add(double *a. double *b){
 int i = blockDim.x * blockIdx.x + threadIdx.x;
 i = 3 * i;
 double ai  = a[i];     // <1>
 double ai1 = a[i + 1]; // <2>
 double ai2 = a[i + 2]; // <3>
 b[i] = ai + ai1 + ai2;
}
warp中的32个线程分别以6个128字节的段访问内存。在缓存模式下,它至少需要6个128字节的内存事务。总共是768个字节,但只有256个字节是有用的。总线利用率约为1/3

:这非常类似于,从起点偏移1:

                          <2>
t0                         +                     t31
 +---+---+---+-------------+----------------------+
 |   |   |   |          ......                    |
 v   v   v   v                                    v
++---+---+---+---+--------+-------+--------+------+-+-
|segment|        |        |       |        |        |
+----------------+--------+-------+--------+--------+-
a[0]             a[31]            a[63]             a[95]
                           <3>
 t0                         +                     t31
  +---+---+---+-------------+----------------------+
  |   |   |   |          ......                    |
  v   v   v   v                                    v
+-+---+---+---+--+--------+-------+--------+-------++-
|segment|        |        |       |        |        |
+----------------+--------+-------+--------+--------+-
a[0]             a[31]            a[63]             a[95]
这是否意味着将数据加载到本地或从全局内存注册内存的速度比从全局内存加载到共享内存的速度慢?如果是,为什么我们不使用共享内存作为传输站一个线程只有一个8字节的共享内存就足够了

AFAICT,您不能直接将数据从全局内存传输到共享内存

参考资料: [1] 。 [2]. [3]. [4].
[5]. 我撒谎了,有一种方法可以通过使用u shlf intrinsics来做到这一点

非常感谢你的回答,我从你的回答中受益匪浅。您的意思是访问模式像下面这样合并吗__全局uuvoid add…{…shareM[threadIdx.x]=a[i];shareM[threadIdx.x+1]=a[i+1];shareM[threadIdx.x+2]=a[i+2];…}那么这是否意味着上面的三行是并行执行的,即所有对扭曲内不同线程中共享内存的访问都是并行执行的呢??您在上面标记的三行代码是否在一个线程中串行执行,而在一个扭曲中的是并行的?@ice抱歉,我忘记在最后一个图形中将重命名为。假设块大小足够大>=3个扭曲,可以从全局内存加载数据以注册到共享内存,如下所示:int i=blockDim.x*blockIdx.x+threadIdx.x;如果i<768 shareM[i]=a[i]__同步线程;。您可以看到,这只是一条单行线,前三个扭曲中的每个线程正从a加载8字节的值,对于每个扭曲,32个线程加载连续的256字节数据,即两个128字节的段,因此CUDA可以处理两个128字节的事务。顺便说一句,我们需要一个额外的_syncthreads,因为我们在线程块中有并发执行的warp,我们必须确保前三个warp在使用shareM之前完成了它们的工作。注意,在上面的if语句中,更合适的写入方式是:int i=blockDim.x*blockIdx.x+threadIdx.x;inttid=threadIdx.x&31;intwid=threadIdx.x>>8;其中,tid是指经纱内的线id;wid指螺纹块内的翘曲id;显然,threadIdx.x=wid*32+tid。这样,代码就可以像wid<3 shareM[wid*32+tid]=a[i];那样重写。您可以看到,每个块现在可以加载一个文件的不同部分。1。int i=blockDim.x*blockIdx.x+threadIdx.x;如果i<768 shareM[i]=a[i]__同步线程;此代码可能不仅包含3个war 坑应为768/32?。如果每个线程都读取[i],我认为数据是连续的,为什么它需要共享内存?2.你的意思是将线映射到不同的扭曲中吗?就像你写的最后一个图:a[0]~a[95],只由32个线程读取,为什么它需要3个扭曲?
                          <2>
t0                         +                     t31
 +---+---+---+-------------+----------------------+
 |   |   |   |          ......                    |
 v   v   v   v                                    v
++---+---+---+---+--------+-------+--------+------+-+-
|segment|        |        |       |        |        |
+----------------+--------+-------+--------+--------+-
a[0]             a[31]            a[63]             a[95]
                           <3>
 t0                         +                     t31
  +---+---+---+-------------+----------------------+
  |   |   |   |          ......                    |
  v   v   v   v                                    v
+-+---+---+---+--+--------+-------+--------+-------++-
|segment|        |        |       |        |        |
+----------------+--------+-------+--------+--------+-
a[0]             a[31]            a[63]             a[95]
      (warp1)           (warp2)          (warp3)
         +                 +                +
         |                 |                |
t0       |     t31         |         t0     |        t31
 +-+-+-+---+-+-+-+---------+---------+-+-+-+++-+-+-+-+
 | | | | | | | | |        ......     | | | | | | | | |
 v v v v v v v v v                   v v v v v v v v v
 +-+-+-+---+-+-+-++--------+-------+-+-+-+-+++-+-+-+---
 |segment|        |        |       |        |        |
 +----------------+--------+-------+--------+--------+-
 a[0]             a[31]            a[63]             a[95]