CUDA计时

本文详细介绍了CUDA中CPU与GPU的异步并发和同步机制。CUDA内核启动和内存复制可以异步进行,允许CPU与GPU并发执行任务。同步通过共享的同步位置和CUDA事件实现,包括非阻塞和阻塞同步方式,以高效管理计算流程。此外,还展示了如何使用CUDA事件记录和计算执行时间,并提供了一个简单的`Timing`类实现计时功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CPU和GPU异步并发

  CUDA内核程序的所有启动都是异步的,CPU通过将命令写入命令缓冲区,来请求启动内核,然后直接返回结果,而不检查GPU的执行进度。内存复制也可以选择异步方式,这使CPU和GPU可以并发执行,也使内存复制和内核处理可以并发执行。

CPU和GPU同步

  在CUDA程序中,CPU端将命令写到命令缓冲区中,GPU端会依次读取命令缓冲区并执行任务,一般的程序中,GPU需要给CPU汇报任务的工作进度。命令缓冲区和“同步信息位置”都位于锁页主机内存上,所以CPU和GPU都能同时读写这些数据。在这个“同步信息位置”的内存上,会设置一个单调递增的整数值(“进度值”),GPU完成一条命令操作之后,就会更新递增这个“同步值”,CPU读取这个“同步值”,就可以知道GPU的工作进度。
  “CUDA事件”可以反映这种硬件能力,cudaEventRecord()函数的作用是将一个命令加入队列,使一个新的同步值写入共享同步位置中,cudaEventQuery()和cudaEventSynchronize()则分别用于检查和等待这个事件的同步值。
  早期的CUDA只是简单地轮询共享的同步位置,反复地读取内存,直到等待条件满足为止,但是这种方法的代价比较大。后面有了更好的“阻塞同步”的方案,是CPU等待线程挂起,直到GPU发出中断信号为止。驱动程序将GPU中断映射到一个特定的线程同步原语平台,如Win32事件或Linux的信号,当应用程序开始等待时,若等待条件不成立,这样做可以挂起CPU的线程。
  通过指定CU_EVENT_BLOCKING_SYNC到cuEventCreate(),或者指定cudaEventBlockingSync到cudaEventCreate(),可以使用阻塞的CUDA事件。

CPU端打印GPU任务的计时信息

  主机接口有一个机载高分辨率计时器,它可以在写入一个32位的同步值时,同时写一个时间戳,CUDA使用这个硬件设施实现CUDA事件中的异步计时功能。

// 创建CUDA事件,用以记录时间戳
cudaEvent_t start, stop;
float elapsedTime;
cudaEventCreate(&start);
cudaEventCreate(&stop);

// 记录开始时刻的时间戳
cudaEventRecord(start, 0);
// Do Something

// ...

// 记录结束时刻的时间戳
cudaEventRecord(stop, 0);
// 等待事件同步值
cudaEventSynchronize(stop);

// 根据开始和结束时刻的时间戳,计算其中所经过的时间
cudaEventElapsedTime(&elapsedTime, start, stop);
// 打印时间
printf("Time to generate: %3.2f ms\n", elapsedTime/float(iterNum));

// 销毁CUDA事件
cudaEventDestroy(start);
cudaEventDestroy(stop);
将上述过程封装成类

类的头文件

#pragma once
#ifndef _CUDA_LIB_H_
#define _CUDA_LIB_H_
#ifdef __cplusplus
extern "C++"{
#endif // __cplusplus

#include <cuda.h>
#include <cuda_runtime.h>
#include <cuda_gl_interop.h>
#include <device_launch_parameters.h>
#include <iostream>


class Timing{
public:
    cudaEvent_t start, stop;
    float elapsedTime;
    Timing();
    void tic();
    void toc();
    ~Timing();
};

#ifdef __cplusplus
};
#endif // __cplusplus
#endif // _CUDA_LIB_H_

类的源文件

#ifdef __cplusplus
extern "C++"{
#endif // __cplusplus

#include "cudaLib.h"

Timing::Timing(){
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
}
void Timing::tic(){
    // 记录开始时刻的时间戳
    cudaEventRecord(start, 0);
}
void Timing::toc(){
    // 记录结束时刻的时间戳
    cudaEventRecord(stop, 0);
    // 等待事件同步值
    cudaEventSynchronize(stop);
    // 根据开始和结束时刻的时间戳,计算其中所经过的时间
    cudaEventElapsedTime(&elapsedTime, start, stop);
    // 打印时间
    printf("Time to generate: %3.2f ms\n", elapsedTime);
}
Timing::~Timing(){
    // 销毁CUDA事件
    cudaEventDestroy(start);
    cudaEventDestroy(stop);
}

#ifdef __cplusplus
};
#endif // __cplusplus

主函数调用

#include "cudaLib.h"
int main(void){
    Timing t = Timing();
    t.tic();
    // Do Something
    t.toc();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值