【问题标题】:2D array CUDA problems二维数组 CUDA 问题
【发布时间】:2019-08-08 07:05:03
【问题描述】:

我目前正在努力在我的 CUDA 内核中正确处理二维数组。 1D 很好,但到目前为止还没有成功转移到 2D。这是我的主机函数和内核:

__global__ void add_d2D(double *x, double *y,double *z, int n, int m){
    for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x){
        for(int j = blockIdx.y * blockDim.y + threadIdx.y; j <  m; j += blockDim.y * gridDim.y){
            z[i*m + j] = x[i*m + j] + y[i*m + j];
        }
    }
}

__host__ void add2D(double *a, double *b, double *result, int N, int M){
    double *a_d, *b_d, *c_d;

    size_t pitcha;
    size_t pitchb;
    size_t pitchc;

    cudaErrchk(cudaMallocPitch(&a_d,&pitcha, M*sizeof(double),N));
    cudaErrchk(cudaMallocPitch(&b_d,&pitchb, M*sizeof(double),N));
    cudaErrchk(cudaMallocPitch(&c_d,&pitchc, M*sizeof(double),N));
    cudaErrchk(cudaMemcpy2D(a_d,M*sizeof(double), a,pitcha, M*sizeof(double),N, cudaMemcpyHostToDevice));
    cudaErrchk(cudaMemcpy2D(b_d,M*sizeof(double), b,pitchb, M*sizeof(double),N, cudaMemcpyHostToDevice));

    dim3 threadsPerBlock(2, 2); 
    dim3 numBlocks(N/threadsPerBlock.x, M/threadsPerBlock.y); 

    add_d2D<<<numBlocks, threadsPerBlock>>>(a_d, b_d, c_d , N, M);

    cudaDeviceSynchronize();

    cudaErrchk(cudaMemcpy2D(result,M*sizeof(double), c_d,pitchc, M*sizeof(double),N, cudaMemcpyDeviceToHost));

    cudaFree(a_d);
    cudaFree(b_d);
    cudaFree(c_d);
}

下面是我的例子来测试它。它正确打印出 C 的前 10 个值,但所有其他值都保持为 0。我相信问题出在内核中。由于音高而无法找到正确的值,但不确定如何正确解决。

double a[4][10];
double b[4][10];
double c[4][10];
for (int i = 0; i < 4; i ++){
    for (int j = 0; j < 10; j ++){
        a[i][j] = 0 + rand() % 10;
        b[i][j] = 0 + rand() % 10;
    }
}
ertiscuda::add2D((double *)a, (double *)b, (double *)c, 4, 10);
for (int i = 0; i < 4; i ++){
    for (int j = 0; j < 10; j ++){
        std::cout << a[i][j] << " " << b[i][j] << " " << c[i][j] << std::endl;  
    }
}

【问题讨论】:

    标签: c++ multidimensional-array memory-management cuda


    【解决方案1】:

    你有两个错误

    1. 内核中的每个线程都应该执行一项操作而不是所有操作。 (出于记忆的原因,您可能想要做更多的事情,我们将保持这个示例简单)。

    2. 在将数据加载到设备时,您切换了目标音高和源音高。

    这是一个工作版本

    #include <cuda_runtime.h>
    #include <stdlib.h>
    #include <iostream>
    #include <sstream> 
    
    #define CUDASAFECALL( err ) cuda_safe_call(err, __FILE__, __LINE__ )
    void cuda_safe_call(const cudaError err, const char *file, const int line)
    {
        if (cudaSuccess != err)
        {
            std::stringstream error_msg;
            error_msg << "cuda_safe_call() failed at " << file << ":" << line << ":" << cudaGetErrorString(err);
            const auto error_msg_str = error_msg.str();
            std::cout << error_msg_str << std::endl;
            throw std::runtime_error(error_msg_str);
        }
    }
    
    __global__ void add_d2D(const double *x, const double *y, double *z, int n, int m, int m_pitch_elements) 
    {
        int row = blockIdx.x * blockDim.x + threadIdx.x;
        int col = blockIdx.y * blockDim.y + threadIdx.y;
        if (row< n && col <m )
        {
            auto idx = row*m_pitch_elements + col;
            z[idx] = x[idx] + y[idx];
            //z[idx] = idx;
        }
    }
    
    __host__ void add2D(const double *a,const double *b, double *result, int N, int M) {
        double *a_d, *b_d, *c_d;
        size_t pitcha,pitchb,pitchc;
    
        CUDASAFECALL(cudaMallocPitch(&a_d, &pitcha, M * sizeof(double), N));
        CUDASAFECALL(cudaMallocPitch(&b_d, &pitchb, M * sizeof(double), N));
        CUDASAFECALL(cudaMallocPitch(&c_d, &pitchc, M * sizeof(double), N));
        CUDASAFECALL(cudaMemcpy2D(a_d, pitcha, a, M * sizeof(double), M * sizeof(double), N, cudaMemcpyHostToDevice));
        CUDASAFECALL(cudaMemcpy2D(b_d, pitchb, b, M * sizeof(double), M * sizeof(double), N, cudaMemcpyHostToDevice));
    
        dim3 threadsPerBlock(2, 2);
        auto safediv = [](auto a, auto b) {return static_cast<unsigned int>(ceil(a / (b*1.0))); };
        dim3 numBlocks(safediv(N, threadsPerBlock.x), safediv( M, threadsPerBlock.y));
        //all the pitches should be the same
        auto pitch_elements = pitcha / sizeof(double);
        add_d2D << <numBlocks, threadsPerBlock >> >(a_d, b_d, c_d, N, M, pitch_elements);
    
        CUDASAFECALL(cudaDeviceSynchronize());
    
        CUDASAFECALL(cudaMemcpy2D(result, M * sizeof(double), c_d, pitchc, M * sizeof(double), N, cudaMemcpyDeviceToHost));
    
        CUDASAFECALL(cudaFree(a_d));
        CUDASAFECALL(cudaFree(b_d));
        CUDASAFECALL(cudaFree(c_d));
    }
    
    int main()
    {
        double a[4][10];
        double b[4][10];
        double c[4][10];
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 10; j++) {
                a[i][j] = 0 + rand() % 10;
                b[i][j] = 0 + rand() % 10;
            }
        }
        add2D((double *)a, (double *)b, (double *)c, 4, 10);
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 10; j++) {
                std::cout << a[i][j] << " " << b[i][j] << " " << c[i][j]<< "|"<< a[i][j]+ b[i][j] << std::endl;
            }
        }
        return 0;
    }
    

    【讨论】:

    • 感谢您解决了所有问题。调整后的内核正是我自己想不通的。
    猜你喜欢
    • 1970-01-01
    • 2017-09-20
    • 1970-01-01
    • 2012-09-13
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    相关资源
    最近更新 更多