我发布了一个深入的代码供审核。我相信它应该没有任何问题地编译和执行,但由于我排除了所有不相关的部分,我可能会犯一些错误。
struct Users {
double A[96];
double B[32];
double C[32];
};
这是我的用户结构,具有固定长度的数组。下面给出了主要功能。
int main(int argc, char **argv) {
int numUsers = 10;
Users *users = new Users[numUsers];
double Step[96];
for (int i = 0; i < 32; i++) {
Step[i] = 0.8;
Step[i + 32] = 0.8;
Step[i + 64] = 0.8;
}
for (int usr = 0; usr < numUsers; usr++) {
for (int i = 0; i < 32; i++) {
users[usr].A[i] = 10;
users[usr].A[i + 32] = 20;
users[usr].A[i + 64] = 30;
}
memset(users[usr].B, 0, sizeof(double) * 32);
memset(users[usr].C, 0, sizeof(double) * 32);
}
double *d_Step;
cudaMalloc((void**)&d_Step, sizeof(double) * 96);
cudaMemcpy(d_Step, Step, sizeof(double) * 96, cudaMemcpyHostToDevice);
Users *deviceUsers;
cudaMalloc((void**)&deviceUsers, sizeof(Users) * numUsers);
cudaMemcpy(deviceUsers, users, sizeof(Users) * numUsers, cudaMemcpyHostToDevice);
dim3 grid;
dim3 block;
grid.x = 1;
grid.y = 1;
grid.z = 1;
block.x = 32;
block.y = 10;
block.z = 1;
calc<<<grid, block >>> (deviceUsers, d_Step, numUsers);
delete users;
return 0;
}
请注意,Step数组是带有96个bin的1D数组,我正在跨越10个warp(x方向有32个线程,我的块中有10个)。每个warp将访问相同的Step数组。这可以在内核中看到。
__global__ void calc(Users *users, double *Step, int numUsers) {
int tId = threadIdx.x + blockIdx.x * blockDim.x;
int uId = threadIdx.y;
while (uId < numUsers) {
double mean00 = users[uId].A[tId] * Step[tId];
double mean01 = users[uId].A[tId + 32] * Step[tId + 32];
double mean02 = users[uId].A[tId + 64] * Step[tId + 64];
users[uId].A[tId] = (mean00 == 0? 0 : 1 / mean00);
users[uId].A[tId + 32] = (mean01 == 0? 0 : 1 / mean01);
users[uId].A[tId + 64] = (mean02 == 0? 0 : 1 / mean02);
uId += 10;
}
}
现在,当我使用NVIDIA Visual Profiler时,合并后的检索率为47%。我进一步调查并发现每个warp正在访问的Step数组导致了这个问题。如果我用一些常量替换它,则访问是100%合并的。
Q1)据我所知,合并访问与字节行相关联,即字节行必须是32的倍数,无论它们是整数双字节行。为什么我没有得到合并访问?
据我所知,cuda每当在设备全局内存中分配一个内存块时,就会为它分配一个偶数地址。因此,只要经线访问起点+32位置,就应该合并访问。我是对的吗?
Geforce GTX 470,Compute Capability 2.0
答案 0 :(得分:1)
您的内核从全局内存中读取Step
10次。尽管L1缓存可以减少对全局内存的实际访问,但它仍然被分析器视为低效的访问模式。
我的探查器将其命名为“全局负载效率”。它没有说它是否合并。