关于计时函数

来源:互联网 发布:python图像处理opencv 编辑:程序博客网 时间:2024/05/21 19:38

在用C/C++写一些算法时,经常要分析程序或函数的性能,不可避免地要使用到计时函数。尤其是在做图像处理时,更是要细致到每个函数到底占用了多少时间,以此来作为进一步提高程序效率的依据。

在这儿大致总结一下用过的计时函数。


一、最常使用的time()和clock()

1、time()函数,头文件<time.h>,函数原型:time_t time(time_t * _Time);  time_t在VC6.0中定义为long型,在Visual Studio 2010中定义为__int64型,即64位整型(可能是为了防止到2038年1月18日19时14分07秒后清零的情况,64位整型可以表示到3001年1月 1日0时0分0秒(不包括该时间点)之前的时间)。参数为接收该函数返回值的变量的地址,返回值为从1970年1月1日0时0分0秒到当前系统时间所经过的数。

注:用C语言的方式输入输出时,64位整型变量的标识符为%I64d或%I64u(无符号)。

2、clock()函数,头文件也是<time.h>,函数原型:clock_t  clock(void);  clock_t定义为long型(VC和VS2010中都是)。返回值为该进程运行的滴答数。在<time.h>中定义了常量CLOCKS_PER_SEC表示每秒嘀嗒数,Windows下一般是1000,LINUX下一般是1000000。即Windows下clokc()的返回值可当作毫秒用,LINUX下可当作微秒用。(在LINUX下多线程时clock函数不稳定,可能是LINUX下线程实现机制的缘故)。


二、WindowsAPI中提供的GetTickCount()函数

GetTickCount()函数,定义在<WinBase.h>中,但需要包含<Windows.h>,否则会报错。没深入了解过Windows编程,故其具体原因不详。

函数原型:DWORD GetTickCount(void); DWORD定义为为long型。该函数返回从操作系统启动所经过的毫秒数。

注1:该函数并非实时发送,而是由系统每18ms发送一次,因此其最小精度为18ms。(VC6.0测试,在15-18毫秒之间,某篇论文上写到MSDN上关于该函数的时间精度说明为10-16毫秒之间);

注2:该函数返回值以32位的双字类型DWORD存储,因此可以存储的最大值是2^32 ms约为49.71天,因此若系统运行时间超过49.71天时,这个数就会归0。在使用时需特别注意。尤其是在编写服务端程序时。


三、WindowsAPI中提供的QueryPerformanceCounter()和QueryPerformanceFrequency()函数

1、 QueryPerformanceCounter()函数,定义在<WinBase.h>中,需包含头文件<Windows.h>。

函数原型:BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount );

返回值非零表示硬件支持高精度计数器,零表示不支持。

唯一的参数是被写入的LARGE_INTEGER变量的地址。LARGE_INTEGER是一个联合体,一般可直接引用其QuadPart成员即可,QuadPart定义为LONGLONG,即__int64型,64位整型变量。

该函数(如果硬件支持的话)将硬件的高精度计时器的值写入lpPerformanceCount指向的变量。在某事件前后两次调用该函数,计算差值即可得到计时器间隔。

2、QueryPerformanceFrequency()函数,定义在<WinBase.h>中,需包含头文件<Windows.h>。

函数原型:BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

返回值同上,非零表示硬件支持高精度计数器,零表示不支持。

该函数将硬件支持的高精度计数器的频率写入lpFrequency指向的变量。

将两次调用QueryPerformanceCounter()函数的差值去除以频率,即可得到以秒为单位的时间间隔。


四、在使用OpenCV时,OpenCV中提供了两个用于计算时间的函数

1、cvGetTickCount()函数,定义在<core_c.h>中,一般包含<opencv.hpp>即可。

函数原型:int64 cvGetTickCount( void );

返回值为从依赖于平台的事件(从启动开始 CPU 的ticks 数目, 从1970年开始的微秒数目等等)开始的 tics 的数目。

2、cvGetTickFrequency()函数,定义在<core_c.h>中,一般包含<opencv.hpp>即可。

函数原型:double cvGetTickFrequency( void );

返回值为每个微秒的 tics 的数目

结合使用cvGetTickCount()与cvGetTickFrequency()即可得到某事件消耗的时间。


附测试代码:

// TimeTest.cpp : 定义控制台应用程序的入口点。//#include <stdio.h>#include <time.h>#include <Windows.h>#include <opencv.hpp>int main(int argc, char* argv[]){// clock()测试clock_t c0 = clock();Sleep(1000);printf("clock: %ldms\n", clock() - c0);// GetTickCount()测试DWORD d0 = GetTickCount();Sleep(1000);printf("GetTickCount: %ldms\n", GetTickCount() - d0);// cvGetTickCount()测试int64 cv0 = cvGetTickCount();Sleep(1000);printf("cvGetTickCount: %gus\t", (cvGetTickCount() - cv0) / cvGetTickFrequency());printf("cvGetTickFrequency: %g tics/us\n", cvGetTickFrequency());// QueryPerformance()测试LARGE_INTEGER largeFrequency;if (0 == QueryPerformanceFrequency(&largeFrequency)) {printf("硬件不支持高精度时钟!\n");} else {LARGE_INTEGER largeTime0, largeTime1;QueryPerformanceCounter(&largeTime0);Sleep(1000);QueryPerformanceCounter(&largeTime1);printf("QueryPerformanceCounter: %I64ums\t", (largeTime1.QuadPart - largeTime0.QuadPart) * 1000 / largeFrequency.QuadPart);printf("QueryPerformanceFrequency: %I64u tics/s\n", largeFrequency.QuadPart);}return 0;}

总结:

一般计时用time()函数即可,两次time(NULL)的返回值相减就是间隔的秒数,同时time_t的数据类型也方便用localtime()函数去转换成各种各样的格式输出;32位情况下,time_t大约可以计时到2106年。

若要计算程序运行时间,可以用clock()函数也很方便,可以得到毫秒数(LINUX下可能是微秒数);32位情况下,若返回毫秒数,clock()函数可以计时49天。

同样,WindowsAPI中提供的函数QueryPerformanceFrequency()也可以返回毫秒数,计时49天。但这个函数不一定能用,需要先调用QueryPerformanceCounter()进行测试。所以感觉比较鸡肋。可能提供的精度要比clock()好一些。没测试过。

在用OpenCV编程时,用OpenCV的两个函数获得微秒级的时间间隔应该能满足要求;由于返回值是64位的整型,故可以计时585942年,这个一般情况下不会溢出。

若要更精确的控制时间,用QueryPerformanceCounter()函数可以算是最高精度的了。用两次得到的值作差,除以QueryPerformanceFrequency()两个Windows提供的函数,得到的是秒数,把被除数乘以1000可得到毫秒,再乘1000可得到微秒。因为返回的是double类型,所以精度基本可以得到保证。


另见:高性能计算下的精确时间处理问题

0 0
原创粉丝点击