• CUDA核函数


    启动一个核函数

    一个CUDA函数的调用

    kernel_name <<>>(argument list);

    <<<>>>中间的部分,是核函数的运行配置。执行配置的第一个值是网格维度,也就是启动块的数目;第二个值是块维度,也就是每个块中线程的数目。

    同一个块中的线程可以相互协作,不同块内的线程不能协作。

    由于数据在全局内存中是线性存储的,因此可以用变量blockIdx.x和threadIdx.x来进行以下操作。

    • 在网格中标识一个唯一的线程
    • 建立线程和数据元素之间的映射关系

    核函数的调用与主机线程是异步的。核函数调用结束后,控制权立刻返回给主机端。但是可以通过调用以下函数来强行令主机端等待所有的核函数执行结束:

    cudaError_t cudaDeviceSynchronize(void);

    举个栗子

    我们在调用核函数之后,控制权立刻返回给主机端,所以先打印了hello cpu,然后才打印了GPU的核函数的输出。

    强制让主机端等待后,先输出了核函数的打印,才打印了主机端的CPU。

    另外一些CUDA运行时API在主机端与设别端是隐式同步的,比如cudaMemcpy函数,在之前所有的核函数调用完成后,开始拷贝数据。直到数据拷贝完成后,将控制权返回给主机端

    编写核函数

    核函数的定义

    1. __global__ void kerel_name(argument list){
    2. //...
    3. }

    核函数由__global__声明,返回类型必须是void

    下面说明CUDA中函数类型限定符

    __global__在设备端执行

    可以从主机端调用

    也可以从计算能力为3的设备中调用

    __device__在设备端执行仅能从设备端调用
    __host__在主机端执行

    仅能从主机端调用(可以省略)

    device限定符和host限定符可以一起使用,这样函数可以同时在主机端和设备端进行编译。

    CUDA核函数的限制

    • 只能访问设备内存
    • 必选返回void类型
    • 不支持可变数量的参数
    • 不支持静态变量
    • 显示异步行为

    举个栗子

    将两个大小为N的向量A,B相加,如果在主机端完成,代码如下

    1. void sumArray(int* A, int* B, int* C, const int N){
    2. for(int i=0; i
    3. c[i] = A[i] + B[i];
    4. }

    我们对比一下在GPU核函数上进行相同的操作

    1. __global__ void addArrayOnGPU(const int* a, const int* b, int* c) {
    2. int i = threadIdx.x;
    3. c[i] = a[i] + b[i];
    4. }
    5. int main()
    6. {
    7. using namespace std;
    8. int a[] = { 1,2,3,4 };
    9. int b[] = { 1,2,3,4 };
    10. int c[4];
    11. int* d_a, * d_b, * d_c;
    12. cudaMalloc((int**)&d_a, sizeof(a));
    13. cudaMalloc((int**)&d_b, sizeof(b));
    14. cudaMalloc((int**)&d_c, sizeof(c));
    15. cudaMemcpy(d_a, a, sizeof(a), cudaMemcpyHostToDevice);
    16. cudaMemcpy(d_b, b, sizeof(b), cudaMemcpyHostToDevice);
    17. addArrayOnGPU << <1, 4 >> > (d_a, d_b, d_c);
    18. cudaMemcpy(c, d_c, sizeof(a), cudaMemcpyDeviceToHost);
    19. cudaDeviceReset();
    20. for (int i = 0; i < 4; i++)
    21. cout << c[i] << " ";
    22. return 0;
    23. }

    我们注意到,循环体消失了,用内置的线程坐标变量替换了数组索引。因为我们在主机端调用核函数时,启动了4个线程,每个线程都从GPU全局内存中读取数据并且进行了修改。

  • 相关阅读:
    【C++11新特性】右值引用和移动语义(移动构造,移动赋值)
    【线下沙龙】低成本高效率构建您的业务系统
    无代码开发平台权限设置入门教程
    为什么不建议给MySQL设置Null值?《死磕MySQL系列 十八》
    什么是Redis?
    微信小程序标题栏封装
    【Linux】详解自主实现HTTP服务器
    ArcGIS JS自定义Accessor,并通过watchUtils相关方法watch属性
    二叉搜索树中的搜索(力扣700)
    高质量的子程序
  • 原文地址:https://blog.csdn.net/A11en3/article/details/138185668