CUDA编程之CUDA Sample-0_Introduction-simplePrintf

CUDA sample中0_Introduction里包含CUDA基础的sample,simplePrintf展示了如何在device代码里使用printf。

// System includes
#include <stdio.h>
#include <assert.h>

// CUDA runtime
#include <cuda_runtime.h>

// helper functions and utilities to work with CUDA
#include <helper_functions.h>
#include <helper_cuda.h>

#ifndef MAX
#define MAX(a, b) (a > b ? a : b)
#endif

__global__ void testKernel(int val) {
  printf("[%d, %d]:\t\tValue is:%d\n", blockIdx.y * gridDim.x + blockIdx.x,
         threadIdx.z * blockDim.x * blockDim.y + threadIdx.y * blockDim.x +
             threadIdx.x,
         val);
}

int main(int argc, char **argv) {
  int devID;
  cudaDeviceProp props;

  // This will pick the best possible CUDA capable device
  devID = findCudaDevice(argc, (const char **)argv);

  // Get GPU information
  checkCudaErrors(cudaGetDevice(&devID));
  checkCudaErrors(cudaGetDeviceProperties(&props, devID));
  printf("Device %d: \"%s\" with Compute %d.%d capability\n", devID, props.name,
         props.major, props.minor);

  printf("printf() is called. Output:\n\n");

  // Kernel configuration, where a two-dimensional grid and
  // three-dimensional blocks are configured.
  dim3 dimGrid(2, 2);
  dim3 dimBlock(2, 2, 2);
  testKernel<<<dimGrid, dimBlock>>>(10);
  cudaDeviceSynchronize();

  return EXIT_SUCCESS;
}

代码概述:

  1. MAX Macro:

    • 定义一个MAX宏,用于返回两个数字中的最大值。
  2. testKernel() 函数:

    • 这是一个CUDA内核函数,在GPU上并行执行。
    • 它接受一个整数参数val,并打印出当前线程的坐标和该值。
  3. main() 函数:

    • 首先找到最合适的CUDA设备。
    • 获取该设备的属性,如名称、计算能力等。
    • 打印一条消息,表示即将调用printf()
    • 配置CUDA内核的网格和块的维度:
      • 2x2的2D网格
      • 2x2x2的3D块
    • 启动testKernel()内核,并传入值10。
    • 等待内核执行完成。
    • 最后返回成功退出状态。

CUDA  相关API解读

 该Sample使用的CUDA API:  cudaDeviceSynchronize

这个API属于CUDA runtime API。

显示同步

在 CUDA 编程中如何显式地同步不同的流(stream),有以下方法:

  1. cudaDeviceSynchronize():

    • 该函数会等待所有主机线程中的所有流中的所有前置命令都完成执行。
    • 它可以用于在主机端等待所有 CUDA 操作完成。
  2. cudaStreamSynchronize():

    • 该函数接受一个流(stream)作为参数,并等待给定流中的所有前置命令都完成执行。
    • 它可以用于让主机端同步特定的流,同时允许其他流在设备上继续执行。
  3. cudaStreamWaitEvent():

    • 该函数接受一个流和一个事件(event)作为参数(事件的描述见"事件"部分)。
    • 它会让添加到给定流中的所有命令延迟执行,直到指定的事件完成。
    • 这可以用于同步流与事件的执行。
  4. cudaStreamQuery():

    • 该函数为应用程序提供了一种方式,用于查询给定流中的所有前置命令是否都已完成。
    • 它可以用于检查流的执行状态。

总的来说,这些函数提供了多种方式来显式地同步 CUDA 编程中的流,以满足不同的需求。合理使用它们可以帮助开发人员更好地控制 CUDA 应用程序的并行执行。

Kernel解读

它接受一个整数参数val,并打印出当前线程的坐标和该值val。

Main函数

findCudaDevice是一个inline function,可以获取device ID,cudaGetDeviceProperties是一个runtime API,主要是返回CUDA device的信息,包括卡信息和compute capability。

这些代码定义了CUDA内核的网格和块的配置。网格由4个块(2*2)组成,每个块由8个(2*2*2)线程组成。

  dim3 dimGrid(2, 2);
  dim3 dimBlock(2, 2, 2);

然后调用kernel函数。

最后进行device同步。

运行结果:

运行时间单位是毫秒

GPU Device 0: "Ada" with compute capability 8.9

Device 0: "NVIDIA GeForce RTX 4080" with Compute 8.9 capability
printf() is called. Output:

[1, 0]:         Value is:10
[1, 1]:         Value is:10
[1, 2]:         Value is:10
[1, 3]:         Value is:10
[1, 4]:         Value is:10
[1, 5]:         Value is:10
[1, 6]:         Value is:10
[1, 7]:         Value is:10
[0, 0]:         Value is:10
[0, 1]:         Value is:10
[0, 2]:         Value is:10
[0, 3]:         Value is:10
[0, 4]:         Value is:10
[0, 5]:         Value is:10
[0, 6]:         Value is:10
[0, 7]:         Value is:10
[2, 0]:         Value is:10
[2, 1]:         Value is:10
[2, 2]:         Value is:10
[2, 3]:         Value is:10
[2, 4]:         Value is:10
[2, 5]:         Value is:10
[2, 6]:         Value is:10
[2, 7]:         Value is:10
[3, 0]:         Value is:10
[3, 1]:         Value is:10
[3, 2]:         Value is:10
[3, 3]:         Value is:10
[3, 4]:         Value is:10
[3, 5]:         Value is:10
[3, 6]:         Value is:10
[3, 7]:         Value is:10

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值