谁能解释一下这个 CUDA 内核是如何执行的?

标签 c cuda

我是 CUDA 的初学者,我尝试了这个示例代码。

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};
    cudaMalloc((void**)&d_in,9*sizeof(float));
    cudaCheckErrors("malloc failed");
    cudastatus=cudaMemcpy(d_in,h_in,9*sizeof(float),cudaMemcpyHostToDevice);
    cudaCheckErrors("memcpyh2d failed");
    float* d_out={0};
    cudaMalloc((void**)&d_out,9*sizeof(float));
    float* out[9]={0};
    kernel<<<3,3>>>(d_in,d_out);
    cudastatus=cudaDeviceSynchronize();
    cudaError_t cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess) {
         fprintf(stderr, "Kernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
         getchar();
    }
    cudaStatus = cudaDeviceSynchronize();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching             Kernel!\n", cudaStatus);
    getchar();
      }
    cudastatus=cudaMemcpy(out,d_out,9*sizeof(float),cudaMemcpyDeviceToHost);
    cudaCheckErrors("memcpyd2h failed");
    for(i=0;i<9;i++)
    {
        printf("%f\n",out[i]);
    }
    getchar();
    return 0;

}

内核代码是这样的

__device__ void func(float temp)
{
     float a=2;
     temp=temp*a;
     return;
}
__global__ void kernel(float* d_in, float* d_out)
{
     int tid=(blockIdx.x*blockDim.x)+threadIdx.x;
     float temp=d_in[tid];
     func(temp);
     d_out[tid]=d_out[tid]+temp;
}

但是当我打印 out 数组的值时,这些值全为零。我的问题是 是否为每个线程从内核调用设备函数? GPU 中如何执行此操作?

最佳答案

任何时候您在使用 CUDA 代码时遇到问题,您都应该这样做 proper cuda error checking并使用cuda-memcheck运行您的代码。由于程序中的其他错误,或者计算机上的 CUDA 设置存在问题,内核可能根本没有执行。

这个函数:

__device__ void func(float temp)
{
     float a=2;
     temp=temp*a;
     return;
}

由于与 CUDA 无关的原因,无法做任何有用的事情。

在 C/C++ 中,当我们将参数传递给这样的函数时:

void func(float temp)

temp 参数按值传递。这意味着副本temp组成,并提供给要使用的函数。该副本与调用环境中的任何temp独立。对 temp 的任何修改都不会显示在调用环境中。因此该函数没有做任何有用的事情。尽管它看起来是将 temp 乘以 a(本例中为 2),但当函数返回时,修改后的值就会丢失。

为了避免这种情况,您应该了解有关 C/C++ 编程的更多信息,并考虑通过指针传递值(模拟按引用传递):

__device__ void func(float *temp)

或引用:

__device__ void func(float &temp)

这行代码也不是您想要的:

float* out[9]={0};

我认为应该是:

float out[9]={0};

您需要一个float数量数组,而不是一个float指针数组。

这是代码的“固定”版本:

#include <stdio.h>

__device__ void func(float &temp)
{
     float a=2;
     temp=temp*a;
     return;
}
__global__ void kernel(float* d_in, float* d_out)
{
     int tid=(blockIdx.x*blockDim.x)+threadIdx.x;
     float temp=d_in[tid];
     func(temp);
     d_out[tid]=d_out[tid]+temp;
}

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};
    kernel<<<3,3>>>(d_in,d_out);
    cudaDeviceSynchronize();
    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]);
    }
    return 0;
}

关于谁能解释一下这个 CUDA 内核是如何执行的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25035758/

相关文章:

编译器不会在函数参数不匹配时发出错误/警告

c - 乱序执行和内存栅栏

c - C中的部分线程排序

CUDA 地址越界

CUDA Thrust : reduce_by_key on only some values in an array, 基于 "key"数组中的值

memory - 内存一致性模型 CUDA 4.0 和全局内存?

c++ - 访问冲突读取位置 0x00184000

封装静态2D对象的CUDA结构

c++ - 如何确定 Mandelbrot 集缩放的良好中心

c - Thermo 迷你打印机上 C 语言的文本换行