CUDA计时

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;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值