我有一个由多个CPU线程组成的应用程序,每个CPU线程在我的GPU上的同一个cudaContext中创建一个单独的cudaStream。我有特斯拉K20c。我正在使用Windows 7 64位和Cuda 5.5。
这是我的代码:
#include "gpuCode.cuh"
__global__ void kernelAddConstant1(int *g_a, const int b)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
g_a[idx] += b;
for (int i = 0; i < 4000000.0; i++)
{
if (i%2 == 0)
{
g_a[idx] += 5;
}
else
{
g_a[idx] -= 5;
}
}
}
// a predicate that checks whether each array elemen is set to its index plus b
int correctResult(int *data, const int n, const int b)
{
for (int i = 0; i < n; i++)
{
if (data[i] != i + b)
{
return 0;
}
}
return 11;
}
int gpuDo()
{
cudaSetDevice(0);
cudaStream_t stream;
cudaStreamCreate( &stream );
int *a;
int *d_a;
unsigned int n;
unsigned int nbytes;
int b;
n = 2 * 8192/16;
nbytes = n * sizeof(int);
b = 7; // value by which the array is incremented
cudaHostAlloc( (void**)&a, nbytes, cudaHostAllocDefault ) ;
cudaMalloc((void **)&d_a, nbytes);
for (unsigned int i = 0; i < n; i++)
a[i] = i;
unsigned int nbytes_per_kernel = nbytes;
dim3 gpu_threads(128); // 128 threads per block
dim3 gpu_blocks(n / gpu_threads.x);
cudaMemsetAsync(d_a, 0, nbytes_per_kernel, stream);
cudaMemcpyAsync(d_a, a, nbytes_per_kernel, cudaMemcpyHostToDevice, stream);
kernelAddConstant1<<<gpu_blocks, gpu_threads, 0, stream>>>(d_a, b);
cudaMemcpyAsync(a, d_a, nbytes_per_kernel, cudaMemcpyDeviceToHost, stream);
cudaStreamSynchronize ( stream ) ;
cudaStreamDestroy(stream);
//cudaFree(d_a);
int bResult = correctResult(a, n, b);
//if (a)
//cudaFreeHost(a); // free CPU memory
return bResult;
}
void gpuEnd()
{
cudaDeviceReset();
}
当我离开cudaFree并且cudaFreeHost注释掉时,我实现了以下结果:
这是完美的,除了我有内存泄漏,因为我没有使用cudaFree和cudaFreeHost。当我使用cudaFree和cudaFreeHost时,我得到以下结果:
这很糟糕。当使用cudaFree时,一些流等待其他流完成,一些流异步工作。我假设这是因为cudaFree不是异步的,这很好,但是这并不能解释为什么它有时会像调用前三个内核那样工作,而不是在其他时候?如果cudaFree被调用但GPU已经忙于做其他事情,那么CPU是否可以继续计算并让cudaFree在第一次获得机会时自动发生?有没有其他方法来解决这个问题?感谢您提供任何帮助!
答案 0 :(得分:1)
是的,cudaFree
不是异步的。 Niether是cudaMalloc
在时间关键代码之前预先完成所有分配,并在最后执行免费操作。
在您的情况下,这应该特别容易,因为每次分配的大小都是相同的。
相同的评论适用于流创建。我不打算在飞行中创造和摧毁它们。创建你想要的许多,并重复使用它们直到你完成。