如何在C/C++中测量一个函数或者功能的运行时间(串行和并行,以及三种方法的实际情况对比)

本文算是一个比较完整的关于在 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 标准的文档 https://pubs.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html,发现在“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 哦):

请添加图片描述

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

参考

21.2 Time Types - GNU

21.4 Processor And CPU Time - GNU

clock_gettime(3) — Linux manual page

What is the proper way to use clock_gettime()? - stack overflow

clock_getres, clock_gettime, clock_settime - clock and timer functions - IEEE

希望能帮到有需要的人~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/238279.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于相关性的四种机器学习聚类方法

在这篇文章中&#xff0c;基于20家公司的股票价格时间序列数据。根据股票价格之间的相关性&#xff0c;看一下对这些公司进行分类的四种不同方式。 苹果&#xff08;AAPL&#xff09;&#xff0c;亚马逊&#xff08;AMZN&#xff09;&#xff0c;Facebook&#xff08;META&…

【技术分享】RK356X Android11 以太网共享4G网络

本文基于IDO-SBC3566-V1B Android11系统实现开机后以太网自动共享4G网络功能。 IDO-SBC3566基于瑞芯微RK3566研发的一款高性能低功耗的智能主板&#xff0c;采用四核A55,主频高达1.8GHz&#xff0c;专为个人移动互联网设备和AIOT设备而设计&#xff0c;内置了多种功能强大的嵌…

TZOJ 1379 C语言合法标识符

答案&#xff1a; #include <stdio.h> #include <string.h> int main() {char arr[60];int n 0, i 0, num 0, flag;scanf("%d", &n);getchar(); //读取回车键while (n--) //循环N次{gets(arr);num strlen(arr); //num为字符串长度flag 1; …

ChatGPT 问世一周年之际,开源大模型能否迎头赶上?

就在11月30日&#xff0c;ChatGPT 迎来了它的问世一周年&#xff0c;这个来自 OpenAI 的强大AI在过去一年里取得了巨大的发展&#xff0c;迅速吸引各个领域的用户群体。 我们首先回忆一下 OpenAI和ChatGPT这一年的大事记&#xff08;表格由ChatGPT辅助生成&#xff09;&#x…

福德植保无人以科技为动力,推动农业可持续发展

福德植保无人机&#xff1a;高效、精准、环保的农业解决方案 福德植保无人机&#xff0c;凭借先进的技术和卓越的性能&#xff0c;为农业领域带来前所未有的变革。通过高效、精准、环保的作业方式&#xff0c;为您的农业生产提供全方位的保障。 福德无人机工厂&#xff1a;引领…

【概率统计】如何理解概率密度函数及核密度估计

文章目录 概念回顾浅析概率密度函数概率值为0&#xff1f;PDF值大于1&#xff1f;一个栗子 核密度估计如何理解核密度估计核密度估计的应用 总结 概念回顾 直方图&#xff08;Histogram&#xff09;&#xff1a;直方图是最直观的一种方法&#xff0c;它通过把数据划分为若干个区…

uniapp-从后台返回的一串地址信息上,提取省市区进行赋值

1.这是接口返回的地址信息 2.要实现的效果 3.实现代码&#xff1a; <view class"address">{{item.address}}</view>listFun() {let url this.$url.url.positionInfoCompany;let param {page: this.page,limit: this.limit,keyword: this.keyword,};thi…

onnx nvidia cuda cudnn driver 各种版本对应

onnx 和 nvidia cuda&#xff0c; nvidia cudnn 之间对应关系 NVIDIA - CUDA | onnxruntime # 查看cuda版本 nvcc -V# 查看cudnn版本 cat /usr/include/x86_64-linux-gnu/cudnn_v*.h | grep CUDNN_MAJOR -A 2

Linux常用发行版本软件包安装指南

Linux操作系统以其开源、灵活和高度定制的特性而备受欢迎。然而&#xff0c;对于初学者来说&#xff0c;熟悉不同发行版的软件包管理系统可能是一个挑战。本文将介绍在常见的Linux发行版&#xff08;Ubuntu、CentOS、Alpine&#xff09;上安装软件包的基本指南&#xff0c;以帮…

软著项目推荐 深度学习图像风格迁移

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

力扣225-用队列实现栈

文章目录 力扣225-用队列实现栈示例代码实现总结收获 力扣225-用队列实现栈 示例 代码实现 class MyStack {Queue<Integer>queue1;Queue<Integer>queue2;public MyStack() {queue1new LinkedList<Integer>();queue2new LinkedList<Integer>();}public…

elupload base64

创作灵感也许就是这会儿还没有入睡吧&#xff0c;对接百度图片OCR功能&#xff0c;需要将图片转为BASE64上传调用百度的接口api&#xff0c;进行研究实现。页面如下&#xff0c;点击后选择图片文件后不是直接上传&#xff0c;而是获取图片的bytes数据&#xff01; <el-uploa…