资源描述
目录1常规计时.11.1 time().11.2 GetTickCount.32使用 CPU 时间戳进行高精度计时 .53精确获取时间 QueryPerformanceCounter .91.常规计时1.1 time()C 语言中 time()函数函数简介函数名:time头文件:time.h函数原型:time_t time(time_t*timer)功能:获取当前的系统时间,返回的结果是一个 time_t 类型,其实就是一个大整数,Epoch 时间)到当前时刻的秒数。然后调用别表示年月日时分秒。补充说明:time 函数的原型也可以理解为long time(long*tloc),即返回一个 long 型整localtime 将 time_t 所表示的 CUT 时间其值表示从 CUT(Coordinated Universal Time)时间 1970 年 1 月 1 日 00:00:00(称为 UNIX 系统的转换为本地时间(我们是+8 区,比 CUT 多 8 个小时)并转成 struct tm 类型,该类型的各 数据成员分数。因为在 time.h 这个头文件中 time_t 实际上就是:#ifndef _TIME_T_DEFINEDtypedef long time_t;/*time value*/#define _TIME_T_DEFINED/*avoid multiple defines of time_t*/#en dif即 long。函数应用举例程序例 1:time 函数获得日历时间。日历时间,是用从一个标准时间点到此时的时间经过的秒数”来表示的时间。这个标准时间点对不同的编译器来说会有所不同,但对一个编译系统 来说,这个标准时间点是不变的,该编译系统中的时间对应的日历时间都通过该标准时间点来衡量,所以可以说日历时间是 相对时间”但是无论你在哪一个时区,在同一时刻对同一个标准时 间点来说,日历时间都是一样的。#in elude#in elude#inelude int mai n(void)time_t t;t=time(NULL);printf(The number of seeonds since January 1,1970 is%ld,t);return 0;程序例 2:/time 函数也常用于随机数的生成,用日历时间作为种子。#in elude#in elude#includeint mai n(void)int i;srand(unsigned)time(NULL);prin tf(te n ran dom nu mbers from 0 to 99nn);for(i=0;i10;i+)prin tf(%dn,ra nd()%100);return 0;程序例 3:用 time()函数结合其他函数(如:loealtime、gmtime、asetime、etime)可以获得当前 系统时间或是标准时间。#in elude#in elude#in elude int mai n(void)time_t timer;/time_t 就是 long int 类型struet tm*tbloek;timer=time(NULL);/这一句也可以改成time(&timer);tbloek=loealtime(&timer);prin tf(Loeal time is:%sn,asctime(tblock);return 0;1.2 GetTickCountGetTickCount 函数函数功能:GetTickCount 返回(retrieve)从操作系统启动到现在所经过(的毫秒数,它的返回值是 DWORD。函数原型:DWORD GetTickCou nt(void);C+版CStri ng s;DWORD k=:GetTickCou nt();/获取毫秒级数目int se=k/1000;/se 为秒coutsee ndl;库文件:kernl32.dllC/C+头文件:win base.hwindows 程序设计中可以使用头文件windows.h程序示例代替 time 函数来初始化随机数生成器#in clude#i ncludeint mai n()int i,k,r;for(i=0;i10;i+)sran d(GetTickCou nt();prin tf(n);for(k=0;k5;k+)r=ran d();prin tf(%d”,r);return 0;elapsed)注意事项GetTickcou nt 函数:它返回从操作系统启动到当前所经过的毫秒数,常常用来判断某个方法执行的时间,其函数原型是这个数就会归DWORD GetTickCount(void),返回值以 32 位的双字类型0,MSDN 中也明确的提到了DWORD 存储,因此可以存储的最大值是 2-1 ms约为 49.71 天,因此若系统运行时间超过 49.71 天时,:Retrieves the number of。因此,女口millisec onds that have elapsed since the system was started,up to 49.7 days.果是编写服务器端程序,此处一定要万分注意,避免引起意外的状况。DWORD nowtime=0,lastime=0;no wtime=GetTickCo un t();1.3clock()clock()是 C/C+中的计时函数,而与其相关的数据类型是clock 函数定义如下:clock_t clock(void);这个函数返回从开启这个程序进程”到程序中调用 clock()函数”时之间的 CPU 时钟计时 单元(clock tick)数,在 MSDN 中称之为挂钟时间(wal-clock);若挂钟时间不可取,则返 回-1。其中 clock_t是用来保存时间的数据类型,在义:#ifndef _CLOCK_T_DEFINEDtypedef long clock_t;#define _CLOCK_T_DEFINED#en dif很明显,clock_t 是一个长整形数。在 time.h 文件中,还定义了一个常量 CLOCKS PER SEC,它用来表示一秒钟会有多少个时钟计时单元,其定义如下:#define CLOCKS_PER_SEC(clock_t)1000)可以看到每过千分之一秒(1 毫秒),调用 clock()函数返回的值就加1。下面举个例time.h 文件中,我们可以找到对它的定clock_t。在 MSDN 中,查得对子,你可以使用公式 clock()/CLOCKS_PER_SE 来计算一个进程自身的运行时间:void elapsed_time()prin tf(Elapsed time:%u secs.n,clock()/CLOCKS_PER_SEC);当然,你也可以用 clock 函数来计算你的机器运行一个循环或者处理其它事件到底花了 多少时间:#in clude#in clude#in clude int mai n(void)long i=10000000L;clock_t start,finish;double duration;/*测量一个事件持续的时间*/printf(Time to do%ld empty loops is,i);start=clock();while(i-);finish=clock();duration=(double)(finish-start)/CLOCKS_PER_SEC;printf(%f secondsn,duration);system(pause);在笔者的机器上,运行结果如下:Time to do 10000000 empty loops is 0.03000 seconds上面我们看到时钟计时单元的长度为 1 毫秒,那么计时的精度也为 1 毫秒,那么我们可不可以通过改变 CLOCKS_PER_SEC 定义,通过把它定义的大一些,从而使计时精度更高呢?通过尝试,你会发现这样是不行的。在标准C/C+中,最小的计时单位是一毫秒。2.使用 CPU时间戳进行高精度计时对关注性能的程序开发人员而言,一个好的计时部件既是益友,也是良师。计时器既可以作 为程序组件帮助程序员精确的控制程序进程,又是一件有力的调试武器,在有经验的程序员 手里可以尽快的确定程序的性能瓶颈,或者对不同的算法作出有说服力的性能比较。在 Windows 平台下,常用的计时器有两种,一种是 timeGetTime 多媒体计时器,它可以提 供 毫秒 级的 计时。但 这个精 度对 很多应 用场 合而言 还是太 粗糙 了。另 一种 是 QueryPerformanceCount计数器,随系统的不同可以提供微秒级的计数。对于实时图形处理、多 媒体数 据流 处理、或者实时系 统构造 的 程 序员,善用 QueryPerformanceCount QueryPerformanceFrequency 是一项基本功。本文要介绍的,是另一种直接利用 Pentium CPU 内部时间戳进行计时的高精度计时手段。以 下讨论主要得益于 Windows 图形编程一书,第 15 页 17 页,有兴趣的读者可以直接参 考该书。关于RDTSC 指令的详细讨论,可以参考 Intel 产品手册。本文仅仅作抛砖之用。在 Intel Pentium 以上级别的 CPU 中,有一个称为“时间戳(Time Stamp)”的部件,它以 64 位无符号整型数的格式,记录了自 CPU 上电以来所经过的时钟周期数。由于目前的 CPU 主 频都非常高,因此这个部件可以达到纳秒级的计时精度。这个精确性是上述两种方法所无法 比拟的。在 Pentium 以上的 CPU 中,提供了一条机器指令RDTSC(Read Time Stamp Counter)来读取这个时间戳的数字,并将其保存在 EDX:EAX 寄存器对中。由于 EDX:EAX 寄存器对恰好 是 Win32平台下 C+语言保存函数返回值的寄存器,所以我们可以把这条指令看成是一个 普通的函数调用。像这样:inline unsigned _int64 GetCycleCount()asm RDTSC但是不行,因为 RDTSC 不被 C+的内嵌汇编器直接支持,所以我们要用 _emit 伪指令直接嵌入该指令的机器码形式OXOF、0X31,如下:inline unsigned _int64 GetCycleCount()_asm _emit 0 x0F_asm _emit 0 x31以后在需要计数器的场合,可以像使用普通的 Win32 API 一样,调用两次 GetCycleCount 函 数,比较两个返回值的差,像这样:unsigned long t;t=(unsigned long)GetCycleCount();/Do Something time-intensive.t-=(unsigned long)GetCycleCount();Windows 图形编程第 15 页编写了一个类,把这个计数器封装起来。有兴趣的读者可以 去参考那个类的代码。作者为了更精确的定时,做了一点小小的改进,把执行RDTSC 指令的时间,通过连续两次调用 GetCycleCount 函数计算出来并保存了起来,以后每次计时结束 后,都从实际得到的计数中减掉这一小段时间,以得到更准确的计时数字。但我个人觉得这 一点点改进意义不大。在我的机器上实测,这条指令大概花掉了几十到100 多个周期,在Celeron 800MHz的机器上,这不过是十分之一微秒的时间。对大多数应用来说,这点时间 完全可以忽略不计;而对那些确实要精确到纳秒数量级的应用来说,这个补偿也过于粗糙了。这个方法的优点是:高精度。可以直接达到纳秒级的计时精度(在纳秒),这是其他计时方法所难以企及的。成本低。timeGetTime 函数需要链接多媒体库 winmm.lib,QueryPerformance*函数根 据MSDN 的说明,
展开阅读全文
温馨提示:
金锄头文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
相关搜索