【问题标题】:Concurrently initializing many arrays with random numbers using Curand and CUDA kernel使用 Curand 和 CUDA 内核同时初始化许多具有随机数的数组
【发布时间】:2018-01-16 05:38:31
【问题描述】:

我正在尝试在 GPU 上同时使用随机生成的数字初始化每个这些并行数组的 100 个元素。但是,我的例程不会产生各种随机数。当我在 Visual Studio 中调试代码时,我看到数组中的每个元素都有一个数字。这段代码的目的是优化 CImg FilledTriangles 例程以尽可能使用 GPU。

我做错了什么,我该如何解决?这是我的代码:

__global__ void initCurand(curandState* state, unsigned long seed)
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    curand_init(seed, idx, 0, &state[idx]);
    __syncthreads();
}

/*
 * CUDA kernel that will execute 100 threads in parallel
*/

__global__ void initializeArrays(float* posx, float* posy,float* rayon, float* veloc, float* opacity
                                ,float * angle, unsigned char** color, int height, int width, curandState* state){

    int idx = threadIdx.x + blockIdx.x * blockDim.x;

    curandState localState = state[idx];
    __syncthreads();

    posx[idx] = (float)(curand_uniform(&localState)*width);
    posy[idx] = (float)(curand_uniform(&localState)*height);
    rayon[idx] = (float)(10 + curand_uniform(&localState)*50);
    angle[idx] = (float)(curand_uniform(&localState)*360);
    veloc[idx] = (float)(curand_uniform(&localState)*20 - 10);
    color[idx][0] = (unsigned char)(curand_uniform(&localState)*255);
    color[idx][1] = (unsigned char)(curand_uniform(&localState)*255);
    color[idx][2] = (unsigned char)(curand_uniform(&localState)*255);
    opacity[idx] = (float)(0.3 + 1.5*curand_uniform(&localState));
}

这是准备和调用这些内核的主机代码:我正在尝试在网格的一个块上创建 100 个线程(针对每个元素)。

 // launch grid of threads
      dim3 dimBlock(100);
      dim3 dimGrid(1);

      initCurand<<<dimBlock,dimGrid>>>(devState, unsigned(time(nullptr)));
      // synchronize the device and the host
    cudaDeviceSynchronize();
     initializeArrays<<<dimBlock, dimGrid>>>(d_posx, d_posy, d_rayon, d_veloc, d_opacity, d_angle,d_color, img0.height(), img0.width(), devState);

预赛:

  // Define random properties (pos, size, colors, ..) for all triangles that will be displayed.
    float posx[100], posy[100], rayon[100], angle[100], veloc[100], opacity[100];
    // Define the same properties but for the device
    float* d_posx;
    float* d_posy;
    float* d_rayon;
    float* d_angle;
    float* d_veloc;
    float* d_opacity;
    //unsigned char d_color[100][3];
    unsigned char** d_color;
    curandState* devState;
    cudaError_t err;

    // allocate memory on the device for the device arrays
    err = cudaMalloc((void**)&d_posx, 100 * sizeof(float));
    err = cudaMalloc((void**)&d_posy, 100 * sizeof(float));
    err = cudaMalloc((void**)&d_rayon, 100 * sizeof(float));
    err = cudaMalloc((void**)&d_angle, 100 * sizeof(float));
    err = cudaMalloc((void**)&d_veloc, 100 * sizeof(float));
    err = cudaMalloc((void**)&d_opacity, 100 * sizeof(float));
    err = cudaMalloc((void**)&devState, 100*sizeof(curandState));
    errCheck(err);
    size_t pitch;
    //allocated the device memory for source array  
    err = cudaMallocPitch(&d_color, &pitch, 3 * sizeof(unsigned char),100);

得到结果:

// get the populated arrays back to the host for use
     err = cudaMemcpy(posx,d_posx, 100 * sizeof(float), cudaMemcpyDeviceToHost);
     err = cudaMemcpy(posy,d_posy, 100 * sizeof(float), cudaMemcpyDeviceToHost);
     err = cudaMemcpy(rayon,d_rayon, 100 * sizeof(float), cudaMemcpyDeviceToHost);
     err = cudaMemcpy(veloc,d_veloc, 100 * sizeof(float), cudaMemcpyDeviceToHost);
     err = cudaMemcpy(opacity,d_opacity, 100 * sizeof(float), cudaMemcpyDeviceToHost);
     err = cudaMemcpy(angle,d_angle, 100 * sizeof(float), cudaMemcpyDeviceToHost);
     err = cudaMemcpy2D(color,pitch,d_color,100, 100 *sizeof(unsigned char),3, cudaMemcpyDeviceToHost);

【问题讨论】:

    标签: random parallel-processing cuda cimg


    【解决方案1】:

    您肯定需要对此进行更改:

    err = cudaMalloc((void**)&devState, 100*sizeof(float));
    

    到这里:

    err = cudaMalloc((void**)&devState, 100*sizeof(curandState));
    

    如果您通过 cuda-memcheck 运行代码,您就会发现这一点。因此,您的 initCurand 内核有很多越界访问。

    您还应该在所有 cuda 调用和所有内核启动时执行 error checking。我相信您的第二个内核调用失败是由于您的 color[][] 数组上的操作混乱。

    通常当我们使用cudaMallocPitch 创建一个数组时,我们需要使用 pitch 参数来访问它。 C 的双下标数组本身是行不通的,因为 C 对实际的数组宽度没有内在的了解。

    我能够通过进行以下更改来修复它:

    __global__ void initializeArrays(float* posx, float* posy,float* rayon, float* veloc, float* opacity,float * angle, unsigned char* color, int height, int width, curandState* state, size_t pitch){
    
        int idx = threadIdx.x + blockIdx.x * blockDim.x;
    
        curandState localState = state[idx];
        __syncthreads();
    
        posx[idx] = (float)(curand_uniform(&localState)*width);
        posy[idx] = (float)(curand_uniform(&localState)*height);
        rayon[idx] = (float)(10 + curand_uniform(&localState)*50);
        angle[idx] = (float)(curand_uniform(&localState)*360);
        veloc[idx] = (float)(curand_uniform(&localState)*20 - 10);
        color[idx*pitch] = (unsigned char)(curand_uniform(&localState)*255);
        color[(idx*pitch)+1] = (unsigned char)(curand_uniform(&localState)*255);
        color[(idx*pitch)+2] = (unsigned char)(curand_uniform(&localState)*255);
        opacity[idx] = (float)(0.3 + 1.5*curand_uniform(&localState));
    }
    

     initializeArrays<<<dimBlock, dimGrid>>>(d_posx, d_posy, d_rayon, d_veloc, d_opacity, d_angle,d_color, img0.height(), img0.width(), devState, pitch);
    

    unsigned char* d_color;
    

    通过这些更改,我能够消除我发现的错误并且代码会吐出各种随机值。我还没有检查所有值,但这应该可以帮助您入门。

    【讨论】:

    • 谢谢!我不敢相信我错过了!我对CUDA相当陌生。我将更新我的问题以包含该更改。
    • 实际上,通过我的额外编辑,我认为您应该能够使其正常工作
    • 我仍然遇到错误,但这可能是由于颜色数组结构被更改以及它是如何被调用的。我会做出这些改变,我会看看会发生什么。非常感谢您的帮助,在 CUDA 中我还有很多东西要学。
    • 对于未来的读者:还有一个索引计算错误:int idx = threadIdx.x + blockIdx.x * blockDim.x;应该是int idx = threadIdx.x * blockDim.x + blockIdx.x;,否则随机数将高度相关。
    • 我不同意上述评论。给定的索引是在 CUDA 中创建全局唯一线程索引的标准索引方法。建议的修改将造成一种以各种方式被破坏的情况。如果担心线程之间生成的随机数相关性,可以通过在初始化时适当处理传递给教线程的种子或使用其他方法来解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 2016-12-24
    • 2013-02-09
    • 2018-10-12
    • 1970-01-01
    相关资源
    最近更新 更多