Memory management CUDA:来自CPU的不同结果

Memory management CUDA:来自CPU的不同结果,memory-management,cuda,thread-safety,Memory Management,Cuda,Thread Safety,关于CUDA的一些问题 1) 我注意到,在每个示例代码中,在全局函数中执行的非并行操作(即标量计算)总是指定某个线程来完成。例如,在此点积的简单代码中,线程0执行求和: __global__ void dot( int *a, int *b, int *c ) { // Shared memory for results of multiplication __shared__ int temp[N]; temp[threadId

关于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;
       }
    }
各种变量作为全局函数的参数传递。我的第二个问题来了

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

        if (epsilon == 1)
        {
            V[0] = B*(Exp - 1 - b);
        }
        else
        {
            V[0] = B*(Exp - 1 + a);
        }
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);
}
在代码末尾,我写道:

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

cudaFree(V);

cout << V_[0] << endl;
float V_un];
cudaMemcpy(&V_,V,N*sizeof(float),cudaMemcpyDeviceToHost);
cudaFree(V);

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


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

这就是您使用的代码吗? 关于问题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)值相同,那么您可能不会注意到差异,而如果它们的值不同,那么您每次都可能得到不同的结果,具体取决于线程到达的顺序。

请查看NVIDIA白皮书:@njuffa感谢您的链接。我读了论文的一些部分,但我的问题不同:我得到的结果大不相同,而论文建议结果应该仍然非常相似。微小的差异可能会被后续计算放大。问题也可能不是数值上的差异,而是代码中的错误。是的,但我的问题是我尝试了一个非常小的计算(问题中的那个),结果仍然没有意义。关于代码中的bug:我将尝试代码的一个简单实现,看看我得到了什么。谢谢你的帮助!不,我尝试了使用
cudaMemcpy
和不使用这两种方法,但得到了相同的、更大的结果。这就是为什么我认为我的GPU和/或CUDA安装有问题。抱歉,如果我的问题不清楚。那么问题可能仍然存在于memcpy或内核调用的某个地方,那么您可以发布这部分源代码吗?Rico是对的,如果您在内核调用之前和之后发布内存分配和复制调用,这将非常有用,因为问题似乎是你的结果没有改变。memcpy调用是绝对必要的。CPU不能直接访问GPU板上的RAM,GPU也不能访问CPU RAM上的RAM。您必须将输入数据复制到您的内核到GPU的RAM中(使用
cudaMemcpyHostToDevice
),并将内核的输出复制回CPU的RAM中(使用
cudaMemcpyDeviceToHost
),Rico对于您的第一个问题也是正确的。如果您没有指定一个特定的线程来执行非并行计算,那么每个线程都会这样做。但是,由于每个线程都将结果存储在相同的位置,因此每个线程将向该内存地址写入相同的值一次,而不是总共写入一次。这将慢得多,因为每一次写操作都必须按顺序进行,尽管它会产生相同的答案。
V[0] = B*(Exp - 1 - b);