Memory 什么导致CUDA中的指令重放开销

Memory 什么导致CUDA中的指令重放开销,memory,cuda,gpu,overhead,Memory,Cuda,Gpu,Overhead,我在我的CUDA应用程序上运行了可视化分析器。如果数据太大,应用程序会多次调用单个内核。这个内核没有分支 探查器报告了高指令重放开销为83.6%,以及高全局内存指令重放开销为83.5% 以下是内核的总体外观: // Decryption kernel __global__ void dev_decrypt(uint8_t *in_blk, uint8_t *out_blk){ __shared__ volatile word sdata[256]; register uint3

我在我的CUDA应用程序上运行了可视化分析器。如果数据太大,应用程序会多次调用单个内核。这个内核没有分支

探查器报告了高指令重放开销83.6%,以及高全局内存指令重放开销83.5%

以下是内核的总体外观:

// Decryption kernel
__global__ void dev_decrypt(uint8_t *in_blk, uint8_t *out_blk){

    __shared__ volatile word sdata[256];
    register uint32_t data;

    // Thread ID
#define xID (threadIdx.x + blockIdx.x * blockDim.x)
#define yID (threadIdx.y + blockIdx.y * blockDim.y)
    uint32_t tid = xID + yID * blockDim.x * gridDim.x;
#undef xID
#undef yID

    register uint32_t pos4 = tid%4;
    register uint32_t pos256 = tid%256;
    uint32_t blk = pos256&0xFC;

    // Indices
    register uint32_t index0 = blk + (pos4+3)%4;
    register uint32_t index1 = blk + (pos4+2)%4;

    // Read From Global Memory
    b0[pos256] = ((word*)in_blk)[tid+4] ^ dev_key[pos4];

    data  = tab(0,sdata[index0]);
    data ^= tab(1,sdata[index1]);
    sdata[pos256] = data ^ tab2[pos4];

    data  = tab(0,sdata[index0]);
    data ^= tab(1,sdata[index1]);
    sdata[pos256] = data ^ tab2[2*pos4];

    data  = tab(0,sdata[index0]);
    data ^= tab(1,sdata[index1]);
    data ^= tab2[3*pos4];

    ((uint32_t*)out_blk)[tid] = data + ((uint32_t*)in_blk)[tid];
}
正如你所见,这里没有分支。线程最初将基于线程ID+16字节从全局内存中读取。在基于线程ID对全局内存中的数据执行操作后,它们将写入输出缓冲区


你知道为什么这个内核会有这么多开销吗?

在这种情况下,指令重放的来源是一个warp中的非统一常量内存访问。在您的代码中,
选项卡
存储在恒定内存中,并根据线程索引和存储在共享内存中的数据的某种组合进行索引。结果似乎是同一扭曲内的非统一访问线程。常量内存实际上适用于warp中的所有线程访问同一个字的情况,然后可以在单个操作中从常量内存缓存广播该值,否则将发生warp序列化


在需要对小型只读数据集进行非统一访问的情况下,最好将数据绑定到纹理,而不是将其存储为常量内存。

@Talonmes这是我用来访问常量内存的宏。tab2也是常量内存。这不是我的内核实际的样子。但是,这是它通常的行为。好的,那么序列化可能是因为不断的内存访问。如果一个warp中的所有线程都不能访问常量内存中的同一个字,那么您可以获得序列化。@Talonmes所以即使常量内存访问也必须以某种方式访问才能合并?《CUDA C编程指南》没有提到这一点。@Talonmes我更改了代码,创建了32个表实例(仍然有大量的常量内存)。探查器正在报告相同的事情。我是否应该重新安排表,以便相邻线程访问相邻的字?除非warp中的每个线程都访问恒定内存中的同一个字,否则将获得序列化。如果您想要随机或半随机访问,请使用全局内存或纹理,而不是常量内存。