[原创分享]关于1ms精度的计时延时器的基本测试,该怎么处理

[原创分享]关于1ms精度的计时延时器的基本测试
2013年11月30日补充
之前写这篇文章时,因为已经使用win7一段较长的时间,所以没针对API帮助提到的Period方面的精度控制,在WinXP系统下做测试,后来找时间测试了下,不加timeBeginPeriod的话,那两个API在XP下精度远不到1ms。当初写这篇文章的主要目的,是闲聊一下自己测试代码执行速度的一些办法。现在打算结帖了,考虑到确实还有不少程序需要在winxp和win2003下使用,而且即使只在WIN7以上系统中运行,按官方的API说明,加上timeBeginPeriod的设置,也更严谨些,毕竟我也没看到哪里说,在WIN7下这个调用是可以省去的,搞不好在有些地方没调用timeBeginPeriod就不够精度呢。唉,不废话了,直接贴补充的代码。对了,有趣的是,加了timeBeginPeriod(1)后,在xp下多次测试那段DoTestSleep的代码,返回值都是2,不像win7下那样是1.

Public Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long
Public Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long

Private Sub Form_Initialize()
    Call timeBeginPeriod(1)
End Sub

Private Sub Form_Terminate()
    Call timeEndPeriod(1)
End Sub


注意:这里说的1ms精度,只是指在适当条件(比如说CPU占用率不太高)下,用下述代码实测时,一般能达到的时间上的分辨率。就好像说一个人视力2.0,是指的他在准备充分条件下,去光线等条件符合相关标准的视力测试表前能测到2.0的水准,并不是说他在睡眼矇眬或长时间盯着电脑屏幕,或其它平时常见的生活状态下都能测试出有这个成绩。绝不能理解为“MS的windows系统能保证这些API实际执行时,所有情况都能有1ms的精度”。如果有“准确率”方面的严苛要求,建议多了解实时操作系统(RTOS)方面的知识。本人那方面了解不多,也就不多讨论了。

刚发了篇小博文,特别适合小白,考虑到论坛里很多人不怎么上博客,在这里也宣传一下
http://blog.csdn.net/bcrun/article/details/13772257
关于1ms精度的计时延时器的基本测试 

  一般来说,在平时编程中,出于优化代码运行速度等需求,常需要测算时间,这就需要对相关计时函数的精度做一番了解,不能老是糊里糊涂混日子。下面的测试由此而来

  首先,我们需要测出,常用的计时函数中哪个达到了1ms精度。先测GetTickCount

    '声明:  
    Declare Function GetTickCount Lib "kernel32" Alias "GetTickCount" () As Long  
    '说明  
    用于获取自windows启动以来经历的时间长度(毫秒)  
    '返回值  
    Long,以毫秒为单位的windows运行时间
  

如果只100000次的话,因为工作量太小,一般会输出0。不过不用担心,我们逐步加大循环次数,多测几次就行了。注意循环次数的跨度不要太大了,可以200000,300000这样的依次增加。这样你会发现,到了某一次,比如说500000,输出值会突然从0跳到16左右。可见这个API的实际精度只有约16ms.



    Private Sub DoTestGetTickCount()  
        Dim lTime1&, lTime2&  
        Dim i&  
        lTime1 = GetTickCount  
        For i = 1 To 400000  
          
        Next i  
        lTime2 = GetTickCount  
        Debug.Print lTime2 - lTime1  
    End Sub
  

写到这里时,可能已经有初学者急着要知道1ms精度的函数在哪了,别急,timeGetTime就是了:



    Private Declare Function timeGetTime Lib "winmm.dll" () As Long
  

测试代码几乎一样。测试结果为,在本人机器上,循环次数在100000时输出值就约为2-3了,次数增加1倍到200000的话,结果为4-5.如果减小到50000,则是1-2.可见,这个计时函数的精度为1ms.



    Private Sub DoTestTimeGetTime()  
        Dim lTime1&, lTime2&  
        Dim i&  
        lTime1 = timeGetTime  
        For i = 1 To 100000  
          
        Next i  
        lTime2 = timeGetTime  
        Debug.Print lTime2 - lTime1  
    End Sub
  

接下来,因为确认了timeGetTime的精度可以达到1ms,我们可以放心测算延时函数sleep的实际精度了,先公布结果,1ms.


    Private Sub DoTestSleep()  
        Dim lTime1&, lTime2&  
        Dim i&  
        lTime1 = timeGetTime  
      
        Sleep 1 'delay 1 ms  
        lTime2 = timeGetTime  
        Debug.Print lTime2 - lTime1  
    End Sub
  


最后补充说明一下,获取UTC时间的GetSystemTime和相应的SystemTimeToFileTime,实际精度也是1ms
------解决方案--------------------
Windows NT:该函数的时间精度是五毫秒或更大一些,这取决于机器的性能。可用timeBeginPeriod和timeEndPeriod函数提高timeGetTime函数的精度。如果使用了,连续调用timeGetTime函数,一系列返回值的差异由timeBeginPeriod和timeEndPeriod决定。
------解决方案--------------------
timeGetTime与操作系统和机器性能本身有关的,高精度计时器一般都是用QueryPerformanceCounter 配合QueryPerformanceFrequency函数的。
------解决方案--------------------
有个很有名的软件叫变速齿轮,也许现在知道的人不多了,可是我们学生时代的回忆啊。

它就是通过hook GetTickCount欺骗软件实现变速的。
------解决方案--------------------