使用cupti拦截多并发kernel launch

使用cupti拦截多并发kernel launch

具体项目地址:https://github.com/Dylan887/CUDA/tree/main/intercept_launch

拦截原理

原理
拦截 CUDA 内核(kernel)执行的原理基于 CUPTI(CUDA Profiling Tools Interface)提供的回调机制。通过 CUPTI 提供的回调机制,开发者可以在内核执行之前和之后插入自定义代码,这就是所谓的拦截内核执行。其核心思想是通过注册回调函数,在 CUDA Driver API 或 Runtime API 函数调用时,捕获这些函数的执行时机,进而对 CUDA 内核启动进行拦截或监控。

本文的并发采取的是多流模式(在所有核函数使用同一个流也可以)
回调函数将拦截到的核函数指针指向null,所以核函数无法正常启动,批量释放的时候,重新获取原函数指针,所用的流也是原函数的流

流程

1. 注册回调函数

通过 cuptiSubscribe() 函数,开发者可以注册一个回调函数,该函数会在 CUDA 内核启动时被调用,监控cuda程序的行为。注册时,需要指定回调函数的域(domain),比如 CUPTI_CB_DOMAIN_DRIVER_API 表示 CUDA Driver API,或者 CUPTI_CB_DOMAIN_RUNTIME_API 表示 CUDA Runtime API。
CUDA Runtime API(运行时 API):

  • 更高层次的抽象,更易于使用。
  • 适合大多数开发者,提供了一些默认配置,简化了 CUDA 编程的难度。
  • 通常用于与 CUDA 驱动层打交道较少的场景,例如标准的 CUDA 程序编写。
  • 需要 CUDA 库(libcudart.so)的支持。

CUDA Driver API(驱动 API):

  • 低层次的 API,更接近硬件,提供了更高的灵活性和控制。
  • 对比 Runtime API 更复杂,但适合那些需要对设备和内存管理进行更细粒度控制的场景。
  • 不需要 CUDA 运行时库的支持,可以直接与 CUDA 驱动打交道。

本文监控的是CUDA driver API,检测cuda runtime API 时拦截不成功

2.启用回调功能

使用 cuptiEnableCallback() 启用对特定 CUDA API 的回调,例如 cuLaunchKernelcudaLaunchKernel。当这些 API 被调用时,CUPTI 会执行事先注册的回调函数。

cuptiEnableCallback(1, subscriber, CUPTI_CB_DOMAIN_DRIVER_API, CUPTI_DRIVER_TRACE_CBID_cuLaunchKernel);
3. 实现回调函数

回调函数的实现是拦截 CUDA 内核的核心。在回调函数中,可以访问即将启动的内核的参数。通过修改这些参数,可以控制内核的执行。

  • 获取内核参数:通过 cbInfo->functionParams 可以获取内核的启动参数,例如网格维度、块维度、共享内存大小等。
  • 修改内核参数:可以通过修改回调函数中的参数,来更改内核的启动行为,甚至可以通过将网格大小设置为零或将函数指针置为 NULL 来阻止内核执行。

示例代码:

void CUPTIAPI cuptiCallback(void *userdata, CUpti_CallbackDomain domain,
                            CUpti_CallbackId cbid, const CUpti_CallbackData *cbInfo) {
   
    if (domain == CUPTI_CB_DOMAIN_DRIVER_API && cbid == CUPTI_DRIVER_TRACE_CBID_cuLaunchKernel) {
   
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值