[原创分享]关于1ms精度的计时延时器的基本测试本帖最后由 bcrun 于 2013-11-30 11:44:27 编辑2013年11月30
[原创分享]关于1ms精度的计时延时器的基本测试 本帖最后由 bcrun 于 2013-11-30 11:44:27 编辑 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 timeGetTime sleep
[解决办法] Windows NT:该函数的时间精度是五毫秒或更大一些,这取决于机器的性能。可用timeBeginPeriod和timeEndPeriod函数提高timeGetTime函数的精度。如果使用了,连续调用timeGetTime函数,一系列返回值的差异由timeBeginPeriod和timeEndPeriod决定。[解决办法] timeGetTime与操作系统和机器性能本身有关的,高精度计时器一般都是用QueryPerformanceCounter 配合QueryPerformanceFrequency函数的。[解决办法] 有个很有名的软件叫变速齿轮,也许现在知道的人不多了,可是我们学生时代的回忆啊。 它就是通过hook GetTickCount欺骗软件实现变速的。[解决办法] 与操作系统和硬件有关吧[解决办法]
我在csdn上传了两个测量时间的 C++ 类,精确到 毫秒[解决办法] 嗯,写的不错,QueryPerformanceFrequency可以获得更高[解决办法] 变速齿轮--满满的回忆[解决办法] sleep 不是用来计时的,是把线程时间片释放掉一些,所以他不存在精度的问题;每次调用sleep貌似都是释放当前的时间片。。。[解决办法] KeDelayExecutionThread可以达到百纳秒精度,NdisMSleep可以达到1微秒精度[解决办法] [解决办法] 你这样说,未免有点儿过分了。 这些东西如果M$不公布具体细节方面的资料,谁又能够知道它的真实运行机会? 都只不过是一些推论、猜测罢了! 如果照你的说法,那sleep带个时间参数干什么?那不是多此一举? 既然它带了一个“以毫秒为单位的时间参数”,并且是实实在在的起到了作用的。 那我们对这个“时间”的精度问题进行一些探讨,又有何不可呢?[解决办法] 非常不错,很好很实用[解决办法] [解决办法] 不错,挺有用的------解决方案--------------------
[解决办法] 既然讨论技术,那咱不扯面子了。针对下面代码,俺给出测试结论:xp和win7结果不同,不同的硬件配置返回值也不同。修改首帖吧,赶紧的。 既然讨论技术,那咱不扯面子了。针对下面代码,俺给出测试结论:xp和win7结果不同,不同的硬件配置返回值也不同。修改首帖吧,赶紧的。 Private Sub DoTestSleep() Dim lTime1&, lTime2& Dim i& lTime1 = timeGetTime Sleep 1 'delay 1 ms lTime2 = timeGetTime Debug.Print lTime2 - lTime1 End Sub 看了好几个帖子,也不知道你们到底在争论什么 这个什么也证明不了,sleep不是用来计时的,用sleep测试时钟精确性非常不恰当 这种测试结果,大概只能表示为系统的繁忙程度 用sleep会导致线程切换,估计那样代码每次的测试结果都不相同,而不相同的原因也有很多种,其中之一是timegettime的精度,另外就是系统内的线程环境,还有就是系统对线程调度的算法问题 总之。。。 这个题目,lz的到底怎么想的用 sleep 测试精度。。。。[解决办法] 斑竹辛苦了.........[解决办法] 我一般用高精度频率计数器的2个API。