vc获取系统时间,vc获取系统时间毫秒

  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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: