几天前,我正在比较我的一些代码的性能,其中我执行了相同算法的非常简单的替换和推力实现。我发现一个数量级的不匹配(!)有利于 Thrust,所以我开始让我的调试器“冲浪”到他们的代码中,以发现魔法发生的地方。
令人惊讶的是,我发现我非常直接的实现实际上与他们的非常相似,一旦我摆脱了所有仿函数的东西并进入了本质。我看到 Thrust 有一个聪明的方法来决定 block _size 和 grid_size (顺便说一句:确切地说,它是如何工作的?!),所以我只是接受他们的设置并再次执行我的代码,因为它们非常相似。我获得了一些微秒,但情况几乎相同。然后,最后,我不知道为什么,只是“尝试”我在内核和 BINGO 之后删除了 cudaThreadSynchronize()!我将差距归零(并且更好)并获得了整个数量级的执行时间。访问我的数组的值,我看到它们完全符合我的预期,因此执行正确。
现在的问题是:我什么时候可以摆脱 cudaThreadSynchronize (et similia)?为什么会造成如此巨大的开销?我看到 Thrust 本身最后没有同步(如果未定义宏 __THRUST_SYNCHRONOUS 且未定义,则为 NOP,synchronize_if_enabled(const char* message))。详细信息和代码如下。
// my replace code
template <typename T>
__global__ void replaceSimple(T* dev, const int n, const T oldval, const T newval)
{
const int gridSize = blockDim.x * gridDim.x;
int index = blockIdx.x * blockDim.x + threadIdx.x;
while(index < n)
{
if(dev[index] == oldval)
dev[index] = newval;
index += gridSize;
}
}
// replace invocation - not in main because of cpp - cu separation
template <typename T>
void callReplaceSimple(T* dev, const int n, const T oldval, const T newval)
{
replaceSimple<<<30,768,0>>>(dev,n,oldval,newval);
cudaThreadSynchronize();
}
// thrust replace invocation
template <typename T>
void callReplace(thrust::device_vector<T>& dev, const T oldval, const T newval)
{
thrust::replace(dev.begin(), dev.end(), oldval, newval);
}
参数详细信息:数组:n=10,000,000 个元素设置为 2,oldval=2,newval=3
- 执行推力调用替换(推力)的时间:0.057 ms
- 同步执行 callReplaceSimple 的时间:0.662 毫秒
- 不同步执行 callReplaceSimple 的时间:0.011 毫秒
我使用了包含 Thrust 的 CUDA 5.0,我的显卡是 GeForce GTX 570,我有一个四核 Q9550 2.83 GHz 和 2 GB RAM。