2

关于CUDA的一些问题。

1)我注意到,在每个示例代码中,在全局函数中执行的非并行操作(即标量的计算)总是在指定某个线程时完成。例如,在这个点积的简单代码中,线程 0 执行求和:

    __global__ void dot( int *a, int *b, int *c )
    {
       // Shared memory for results of multiplication   
       __shared__ int temp[N]; 
       temp[threadIdx.x] = a[threadIdx.x] * b[threadIdx.x];

       // Thread 0 sums the pairwise products
       if( 0 == threadIdx.x ) 
       {
       int sum = 0;
       for( int i = 0; i < N; i++ )
           sum += temp[i];

       *c = sum;
       }
    }

这对我来说很好;但是,在我编写的代码中,我没有为非并行操作指定线程,它仍然有效:因此,是否必须定义线程?特别是,我要执行的非并行操作如下:

        if (epsilon == 1)
        {
            V[0] = B*(Exp - 1 - b);
        }
        else
        {
            V[0] = B*(Exp - 1 + a);
        }

各种变量作为全局函数的参数传递。我的第二个问题来了。

V[0]2) 我用 CUDA 中的一个程序和 CPU 上的另一个序列计算了 的值,得到了不同的结果。显然我认为 CUDA 中的问题可能是我没有指定线程,但是,即使这样,结果也没有改变,而且它仍然(很多)比串行的大:6.71201e+22 vs -2908.05 . 问题可能出在哪里?在全局函数中执行的其他计算如下:

int tid = threadIdx.x;

if ( tid != 0 && tid < N )
{
    {Various stuff which does not involve V or the variables used to compute V[0]}

    V[tid] = B*(1/(1+alpha[tid]*alpha[tid])*(One_G[tid]*Exp - Cos - alpha[tid]*Sin) + kappa[tid]*Sin);
}

如您所见,在我的情况下,我避免考虑这种情况tid == 0

3)最后一个问题:通常在示例代码中我注意到,如果你想在 GPU 内存上分配和计算的 CPU 值上使用,你应该将这些值复制到 CPU 上(例如,使用 command cudaMemcpy,指定cudaMemcpyDeviceToHost) . 但是我设法直接在主代码(CPU)中使用这些值而没有任何问题。这可能是我的 GPU(或我安装的 CUDA)有问题的线索,这也导致了以前的奇怪事情吗?

感谢您的帮助。

== 1 月 5 日添加 ==

抱歉我的回复晚了。在调用内核之前,需要计算数组的所有内存分配(相当多)。特别是,我的问题中涉及的数组的代码是:

float * V;
cudaMalloc( (void**)&V, N * sizeof(float) );

在我写的代码的最后:

float V_ [N];
cudaMemcpy( &V_, V, N * sizeof(float), cudaMemcpyDeviceToHost );

cudaFree(V);

cout << V_[0] << endl;

再次感谢您的关注。

4

2 回答 2

2

如果您的代码中没有任何cudaMemcpy内容,那就是问题所在。;-) GPU 正在访问它自己的内存(显卡上的 RAM),而 CPU 正在访问主板上的 RAM。您需要先使用 分配和复制 alpha、kappa、One_g 和所有其他数组到您的 GPU cudaMemcpy,然后运行您的内核,然后将结果复制回 CPU。另外,不要忘记在两边分配内存。

至于非并行的东西:如果结果总是一样的,那么所有线程都会写同样的东西,所以结果是完全一样的,只是效率低了一点,因为它们都试图访问相同的资源。

于 2013-01-02T22:11:34.977 回答
1

那是您使用的确切代码吗?关于问题 1,在分配给共享内存 temp 之后,您应该有一个 __syncthreads()。否则,您将获得一个竞争条件,其中线程 0 可以在 temp 完全填充之前开始求和。

至于您关于指定线程的其他问题,如果您有

if (epsilon == 1)
{
    V[0] = B*(Exp - 1 - b);
}
else
{
    V[0] = B*(Exp - 1 + a);
}

然后每个线程都会执行该代码;例如,如果您有 X 个线程正在执行,并且所有线程的 epsilon 为 1,那么所有 X 个线程将评估同一行:

V[0] = B*(Exp - 1 - b);

因此您将遇到另一个竞争条件,因为您将让所有 X 线程写入 V[0]。如果所有线程的 B*(Exp - 1 - b) 值相同,那么您可能不会注意到差异,而如果它们具有不同的值,那么您每次都可能得到不同的结果,具体取决于线程的顺序线程到达

于 2013-01-03T20:17:47.383 回答