了解CUDA内核执行

时间:2014-08-06 09:58:51

标签: c cuda

我正在学习CUDA,我尝试了以下内核代码。

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "cuPrintf.cu"
#include <stdio.h>

__device__ void func(float &temp,float* dum)
{
    float a=5;
dum[threadIdx.x]=temp+a;
cuPrintf("%f\n",dum[threadIdx.x]);
return;
}
__global__ void kernel(float* d_in, float* d_out)
{
 int tid=(blockIdx.x*blockDim.x)+threadIdx.x;
 float temp=d_in[tid];
 float dum[9];
 func(temp,dum);
 cuPrintf("dum %f\n",dum[threadIdx.x]);
 atomicAdd(&d_out[tid],dum[tid]);
 //d_out[tid]+=dum[tid];
 cuPrintf("d_out %f\n",d_out[threadIdx.x]);
 }

 int main()
 {
    int i;
    cudaError_t cudastatus;
    float in[9]={1,2,3,4,5,6,7,8,9};
    float* h_in=in;
    float* d_in={0};
    cudastatus=cudaMalloc((void**)&d_in,9*sizeof(float));
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm0 fail %s\n", cudaGetErrorString(cudastatus));
    }
    cudastatus=cudaMemcpy(d_in,h_in,9*sizeof(float),cudaMemcpyHostToDevice);
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm1 fail %s\n", cudaGetErrorString(cudastatus));
    }
    float* d_out={0};
    cudastatus=cudaMalloc((void**)&d_out,9*sizeof(float));
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm2 fail %s\n", cudaGetErrorString(cudastatus));
    }
    cudaMemset(d_out, 0, 9*sizeof(float));
    float out[9]={0};
    cudaPrintfInit();
    kernel<<<3,3>>>(d_in,d_out);
    cudaDeviceSynchronize();
    cudaPrintfDisplay(stdout,true);
    cudaPrintfEnd();
    cudastatus = cudaGetLastError();
    if (cudastatus != cudaSuccess) {
        fprintf(stderr, "Kernel launch failed: %s\n", cudaGetErrorString(cudastatus));
    }
    cudastatus=cudaMemcpy(out,d_out,9*sizeof(float),cudaMemcpyDeviceToHost);
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm3 fail %s\n", cudaGetErrorString(cudastatus));
    }
    for(i=0;i<9;i++)
    {
        printf("%f\n",out[i]);
    }
    getchar();
    return 0;
}

虽然我没有在cuda-memcheck中通过cudaError_t检查得到任何错误,但是printf在设备函数内部给出了输出,而在全局函数中的输出是不同的。 (我尝试了简单的添加和原子添加操作)。

  1. 造成这种差异的原因是什么以及如何解决这个问题?

  2. 另外,我们如何确保为每个temp值调用设备函数?

  3. 请帮我解决这个问题。提前谢谢。

1 个答案:

答案 0 :(得分:0)

您正在启动三个块,每个块有三个线程。在每个块中,这3个线程将具有以下值,每个线程一个:

线程0:threadIdx.x = 0; 线程1:threadIdx.x = 1; 线程2:threadIdx.x = 2;

因此,当您在3个块中的每个块中调用func时,所有3个块中的线程都写入dum的相同3个位置:

dum[threadIdx.x]=temp+a;

即。只有这9个位置数组的0-2位置才会被这行代码填充。

此外,每个线程块都是&#39;由于此初始化,三个线程组将向这三个位置写入不同的值,该初始化不使用threadIdx.x,而是使用tid

float temp=d_in[tid];

由于每个threadblock都在func中写入不同的值,因此func或内核中打印的值可能会随时根据threadblock的确切顺序更改执行。没有办法理解这一点。

简而言之,将tid(一个全局唯一的线程索引)和threadIdx.x(一个线程块唯一线程索引)混合在一起相当令人困惑,并且会导致不可预测由于竞争条件导致的行为,因为未指定线程块执行的顺序。

相反,如果您始终使用tid,我认为您会获得可理解的行为:

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "cuPrintf.cu"
#include <stdio.h>

__device__ void func(float &temp,float* dum, int id)
{
    float a=5;
dum[id]=temp+a;
cuPrintf("%f\n",dum[id]);
return;
}
__global__ void kernel(float* d_in, float* d_out)
{
 int tid=(blockIdx.x*blockDim.x)+threadIdx.x;
 float temp=d_in[tid];
 float dum[9];
 func(temp,dum,tid);
 cuPrintf("dum %f\n",dum[tid]);
 atomicAdd(&d_out[tid],dum[tid]);
 //d_out[tid]+=dum[tid];
 cuPrintf("d_out %f\n",d_out[tid]);
 }

 int main()
 {
    int i;
    cudaError_t cudastatus;
    float in[9]={1,2,3,4,5,6,7,8,9};
    float* h_in=in;
    float* d_in={0};
    cudastatus=cudaMalloc((void**)&d_in,9*sizeof(float));
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm0 fail %s\n", cudaGetErrorString(cudastatus));
    }
    cudastatus=cudaMemcpy(d_in,h_in,9*sizeof(float),cudaMemcpyHostToDevice);
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm1 fail %s\n", cudaGetErrorString(cudastatus));
    }
    float* d_out={0};
    cudastatus=cudaMalloc((void**)&d_out,9*sizeof(float));
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm2 fail %s\n", cudaGetErrorString(cudastatus));
    }
    cudaMemset(d_out, 0, 9*sizeof(float));
    float out[9]={0};
    cudaPrintfInit();
    kernel<<<3,3>>>(d_in,d_out);
    cudaDeviceSynchronize();
    cudaPrintfDisplay(stdout,true);
    cudaPrintfEnd();
    cudastatus = cudaGetLastError();
    if (cudastatus != cudaSuccess) {
        fprintf(stderr, "Kernel launch failed: %s\n", cudaGetErrorString(cudastatus));
    }
    cudastatus=cudaMemcpy(out,d_out,9*sizeof(float),cudaMemcpyDeviceToHost);
    if (cudastatus != cudaSuccess) {
         fprintf(stderr, "cm3 fail %s\n", cudaGetErrorString(cudastatus));
    }
    for(i=0;i<9;i++)
    {
        printf("%f\n",out[i]);
    }
    getchar();
    return 0;
}