我是新手CUDA程序员。我最近了解到更多关于在较低入住率下实现更好性能这是一个代码片段,我需要帮助来理解关于重放开销和指令级别并行的一些事情
__global__ void myKernel(double *d_dst, double *d_a1, double *d_a2, size_t SIZE)
{
int tId = threadIdx.x + blockDim.x * blockIdx.x;
d_dst[tId] = d_a1[tId] * d_a2[tId];
d_dst[tId + SIZE] = d_a1[tId + SIZE] * d_a2[tId + SIZE];
d_dst[tId + SIZE * 2] = d_a1[tId + SIZE * 2] * d_a2[tId + SIZE * 2];
d_dst[tId + SIZE * 3] = d_a1[tId + SIZE * 3] * d_a2[tId + SIZE * 3];
}
这是我的简单内核,它简单地将两个2D数组相乘以形成第三个2D数组(从逻辑角度看),其中这些数组都作为平面1D数组放置在设备内存中。
下面我将介绍另一段代码片段:
void doCompute() {
double *h_a1;
double *h_a2;
size_t SIZE = pow(31, 3) + 1;
// Imagine h_a1, h_a2 as 2D arrays
// with 4 rows and SIZE Columns
// For convenience created as 1D arrays
h_a1 = (double *) malloc(SIZE * 4 * sizeof(double));
h_a2 = (double *) malloc(SIZE * 4 * sizeof(double));
memset(h_a1, 5.0, SIZE * 4 * sizeof(double));
memset(h_a2, 5.0, SIZE * 4 * sizeof(double));
double *d_dst;
double *d_a1;
double *d_a2;
cudaMalloc(&d_dst, SIZE * 4 * sizeof(double));
cudaMalloc(&d_a1, SIZE * 4 * sizeof(double));
cudaMalloc(&d_a2, SIZE * 4 * sizeof(double));
cudaMemcpy(d_a1, h_a1, SIZE * 4 * sizeof(double), cudaMemcpyHostToDevice);
cudaMemcpy(d_a2, h_a2, SIZE * 4 * sizeof(double), cudaMemcpyHostToDevice);
int BLOC_SIZE = 32;
int GRID_SIZE = (SIZE + BLOC_SIZE - 1) / BLOC_SIZE;
myKernel <<< GRID_SIZE, BLOC_SIZE >>> (d_dst, d_a1, d_a2, SIZE);
}
Q1)我在这里打破了任何合并的内存访问模式吗?
Q2)我可以说访问内存,它们在内核中的编码方式 也是指令级并行的例子?如果是,我使用ILP2还是ILP4?和 为什么呢?
Q3)如果我所做的一切都是正确的,为什么nvvp探查器会给我以下消息?
Total Replay Overhead: 4.6%
Global Cache Replay Overhead: 30.3%
如何减少或修复它们?
干杯,
答案 0 :(得分:1)
编译器调度可能的ILP利用指令的能力有限。 GPU本身也必须具有ILP功能,其程度因GPU生成而异。是的,任何不可用的资源都可能导致warp停止,典型的是内存所需的数据。您要询问的重播数量的定义是here。
因此,例如,全局缓存重放开销将由缓存未命中触发,并且您的代码将有一些缓存未命中。即使您具有100%合并访问和(几乎)100%带宽利用率,也可能出现缓存未命中。