我对cuda很新。我在设备仿真模式下使用cuda在我的ubuntu 10.04上。 我编写了一个代码来计算以下数组的平方:
#include <stdio.h>
#include <cuda.h>
__global__ void square_array(float *a, int N)
{
int idx = blockIdx.x + threadIdx.x;
if (idx<=N)
a[idx] = a[idx] * a[idx];
}
int main(void)
{
float *a_h, *a_d;
const int N = 10;
size_t size = N * sizeof(float);
a_h = (float *)malloc(size);
cudaMalloc((void **) &a_d, size);
for (int i=0; i<N; i++) a_h[i] = (float)i;
cudaMemcpy(a_d, a_h, size, cudaMemcpyHostToDevice);
square_array <<< 1,10>>> (a_d, N);
cudaMemcpy(a_h, a_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
// Print results
for (int i=0; i<N; i++) printf(" %f\n", a_h[i]);
free(a_h);
cudaFree(a_d);
return 0;
}
当我运行此代码时,它显示没有问题,它给我正确的输出。
现在我的问题是,当我使用&lt;&lt;&lt;&lt;&lt;&gt;&gt;&gt;&gt;或LT;&LT;&LT; 5,2&GT;&GT;&GT;结果是一样的。在gpu上发生了什么? 我所理解的是,我只需要启动包含2个线程的5个块的cuda内核。 谁能解释一下Gpu如何处理这个或实现启动(内核调用)?
现在我真正的问题是,当我使用&lt;&lt;&lt;&lt;&lt;&lt;&lt; 1,10&gt;&gt;&gt;调用内核时没关系 。它显示了完美的结果。 但当我用&lt;&lt;&lt;&lt; 1,5&gt;&gt;调用内核时结果如下:
0.000000
1.000000
4.000000
9.000000
16.000000
5.000000
6.000000
7.000000
8.000000
9.000000
类似地,当我减少或增加内核调用中的第二个参数时,它显示不同的结果,例如当我将其改为&lt;&lt; 1,4&gt;&gt;时它显示以下结果:
0.000000
1.000000
4.000000
9.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
为什么这个结果会来? 任何机构都可以解释内核启动调用的工作吗?
什么是blockdim类型变量包含? 请帮助我理解内核调用启动和工作的概念? 我搜索了编程指南,但他们没有很好地解释它。
答案 0 :(得分:5)
内核代码中idx
的计算不正确。如果您将其更改为:
int idx = blockDim.x * blockIdx.x + threadIdx.x;
您可能会发现结果更容易理解。
编辑:对于任何给定的内核启动
square_array<<<gridDim,blockDim>>>(...)
在GPU中,自动变量blockDim将包含在主机端内核启动时传递的blockDim参数的x,y和z组件。类似地,gridDim将包含启动时传递的gridDim参数的x和y分量。
答案 1 :(得分:0)
除了talonmies所说的内容之外,您可能需要执行以下操作才能在实际应用程序中获得更好的性能。
if (idx < N) {
tmp = a[idx];
a[idx] = tmp * tmp;
}
答案 2 :(得分:0)
在CUDA中调用内核的方式如下:
kernel<<<numBlocks,numThreads>>>(Kernel arguments);
这意味着将有每个块中运行numThreads线程的numBlocks块。例如,如果你打电话
kernel<<<1,5>>>(Kernel args);
然后1个块将运行并行运行5个线程。如果你打电话
kernel<<<2,5>>>(Kernel args);
然后有2个块,每个块中运行5个线程。除非您更改设备代码,否则您正在“平方”的数组的最大尺寸是产品numBlocks * numThreads。这解释了为什么原始数组中的所有值都不是平方的。
我建议你仔细阅读CUDA工具包附带的CUDA_C_Programming_Guide.pdf。