当前位置: 首页 > news >正文

调试 cuda kernel

        调试 CUDA Kernel 并进入 __device__ 函数是 CUDA 开发中一项非常重要的技能。这主要依赖于 NVIDIA 的官方调试器 NVIDIA Nsight Systems (用于系统级分析) 和 NVIDIA Nsight Compute (用于内核级分析) 以及经典的 cuda-gdb (命令行调试器)。

这里将重点介绍两种最常用和强大的方法:使用 Nsight Visual Studio Code Edition (图形化界面,推荐) 和 cuda-gdb (命令行)。

 

方法一:使用 Nsight VSCode Edition (图形化界面,最推荐)

        Nsight for VSCode 提供了类似于调试 CPU 代码的直观体验,是当前调试 CUDA 的首选工具。

前提条件
  1. 安装 NVIDIA 驱动和 CUDA Toolkit: 确保你的系统安装了正确版本的驱动和 CUDA。

  2. 安装 VSCode: 从 VSCode 官网 下载并安装。

  3. 安装 Nsight VSCode 插件: 在 VSCode 的扩展市场中搜索 “NVIDIA Nsight” 并安装。

  4. 确保你的代码是可调试的: 在编译你的 CUDA 代码时,必须使用 -G 或 -lineinfo 标志来生成调试信息。

    • -G: 生成完整的调试信息,但会严重禁用所有编译器优化,极大影响性能,仅用于调试。

    • -lineinfo (--generate-line-info): 生成行号信息,允许调试和性能分析,但对性能影响较小,是 Nsight Compute 性能分析的首选。对于调试 __device__ 函数,-lineinfo 通常就足够了。

    示例编译命令:

    nvcc -g -G -o my_program my_program.cu # 使用 -g -G 进行完整调试
    # 或者
    nvcc --device-debug -o my_program my_program.cu # CUDA 11.2+ 推荐方式,等同于 -g -G
    # 或者 (如果主要为了分析,附带一些调试能力)
    nvcc -lineinfo -o my_program my_program.cu
调试步骤
  1. 打开项目: 在 VSCode 中打开你的 CUDA 项目文件夹。

  2. 创建调试配置文件:

    • 点击侧边栏的 “运行和调试” 图标 (或 Ctrl+Shift+D)。

    • 点击 “create a launch.json file”。

    • 在弹出的环境选择中,选择 CUDA C++

    • 这会在项目下生成一个 .vscode/launch.json 文件。

  3. 配置 launch.json:

    • 一个基本的配置如下。关键是指定正确的程序路径和 cuda-gdb 路径。

    {"version": "0.2.0","configurations": [{"name": "CUDA C++: Launch","type": "cuda-gdb","request": "launch","program": "${workspaceFolder}/my_program", // 你的可执行文件路径"stopAtEntry": false, // 设为 true 会在 main 函数入口处暂停"cwd": "${workspaceFolder}","args": [], // 传递给程序的命令行参数"environment": [], // 环境变量"externalConsole": false}]
    }
  4. 设置断点:

    • 在你的 CUDA 源码 (.cu 或 .cuh 文件) 中,在你想要中断的行的左侧空白处点击。

    • 你可以在 main 函数、<<<...>>> 调用的 kernel 函数、以及任何 __device__ 函数中设置断点。

  5. 开始调试:

    • 选择刚刚创建的 “CUDA C++: Launch” 配置。

    • 按 F5 或点击绿色的 “开始调试” 按钮。

    • 程序开始运行,并在遇到你设置的断点时暂停。

  6. 步入 __device__ 函数:

    • 当程序在 kernel 的某一行暂停时,你可以使用调试控制栏的按钮:

      • Step Into (F11): 如果当前行调用了某个 __device__ 函数,按 F11 会进入该 __device__ 函数的函数体

      • Step Over (F10): 执行当前行,但不进入函数内部。

      • Step Out (Shift+F11): 执行完当前函数,返回到调用它的地方。

  7. 查看变量和调用堆栈:

    • 在调试过程中,你可以在 VSCode 的左侧面板查看变量的当前值。

    • 调用堆栈 面板会显示你当前的执行位置,从 main 到 kernel 再到 __device__ 函数,清晰明了。

    • 你还可以将鼠标悬停在源码中的变量上来查看其值。

 

方法二:使用 cuda-gdb (命令行)

        但其实我们更习惯命令行操作,或者在没有图形界面的远程服务器上工作,cuda-gdb 是强大的选择。

前提条件

          同样,编译时必须使用 -G 或 -lineinfo 标志。

nvcc -g -G -o my_program my_program.cu

例如: nvcc -g -G --gpu-architecture=sm_120  sgemm_1.cu -o sgemm_1 -I ../cutlass/include/ -I ../cutlass/tools/util/include -I /usr/local/cuda/include

调试步骤
  1. 启动调试器:

    cuda-gdb ./my_program
  2. 设置断点:

    • 在 kernel 函数处设置断点:

      (cuda-gdb) break my_kernel_function
    • 在 __device__ 函数处设置断点:

      (cuda-gdb) break my_device_function
    • 在特定行设置断点:

      (cuda-gdb) break file.cu:123
  3. 运行程序:

    (cuda-gdb) run

    程序会开始执行,并在第一个断点处停止。

  4. 控制执行和步入 __device__ 函数:

    • next (n): Step Over,执行下一行。

    • step (s): Step Into,进入函数。如果下一行是 __device__ 函数调用,这会进入该 __device__ 函数体

    • continue (c): 继续运行直到下一个断点。

    • finish: Step Out,运行到当前函数返回。

  5. 检查线程和变量:

    • CUDA 调试的核心是理解线程。你可以切换当前关注的线程:

      (cuda-gdb) cuda thread 1  # 切换到 block 0, thread 0
      (cuda-gdb) cuda thread (1, 2, 3)  # 切换到 blockIdx(1,2), threadIdx(3)
    • 打印变量值:

      (cuda-gdb) print variable_name
  6. 退出:

    (cuda-gdb) quit
     

重要提示和常见问题

  1. 硬件兼容性: 并非所有 NVIDIA GPU 都支持调试功能。请查阅 NVIDIA 文档 确认你的 GPU 是否支持 “TCC 模式” 或 “Compute Preemption”,这对于调试至关重要。消费级显卡 (GeForce) 的调试支持可能不如专业卡 (Tesla, Quadro) 完善。

  2. 性能影响: 使用 -G 编译会极大降低 kernel 运行速度,并且调试本身也会引入开销。这是正常的,目的是为了获得精确的调试状态。

  3. 焦点线程: 在 CUDA 调试中,任何时候你都只在一个特定的 GPU 线程上下文中查看变量和执行代码。确保你正在检查你感兴趣的线程。

  4. Nsight vs cuda-gdbNsight VSCode 底层调用的也是 cuda-gdb,但它提供了无比友好的图形界面,极大地简化了操作,强烈推荐初学者和绝大多数开发者使用。

总结:要调试并进入 __device__ 函数,只需 1) 用 -G 编译2) 在 Nsight VSCode 或 cuda-gdb 中设置断点3) 使用 Step Into (F11 / step) 命令即可。


文章转载自:

http://zFoVK90i.kLcdt.cn
http://ywJVBvMz.kLcdt.cn
http://pAyT31Uy.kLcdt.cn
http://PVyPR7YD.kLcdt.cn
http://jJPTyNO7.kLcdt.cn
http://uxk73kus.kLcdt.cn
http://qZSL0i8C.kLcdt.cn
http://UGxlZSr9.kLcdt.cn
http://5YYUASOL.kLcdt.cn
http://b0vj9yDY.kLcdt.cn
http://jIAq58iB.kLcdt.cn
http://4Zm6YrqG.kLcdt.cn
http://T5doy5Xc.kLcdt.cn
http://GNYbRSh2.kLcdt.cn
http://P1hfKiv8.kLcdt.cn
http://ChkSf4mB.kLcdt.cn
http://OtHKpb4i.kLcdt.cn
http://yM2zQMcV.kLcdt.cn
http://DLaPK4dk.kLcdt.cn
http://tCFYjQLC.kLcdt.cn
http://BzFdcm94.kLcdt.cn
http://KnzTu9Aw.kLcdt.cn
http://yODpZ2CG.kLcdt.cn
http://5L8qf41C.kLcdt.cn
http://A5aGSLUR.kLcdt.cn
http://rCdwWkv4.kLcdt.cn
http://PSRIhjnt.kLcdt.cn
http://jaXmHJAZ.kLcdt.cn
http://SxTAbkfH.kLcdt.cn
http://Tsh8jyUG.kLcdt.cn
http://www.dtcms.com/a/372618.html

相关文章:

  • OpenLayers常用控件 -- 章节九:比例尺控件教程
  • 李沐深度学习论文精读(一)AlexNet + ResNet
  • CMake构建C++项目,报错“CMake Error CMAKE_C_COMPILER not set, after EnableLanguage”
  • 2025最新超详细FreeRTOS入门教程:第五章 FreeRTOS信号量
  • 安卓逆向(二)相关问题及解决方案
  • 自学嵌入式第37天:MQTT协议
  • daily notes[11]
  • Qt中QProxyStyledrawControl函数4个参数的意义
  • AutoHotkey识别图片
  • 【数学建模】在烟雾导弹遮蔽模型中的实际参考文献
  • 快速了解word2vec模型
  • 关于高并发的一连串问题分析(未完成)
  • Ansible Playbook 核心配置实操指南:主机清单引用、并行执行与模块化组织
  • 2025年金融专业人士职业认证发展路径分析
  • NVM 使用指南(Node Version Manager)
  • 2025年体制内职业发展相关认证选择指南
  • 电脑提速之关于Edge优化
  • 图像纹理相似度评价——Gabor变换
  • [光学原理与应用-463]:波动光学 - AOM的0级光与1级光
  • SpringBoot 公共字段自动填充
  • 《计算》第一二章读书笔记
  • 多模态大模型---第1节
  • 删除字符串中的空格
  • STM32 开发(三十三)STM32F103 片内资源 —— 直接存储 DMA 实战 编码详解
  • MGSM:大模型多语言数学推理的“试金石”
  • 卫星直连服务:从稀疏星座到全球覆盖的未来通信革命
  • FastAPI:像搭建餐厅一样设计API
  • 基于CNN-SE Attention和SHAP可解释性分析的故障诊断matlab
  • 企业级 Django 日志配置示例
  • URL 重写机制深度解析