CUDA:为什么访问相同的设备阵列没有合并?

时间:2013-10-19 10:04:33

标签: memory-management cuda coalescing

我发布了一个深入的代码供审核。我相信它应该没有任何问题地编译和执行,但由于我排除了所有不相关的部分,我可能会犯一些错误。

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

1 个答案:

答案 0 :(得分:1)

您的内核从全局内存中读取Step 10次。尽管L1缓存可以减少对全局内存的实际访问,但它仍然被分析器视为低效的访问模式。

我的探查器将其命名为“全局负载效率”。它没有说它是否合并。