vc获取系统时间,vc获取系统时间毫秒
声明:本文是综合互联网上的信息制作而成。里面的字大部分都不是我自己的。我的作用是总结和补充我的一些看法。非常感谢引用文本作者的辛勤工作。我在文章末尾列出了所有的参考文献。
对于关注性能的程序开发人员来说,好的计时组件既是好朋友,也是好老师。定时器可以作为一个程序组件,帮助程序员精确控制程序进程,也是一个强大的调试武器。有经验的程序员可以尽快确定程序的性能瓶颈,或者在不同算法之间进行令人信服的性能比较。
在Windows平台下,常用的定时器有两种,一种是timeGetTime多媒体定时器,可以提供毫秒级的定时。但是这种精度对于许多应用来说还是太粗糙了。另一个是QueryPerformanceCount计数器,可以提供与不同系统的微秒计数。对于处理实时图形处理,多媒体数据流处理,或者实时系统构造的程序员来说,用好QueryPerformanceCount/QueryPerformanceFrequency是一项基本功。
本文介绍了另一种直接利用奔腾CPU内部时间戳的高精度计时方法。以下讨论主要受益于本书《Windows图形编程》,第15-17页。有兴趣的读者可以直接参考这本书。有关RDTSC指令的详细讨论,请参考英特尔产品手册。本文只为抛砖。
在Intel Pentium及以上的CPU中,有一个叫做“时间戳”的组件,它以64位无符号整数的格式记录CPU上电以来的时钟周期数。因为现在的CPU频率很高,这个组件可以达到纳秒级的计时精度。这种精度是以上两种方法无法比拟的。
在奔腾以上的CPU中,提供了一个机器指令RDTSC(读时间戳计数器)来读取这个时间戳的数目,并将其保存在EDX:EAX寄存器对中。因为EDX:EAX寄存器对恰好是Win32平台上存储C语言中某个函数返回值的寄存器,所以我们可以把这个指令看成一个普通的函数调用。像这样:
内联无符号__int64 GetCycleCount()
{
__asm RDTSC
}
但是,不行,因为C的嵌入式汇编程序不直接支持RDTSC,所以我们要直接嵌入_emit伪指令的机器码形式0X0F和0X31,如下:
内联无符号__int64 GetCycleCount()
{
__asm _emit0x0F
__asm _emit0x31
}
将来需要计数器时,可以调用GetCycleCount函数两次,就像使用通用的Win32 API一样,比较两个返回值之间的差异,如下所示:
无符号长t;
t=(无符号长整型)GetCycleCount();
//做一些时间密集的事情.
t -=(无符号长整型)GetCycleCount();
055-79000第15页写了一个类来封装这个计数器。有兴趣的读者可以参考那个类的代码。为了使计时更加准确,作者做了一点改进,通过连续两次调用GetCycleCount函数来计算和节省RDTSC指令的执行时间,然后在每次计时后从实际计数中减去这一小段时间,从而得到更加准确的计时数字。但我个人认为这一点点改进意义不大。在我的机器上测量,这条指令需要几十到100多个周期,在赛扬800MHz机器上只有十分之一微秒。对于大多数应用来说,这个时间完全可以忽略不计;然而,这种补偿对于那些精确到纳秒的应用来说太粗糙了。
我把这个类的源代码从《Windows图形编程》复制下来给大家看看。下面是使用RDTSC指令的CPU时钟周期秒表类:
这种方法的优点是:
1.精度高。可以直接达到纳秒级的计时精度(1GHz CPU上每个时钟周期为一纳秒),这是其他计时方式无法企及的。
2.成本低。TimeGetTime函数需要链接多媒体库winmm.lib,QueryPerformance*函数需要硬件支持(虽然我还没看到不支持的机器)和内核库支持,所以两者都只能在Windows平台下使用(DOS平台下的高精度计时请参考《Windows图形编程》,里面有控制timer 8253的详细说明)。但RDTSC指令是CPU指令,i386平台上所有奔腾以上机器都支持,甚至不受平台限制(相信这种方法在i386 UNIX和Linux下也适用,但没有条件测试),函数调用开销极小。
(这里我想说的是:这样跨平台只能说是操作系统平台,而不是硬件平台,也就是说只能在英特尔奔腾以上的机器上使用)
3.它与CPU主频有直接对应的速率关系。一次计数相当于1/(CPU主频的Hz数)秒,所以只要知道CPU的主频,就可以直接计算出时间。这与QueryPerformanceCount不同,QueryPerformanceCount需要通过QueryPerformanceFrequency获取当前计数器每秒的计数次数,然后才能转换为时间。
这种方法的缺点是:
1.现有的C/C编译器大多不直接支持RDTSC指令的使用,直接嵌入机器码编程比较麻烦。
2.数据抖动严重。事实上,对于任何测量方法来说,准确性和稳定性永远是一对矛盾。如果用低精度的timeGetTime进行计时,基本上每次计时的结果都是一样的;然而,RDTSC指令的结果每次都不一样,往往有数百甚至数千个缺口。这是这种方法的高精度的内在矛盾。
(这里数据抖动确实是个大问题。我遇到过这样的情况,比如测试A和B两个算法,因为数据抖动,有时候A比B用的时间少,有时候B比A用的时间少,我想过两种测试方法:
(1)增加测试次数,例如测试A和B两种算法,各10次,看哪种算法效率最高,A的次数比B少,B的次数比A少.
(2)增加测试数据量,我认为测试数据量一增加算法效率的差异就会显现)
关于这种方法的最大长度,我们可以简单地用下面的公式来计算:
CPU通电后的秒数rate读取的周期数/CPU主频(Hz)
一个64位无符号整数所能表示的最大数是1.810 ^ 19,在我的赛扬800上可以计时700年左右(书上说在200MHz奔腾上可以计时117年。我不知道这个数字是怎么推导出来的,和我的计算不一样)。无论如何,我们不必在意溢出。
下面举几个小例子,简单比较一下三种计时方式的用法和准确度。
//Timer2.cpp使用timeGetTime函数。
//mmsys.h需要包含,但是由于Windows头文件关系复杂
//单纯包含windows.h就是懒:)
//编译行:CLtimer2.cpp/linkwinmm.lib
#包含windows.h
#包含stdio.h
主()
{
DWORDt1,T2;
t1=time gettime();
睡眠(1000);
T2=time gettime();
printf(BeginTime:%u/n ,t1);
printf(EndTime:%u/n ,T2);
printf(LastingTime:%u/n ,(T2-t1));
}
//Timer3.cpp使用QueryPerformanceCounter函数。
//编译行:CLtimer3.cpp/linkKERNEl32.lib
#包含windows.h
#包含stdio.h
主()
{
LARGE_INTEGERt1,t2,TC;
QueryPerformanceFrequency(TC);
printf(频率:%u/n ,tc。quad part);
QueryPerformanceCounter(t1);
睡眠(1000);
QueryPerformanceCounter(T2);
printf(BeginTime:%u/n ,t1。quad part);
printf(EndTime:%u/n ,t2。quad part);
printf(LastingTime:%u/n ,(t2。四部分-t1。quad part));
//这里要加上这句话来计算时间(秒)。
doubledTotalTime=(double)(t2。四部分-t1。四部分)/(双精度)tc。QuadPart//秒
Printf(耗时:%f/n ,dTotalTime);
}
//以上三个样本程序都是在测试睡眠1秒的时间。
文件://测试/测试环境:赛扬800MHz/256M SDRAM
//Windows 2000专业版SP2
//微软Visual C 6.0 SP5
////////////////////////////////////////////////
下面是定时器1使用高精度RDTSC指令的运行结果。
持续时间:804586872
下面是Timer2的运行结果,使用最粗糙的timeGetTime API。
开始时间:20254254
结束时间:20255255
持续时间:1001
下面是使用QueryPerformanceCount API运行Timer3的结果
频率:3579545
开始时间:3804729124
结束时间:3808298836
持续时间:3569712
古人说,类比。很高兴从一本介绍图形编程的书上获得了这么有用的实时处理知识。希望你和我一样喜欢这个轻巧有效的定时器。
网上有一种说法是
double dTotalTime=(double)(t2。四部分-t1。四部分)/(双精度)tc。四部分
可能有问题。比如现在很多主板都有CPU频率自动调节的功能,主要是为了节能,尤其是笔记本,精度无法保证。我不确定这个说法是否准确,供大家研究。
以上主要取自《图形程序开发人员指南》。其实除了上面说的三种方法,还有一种常用的方法没有上面的准确,那就是使用GetTickCount函数。这种方法可以获得毫秒级的时间,具体用法如下:
055-79000作者:张燕_qd
055-79000,作者冯远
《使用CPU时间戳进行高精度计时》,http://www . CPP blog . com/human Chao/archive/2008/04/22/43322 . html
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。