详解如何在C/C++中测量一个函数或功能的运行时间

 更新时间:2023年12月03日 09:31:34   作者:zhonguncle  
本文算是一个比较完整的关于在 C/C++ 中测量一个函数或者功能的总结,最后会演示三种方法的对比,文章通过代码示例给大家介绍的非常详细,需要的朋友可以参考下

最常用的clock()

最常用的测量方法是使用clock()来记录两个 CPU 时间点clock_t,然后做差。这个方法的好处在于非常简单易写,如下(第一行是为说明需要导入哪个库):

#include <time.h>
.....

	clock_t begin = clock();

    ...需要被测量的代码
    
    clock_t end = clock();
    int duration = (end - begin)/CLOCKS_PER_SEC;

需要注意 3 点:

  1. CLOCKS_PER_SEC在 macOS 上是 1000000,也就是说(end - begin)的单位是微秒,所以要除以CLOCKS_PER_SEC
  2. 不同平台的clock_t类型是不一样的,有些平台是整数型,有些是使用浮点型。如果是浮点型的话,CLOCKS_PER_SEC或许可以不用写,还是要看time.h的相关内容。
  3. 这个方法中的“clock”一词表示的是时钟频率,而不是时间。早期的计算机是固定频率的(现在的一些计算器或者单片机其实也是固定频率的),这个方法就是诞生于那个时间的。

这种方法最大的弊端就是它测量是 CPU 运行时间,准确的说是该进程使用 CPU 的时间。这就导致了对于非 CPU 密集型程序来说,这个结果可能不是那么精确。当然导致的最大的问题是并行计算程序得到的时间完全不对,而且不能简单地使用核心数计算得到正确的时间。

因为这个方法是将多个 CPU 的运行时间加在一起了,串行计算的程序完全没有问题,但是并行计算的话,CPU 使用率一般不会达到或接近核心数*100%,因为计算机上还有其他任务也需要 CPU。比如说如果串行计算的程序使用率一般在 99% 左右,获取时间为 30 秒,但是对于 6 核的设备上运行的并行计算程序的话,CPU 使用率达到 570% 就很不错了,获取的时间可能为 27 秒,而实际上只用了 5 秒。

这是我在使用 ISPC 编写并行计算程序的时候发现的,所以我想寻找到新的方案,于是我发现了下一个方法。

timespec

timespec是一个简单的日历时间或者时间流逝。通过使用日历时间可以解决上一节中无法测量并行程序的实际运行时间的问题。但是“简单”这点的表现为整数时间,也就是说最小的时间精度是秒,而不是上一种方法中的微秒,不过这对于复杂函数或程序的测试来说没啥问题,毕竟 30 分钟和 31 分钟的性能差距不过 3.22%。

方法如下(第一行是为说明需要导入哪个库):

#include <time.h>
	time_t begin = time(NULL);
	
	...需要被测量的代码
    
    time_t end = time(NULL);
    int duration = (end - begin);

可以看到比上一种还要简单。

但是对于一些小型的测试来说,这个方法又不太行,因为整数带来的误差太大了,比如说 0.6 秒是 1.8 秒性能的三倍,但是在整数上只为 2 倍甚至是 1 倍(为什么有这个“甚至”等会演示可以看到),所以还是需要一个更精确时间测量方法,这个方法不光要适应并行计算,还要有一定的精度。

clock_gettime()

clock_gettime()可以完美的符合要求,但是使用上有点复杂。

clock_gettime()是我从文档的下面发现的。一开始我找到的是gettimeofday(),然后我去看了一下 IEEE 标准的文档gettimeofday (opengroup.org),发现在“FUTURE DIRECTIONS(未来方向)”这一栏表示gettimeofday()可能未来会被废弃;在“APPLICATION USAGE(应用使用)”这一栏表示应用应该使用clock_gettime()而不是gettimeofday。这必须得使用clock_gettime()了。

clock_gettime()的复杂之处在于太精确了。先来看看使用方法(第一行是为说明需要导入哪个库):

#include <time.h>
	struct timespec start;
    clock_gettime(CLOCK_REALTIME, &start);
	
	...需要被测量的代码
    
    struct timespec end;
    clock_gettime(CLOCK_REALTIME, &end);
    
	double duration = (double)(end.tv_nsec-start.tv_nsec)/((double) 1e9) + (double)(end.tv_sec-start.tv_sec);

clock_gettime()的参数CLOCK_REALTIME表示系统层面的实时时间;这个地方还可以用CLOCK_MONOTONIC,这个值是从系统启动开始一直运行的,一直连续的不跳跃的(除非手动改了),这个要比CLOCK_REALTIME精度小一些,所以更快一些。

可以看到计算运行时间的代码,也就是时间差的表达式长了很多,是因为clock_gettime()获取的时间分为两部分:秒和纳秒(在某论坛上有人指出在曾经的 Mac OS X 上这里是微秒,不确定,不过现在也是纳秒了)。秒是int很简单的,但是纳秒用的是long int,这就涉及到转换的问题了。所以就需要分别计算两个部分,转换合成。

实际演示(三种方法的对比)

这里展示一段并行计算程序在三种测量时间方法下的对比,各位可以看看差别(可以推测出测试设备是 6C6T 的 CPU 哦):

可以看到有时差别还是挺大的。

以上就是详解如何在C/C++中测量一个函数或者功能的运行时间的详细内容,更多关于在C/C++中测量函数运行时间的资料请关注脚本之家其它相关文章!

相关文章

  • C++读取文件的四种方式总结

    C++读取文件的四种方式总结

    C++可以根据不同的目的来选取文件的读取方式,C++中有四种常见的读取方式,本文主要介绍了这四种方法的具体实现,需要的可以参考一下
    2023-04-04
  • 基于C语言实现见缝插针游戏的示例代码

    基于C语言实现见缝插针游戏的示例代码

    见缝插针游戏就是使用鼠标左键点击发射针,当两个针的夹角小于一定限制时,游戏结束。本文将用C语言实现这一有趣游戏,感兴趣的可以了解一下
    2022-11-11
  • C语言中大小端问题实例探索解决方法

    C语言中大小端问题实例探索解决方法

    这篇文章主要介绍了C语言中大小端问题实例,总的来说这并不是一道难题,那为什么要拿出这道题介绍?拿出这道题真正想要传达的是解题的思路,以及不断优化探寻最优解的过程。希望通过这道题能给你带来一种解题优化的思路
    2023-02-02
  • C语言超详细讲解指针的使用

    C语言超详细讲解指针的使用

    C语言这门课程在计算机的基础教学中一直占有比较重要的地位,然而要想突破C语言的学习,对指针的掌握是非常重要的,本文将具体针对指针的基础做详尽的介绍
    2022-05-05
  • c/c++拷贝构造函数和关键字explicit详解

    c/c++拷贝构造函数和关键字explicit详解

    这篇文章主要介绍了c/c++拷贝构造函数和关键字explicit的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • C语言编写洗牌发牌程序

    C语言编写洗牌发牌程序

    这篇文章主要为大家详细介绍了C语言编写洗牌发牌程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • C++逐步介绍日期类的使用

    C++逐步介绍日期类的使用

    下面小编就为大家带来一篇C++实现日期类(Date类)的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2022-07-07
  • C++详解如何实现单链表

    C++详解如何实现单链表

    线性表的链式存储又称为单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。本文将用C++实现单链表,需要的可以参考一下
    2022-06-06
  • C语言深入探究自定义类型之结构体与枚举及联合

    C语言深入探究自定义类型之结构体与枚举及联合

    今天我们来学习一下自定义类型,自定义类型包括结构体、枚举、联合体,小编觉得挺不错的,现在就分享给大家,也给大家做个参考
    2022-05-05
  • win10中的dlib库安装过程

    win10中的dlib库安装过程

    这篇文章主要介绍了win10中dlib库的安装过程,本文通过实例图文介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03

最新评论