内核中的bool变量是否需要同步

时间:2018-04-18 03:35:25

标签: cuda

我有一个由for循环组成的内核,它在数组中搜索特定的int值。我正在使用256个线程的网格块来执行此操作。但是,当一个线程找到该值时,我想让其他线程知道退出。目前我正在使用布尔标志,但我不确定它是否正常工作。我关心的是同步。

{{1}}

1 个答案:

答案 0 :(得分:1)

正如评论中所指出的,通过将全局设备标志声明为volatile(可以禁止缓存)和使用内存栅栏功能,您可以实现所需。除了CUDA 9和新硬件中引入的新网格同步机制之外,确实没有全局同步原语,但是在这种情况下可能不是必需的。将您的伪代码转变为玩具示例:

#include <iostream>
#include <thrust/device_vector.h>

__device__ volatile bool found;
__device__ volatile size_t idx;

template<bool docheck>
__global__
void search(const int* arr, int x, size_t N)
{
   size_t i = threadIdx.x + blockIdx.x * blockDim.x;
   size_t stride = blockDim.x * gridDim.x;

   for(; (i<N) && (!found); i += stride)
   {
        if(arr[i] == x)
        {
             if (docheck) found = true;
             idx = i;
             __threadfence();
             break;
        }
   }
}  

int main()
{
    const size_t N = 1 << 24;
    const size_t findidx = 280270;
    const int findval = 0xdeadbeef;

    thrust::device_vector<int> data(N,1);
    data[findidx] = findval;

    bool flag = false;
    size_t zero = 0;


    {
    cudaMemcpyToSymbol(found, &flag, sizeof(bool));
    cudaMemcpyToSymbol(idx, &zero, sizeof(size_t));
    int blocks, threads;
    cudaOccupancyMaxPotentialBlockSize(&blocks, &threads, search<false>);
    search<false><<<blocks, threads>>>(thrust::raw_pointer_cast(data.data()), findval, N);
    cudaDeviceSynchronize();
    size_t result = 0;
    cudaMemcpyFromSymbol(&result, idx, sizeof(size_t)); 
    std::cout << "result = " << result << std::endl;
    }

    {
    cudaMemcpyToSymbol(found, &flag, sizeof(bool));
    cudaMemcpyToSymbol(idx, &zero, sizeof(size_t));
    int blocks, threads;
    cudaOccupancyMaxPotentialBlockSize(&blocks, &threads, search<true>);
    search<true><<<blocks, threads>>>(thrust::raw_pointer_cast(data.data()), findval, N);
    cudaDeviceSynchronize();
    size_t result = 0;
    cudaMemcpyFromSymbol(&result, idx, sizeof(size_t)); 
    std::cout << "result = " << result << std::endl;
    }

    return 0;
}

并对其进行分析提供以下内容:

$ nvcc -arch=sm_52 -o notify notify.cu
$ nvprof ./notify
==3916== NVPROF is profiling process 3916, command: ./notify
result = 280270
result = 280270
==3916== Profiling application: ./notify
==3916== Profiling result:
            Type  Time(%)      Time     Calls       Avg       Min       Max  Name
 GPU activities:   78.00%  1.6773ms         1  1.6773ms  1.6773ms  1.6773ms  void search<bool=0>(int const *, int, unsigned long)
                   19.93%  428.63us         1  428.63us  428.63us  428.63us  void thrust::cuda_cub::core::_kernel_agent<thrust::cuda_cub::__parallel_for::ParallelForAgent<thrust::cuda_cub::__uninitialized_fill::functor<thrust::device_ptr<int>, int>, unsigned long>, thrust::cuda_cub::__uninitialized_fill::functor<thrust::device_ptr<int>, int>, unsigned long>(thrust::device_ptr<int>, int)
                    1.82%  39.199us         1  39.199us  39.199us  39.199us  void search<bool=1>(int const *, int, unsigned long)

如您所见,设置找到标志的版本在40微秒内完成搜索,而未设置标志的版本则需要1.7毫秒。鉴于内核在两种情况下都以最大驻留块数运行,我们可以得出结论:早期退出机制正常工作,并且运行块检测到已找到所需的值。