问题:对于使用GPU计算时,都想知道kernel函数运行所耗费的时间,使用CUDA内置的API可以方便准确的获得kernel运行时间。

在CPU上,可以使用clock()函数和GetTickCount()函数计时。

  clock_t start, end;

    start = clock();
  //执行步骤;
  ...... end = clock();
  printf(" time (CPU) : %f ms(毫秒) \n", end - start);
  int startTime, endTime;

    // 开始时间
startTime = GetTickCount();   //执行步骤;
  ......   endTime = GetTickCount();   cout << " 总时间为 : " << (double)(endTime - startTime)<< " ms " << endl;

对于CUDA核函数计时使用clock()或GetTickCount()函数结果不准确,计算归约求和的例子如下:

  //CPU计时
clock_t start, end;
start = clock(); d_SharedMemoryTest << < NThreadX, ThreadX >> > (S_Para, MX); //调用核函数(M个包含N个线程的线程块) cudaDeviceSynchronize();
end = clock(); clock_t time = end - start;
printf(" time (GPU) : %f ms \n", time);

结果为0.000000 ms(明显结果错误):

而使用CUDA内置API(cudaEvent_t)计时,主要代码如下

   //GPU计时
cudaEvent_t startTime, endTime;
cudaEventCreate(&startTime);
cudaEventCreate(&endTime);
cudaEventRecord(startTime, ); d_SharedMemoryTest << < NThreadX, ThreadX >> > (S_Para, MX); //调用核函数(M个包含N个线程的线程块) cudaEventRecord(endTime, );
cudaEventSynchronize(startTime);
cudaEventSynchronize(endTime); float time;
cudaEventElapsedTime(&time, startTime, endTime);
printf(" time (GPU) : %f ms \n", time); cudaEventDestroy(startTime);
cudaEventDestroy(endTime);

结果为39.848801 ms:

最后附上全部代码:

#pragma once
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "device_functions.h" #include <iostream> using namespace std;
const int NX = ; //数组长度
const int ThreadX = ;   //线程块大小 //使用shared memory和多个线程块
__global__ void d_SharedMemoryTest(double *para, int MX)
{
int i = threadIdx.x; //该线程块中线程索引
int tid = blockIdx.x * blockDim.x + threadIdx.x; //M个包含N个线程的线程块中相对应全局内存数组的索引(全局线程) __shared__ double s_Para[ThreadX]; //定义固定长度(线程块长度)的共享内存数组
if (tid < MX) //判断全局线程小于整个数组长度NX,防止数组越界
s_Para[i] = para[tid]; //将对应全局内存数组中一段元素的值赋给共享内存数组
__syncthreads(); //(红色下波浪线提示由于VS不识别,不影响运行)同步,等待所有线程把自己负责的元素载入到共享内存再执行下面代码 if (tid < MX)
{
for (int index = ; index < blockDim.x; index *= ) //归约求和 (对应256=4*4*4*4线程数)
{
__syncthreads();
if (i % ( * index) == )
{
s_Para[i] += s_Para[i + index] + s_Para[i + *index] + s_Para[i + *index];
}
}
} if (i == ) //求和完成,总和保存在共享内存数组的0号元素中
para[blockIdx.x * blockDim.x + i] = s_Para[i]; //在每个线程块中,将共享内存数组的0号元素赋给全局内存数组的对应元素,即线程块索引*线程块维度+i(blockIdx.x * blockDim.x + i) } //使用shared memory和多个线程块
void s_ParallelTest()
{
double *Para;
cudaMallocManaged((void **)&Para, sizeof(double) * NX); //统一内存寻址,CPU和GPU都可以使用 double ParaSum = ;
for (int i = ; i<NX; i++)
{
Para[i] = ;         //数组赋值
ParaSum += Para[i]; //CPU端数组累加
} cout << " CPU result = " << ParaSum << endl; //显示CPU端结果
double d_ParaSum; int Blocks = ((NX + ThreadX - ) / ThreadX);
cout << " 线程块大小 :" << ThreadX << " 线程块数量 :" << Blocks << endl; double *S_Para;
int MX = ThreadX * Blocks;
cudaMallocManaged(&S_Para, sizeof(double) * MX);
for (int i=; i<MX; i++)
{
if (i < NX)
S_Para[i] = Para[i];
} ////CPU计时
//clock_t start, end;
//start = clock(); //d_SharedMemoryTest << < Blocks, ThreadX >> > (S_Para, MX); //调用核函数(M个包含N个线程的线程块)
//
//cudaDeviceSynchronize();
//end = clock(); //clock_t time = end - start;
//printf(" time (GPU) : %f ms \n", time); //GPU计时
cudaEvent_t startTime, endTime;
cudaEventCreate(&startTime);
cudaEventCreate(&endTime);
cudaEventRecord(startTime, ); d_SharedMemoryTest << < Blocks, ThreadX >> > (S_Para, MX); //调用核函数(M个包含N个线程的线程块) cudaEventRecord(endTime, );
cudaEventSynchronize(startTime);
cudaEventSynchronize(endTime); float time;
cudaEventElapsedTime(&time, startTime, endTime);
printf(" time (GPU) : %f ms \n", time); cudaEventDestroy(startTime);
cudaEventDestroy(endTime); for (int i=; i<Blocks; i++)
{
d_ParaSum += S_Para[i*ThreadX]; //将每个线程块相加求的和(保存在对应全局内存数组中)相加求和
} cout << " GPU result = " << d_ParaSum << endl; //显示GPU端结果 } int main() { s_ParallelTest(); system("pause");
return ;
}

CUDA学习(七)之使用CUDA内置API计时的更多相关文章

  1. Python基础学习参考(三):内置函数

    一:内置函数 在第一篇文章中,我们简单的认识了一下print()函数和input()函数,也就是输入和输出,这些函数我们可以直接的调用,不要自己定义或者引入什么,对吧?想这样的函数就叫做内置函数.这里 ...

  2. 前端MVC学习总结(三)——AngularJS服务、路由、内置API、jQueryLite

    一.服务 AngularJS功能最基本的组件之一是服务(Service).服务为你的应用提供基于任务的功能.服务可以被视为重复使用的执行一个或多个相关任务的代码块. AngularJS服务是单例对象, ...

  3. 前端MVC学习笔记(三)——AngularJS服务、路由、内置API、jQueryLite

    一.服务 AngularJS功能最基本的组件之一是服务(Service).服务为你的应用提供基于任务的功能.服务可以被视为重复使用的执行一个或多个相关任务的代码块. AngularJS服务是单例对象, ...

  4. 学习angularjs的内置API函数

    angularjs的内置API函数有很多,如isString()判断给定的对象是否为字符串,如果是返回 true,反之返回false:isNumber()判断给定的对象是否为数字,如果是返回 true ...

  5. ruby -- 基础学习(七)时间的内置函数和格式说明

        Rails -- 时间的内置函数和格式说明 FROM:http://www.douban.com/note/99064603/ time = Time.now #获得当前时间 time.gmt ...

  6. Python基础学习笔记(七)常用元组内置函数

    参考资料: 1. <Python基础教程> 2. http://www.runoob.com/python/python-tuples.html 3. http://www.liaoxue ...

  7. Python学习day07 - Python进阶(1) 内置方法

    figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...

  8. AngularJS学习笔记(四)内置指令

    说说指令 不得不赞叹,指令是ng最为强大的功能之一,好吧,也可以去掉之一,是最强大的功能.ng内置了许多自定义的指令,这避免了我们自己去造轮子.同时,ng也提供了自定义指令的功能,可以让我们的页面元素 ...

  9. Python学习(五)函数 —— 内置函数 lambda filter map reduce

    Python 内置函数 lambda.filter.map.reduce Python 内置了一些比较特殊且实用的函数,使用这些能使你的代码简洁而易读. 下面对 Python 的 lambda.fil ...

随机推荐

  1. DEVOPS技术实践_23:判断文件下载成功作为执行条件

    在实际生产中,我们经常会需要通过判断一个结果作为一个条件去执行另一个内容,比如判断一个文件是否存在,判官一个命令是否执行成功等等 现在我们选择其中一个场景进行实验,当某个目录下存在,则执行操作 1. ...

  2. asp.net保留两位小数

    1.System.Globalization.NumberFormatInfo provider = new System.Globalization.NumberFormatInfo();provi ...

  3. Java 从入门到进阶之路(二十)

    在之前的文章我们介绍了一下 Java 中的包装类,本章我们来看一下 Java 中的日期操作. 在我们日常编程中,日期使我们非常常用的一个操作,比如读写日期,输出日志等,那接下来我们就看一下 Java ...

  4. 【小技巧】object上显示div

    这个现在不大常用了,就是object在页面中显示的优先级最高,其他层想覆盖在其上面,设置的z-index再高都不管用,解决办法是在层中加一个iframe.不多说了,直接记录下代码吧,估计以后用到的机率 ...

  5. 【题解】P4091 [HEOI2016/TJOI2016]求和

    [题解]P4091 [HEOI2016/TJOI2016]求和 [P4091 HEOI2016/TJOI2016]求和 可以知道\(i,j\)从\(0\)开始是可以的,因为这个时候等于\(0\).这种 ...

  6. $HDOJ5542\ The\ Battle\ of\ Chibi$ 数据结构优化$DP$

    $AcWing$ $Description$ $Sol$ 首先显然是是以严格递增子序列的长度为阶段,由于要单调递增,所以还要记录最后一位的数值 $F[i][j]$表示前$i$个数中以$A_i$结尾的长 ...

  7. 「Main」

    这里就是我的小主页辣. My Introduction I am Louch. 姓名:楼翰诚 性别:汉纸 生日:2004/03/09(和加加林同一天呢QAQ) 星座:双鱼座 学校:义乌中学 QQ:10 ...

  8. 1046 划拳 (15 分)C语言

    划拳是古老中国酒文化的一个有趣的组成部分.酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字.如果谁比划出的数字正好等于两人喊出的数字之和,谁就赢了,输家罚一杯酒.两人同赢或两人同输 ...

  9. Linux下离线安装gdb及常用命令汇总

    以redhat6.5虚拟机作为例子,由于工作性质,大部分情况linux的软件安装,是采用离线方式的. 1.离线安装gdb 像gcc.g++或者gdb这种常用的工具软件,一般虚拟机都会安装的,如未安装, ...

  10. html 拨打电话

    其实就一行 你们别想太复杂 直接在手机中访问 点击a标签(如果你在pc端我就没话说了) <a href="tel:13999999999"></a>