阅读:2831回复:17
怎样测量micro sec单位的执行经过时间?
现在需要在一个USB驱动程序里测量一下两个函数执行过程中的经过时间.
开始想用KeQuerySystemTime来测量它们的相差值.但是因为经过时间非常短,而KeQuerySystemTime能取得的系统时间是每10mili sec才更新一次的,所以根本不行. 接下来考虑用KeQueryPerformanceCounter来测量,现在编的程序如下: LARGE_INTEGER stPerfCnt, perfFreq //测量起点 stPerfCnt = KeQueryPerformanceCounter(&perfFreq) ; DebugPrint(\"DispatchRead() : stPerfCnt_Start = %L / perfFreq = %L\", stPerfCnt, perfFreq) ; //测量终点 stPerfCnt = KeQueryPerformanceCounter(&perfFreq) ; DebugPrint(\"DispatchRead() : stPerfCnt_End = %L / perfFreq = %L\", stPerfCnt, perfFreq) ; 我在Windows 2000 SP4的PC上测到的数据如下: perfFreq = 369E99 stPerfCnt_Start = 8EAE1931A stPerfCnt_End = 8EAE1945A 所以我认为经过时间应该是 elapsed time = (stPerfCnt_End - stPerfCnt_Start) * (1 / perfFreq) = 89.4 micro sec 不知道这样测量是不是正确?因为我在Windows 2000 DDK的帮助上看到这样的文章,让我丧失了自信. KeQueryPerformanceCounter is intended for time-stamping packets or for computing performance and capacity measurements. It is not intended for measuring elapsed time, for computing stalls or waits, or for iterations. 如果这种测量方法不正确的话,怎样才能测量单位在micro sec的经过时间呢?我在DDK的帮助上找了半天,已经黔驴计穷,希望大家给予帮忙!!多谢. |
|
沙发#
发布于:2005-02-24 11:09
我记得好像奔腾Cpu以后有个64位的tick,里面是最精确的按CPU频率走的。让后来的战友替你说说它的用法,以前在哪里看过,没有实际用过,现在不好找了
|
|
|
板凳#
发布于:2005-02-24 19:51
KeQueryTickCount 试一下。
|
|
地板#
发布于:2005-02-25 10:07
KeQueryTickCount 试一下。 嘻嘻,真是人多力量大,就是它 |
|
|
地下室#
发布于:2005-02-25 12:24
KeQueryTickCount 试一下。 其实我已经试过了.但是起点和终点测出来的数据是一样的.不知道是为什么?程序如下.如果有错误请指正. LARGE_INTEGER TickCnt; //起点 KeQueryTickCount(&TickCnt); DebugPrint(\"DispatchWrite() : TickCnt_Start = %L\", TickCnt); //终点 KeQueryTickCount(&TickCnt); DebugPrint(\"DispatchWrite() : TickCnt_End = %L\", TickCnt); 测出来的结果是: TickCnt_Start = 0x3723 TickCnt_End = 0x3723 也就是说其间的差值为0.如果tick足够小的话,怎么会没有差值呢?还是搞不明白啊!多谢指教. |
|
5楼#
发布于:2005-02-25 16:35
tick最小是100ns,它也是跟处理器无关的,即跟处理器频率无关,也是加工出来的,如果你执行几条或几十条指令,应该是用不了100ns,你需要用这么高精度的计时吗?
|
|
|
6楼#
发布于:2005-02-25 18:00
tick最小是100ns,它也是跟处理器无关的,即跟处理器频率无关,也是加工出来的,如果你执行几条或几十条指令,应该是用不了100ns,你需要用这么高精度的计时吗? 用KeQueryTickCount测出的tick数所指的tick到底是几秒呢? 我在DDK上看到这样的记述: -------------------------- The TickCount value increases by one at each interval timer interrupt while the system is running. The preferred method of determining elapsed time is by using TickCount for relative timing and time stamps. To determine the absolute elapsed time multiply the returned TickCount by the KeQueryTimeIncrement return value using compiler support for 64-bit integer operations. Callers of KeQueryTickCount can be running at any IRQL. -------------------------- 如果我没理解错的话,意思是[正确的经过时间(系统启动后),应该用KeQueryTickCount的值乘上KeQueryTimeIncrement的值] 我查了KeQueryTimeIncrement的定义 -------------------------- KeQueryTimeIncrement returns the number of 100-nanosecond units that are added to the system time each time the interval clock interrupts. -------------------------- 我调用了KeQueryTimeIncrement, 结果测出的值是10进制的 2152722206 既然它是以100ns为单位的,怎么会那么大? 换成秒的话,就是215秒了.不可能吧? 不知道该如何理解.请指教. |
|
7楼#
发布于:2005-02-26 10:53
[quote]tick最小是100ns,它也是跟处理器无关的,即跟处理器频率无关,也是加工出来的,如果你执行几条或几十条指令,应该是用不了100ns,你需要用这么高精度的计时吗? 用KeQueryTickCount测出的tick数所指的tick到底是几秒呢? 我在DDK上看到这样的记述: -------------------------- The TickCount value increases by one at each interval timer interrupt while the system is running. The preferred method of determining elapsed time is by using TickCount for relative timing and time stamps. To determine the absolute elapsed time multiply the returned TickCount by the KeQueryTimeIncrement return value using compiler support for 64-bit integer operations. Callers of KeQueryTickCount can be running at any IRQL. -------------------------- 如果我没理解错的话,意思是[正确的经过时间(系统启动后),应该用KeQueryTickCount的值乘上KeQueryTimeIncrement的值] 我查了KeQueryTimeIncrement的定义 -------------------------- KeQueryTimeIncrement returns the number of 100-nanosecond units that are added to the system time each time the interval clock interrupts. -------------------------- 我调用了KeQueryTimeIncrement, 结果测出的值是10进制的 2152722206 既然它是以100ns为单位的,怎么会那么大? 换成秒的话,就是215秒了.不可能吧? 不知道该如何理解.请指教. [/quote] 我调用了KeQueryTimeIncrement, 结果测出的值是10进制的 2152722206 不可能那么大,你的返回值都快到ULONG最大值的一半了。 我的机器上返回值为2625A,10进制为156250,以100ns算为0.0156250秒,合理 |
|
|
8楼#
发布于:2005-02-28 12:25
[quote][quote]tick最小是100ns,它也是跟处理器无关的,即跟处理器频率无关,也是加工出来的,如果你执行几条或几十条指令,应该是用不了100ns,你需要用这么高精度的计时吗? 用KeQueryTickCount测出的tick数所指的tick到底是几秒呢? 我在DDK上看到这样的记述: -------------------------- The TickCount value increases by one at each interval timer interrupt while the system is running. The preferred method of determining elapsed time is by using TickCount for relative timing and time stamps. To determine the absolute elapsed time multiply the returned TickCount by the KeQueryTimeIncrement return value using compiler support for 64-bit integer operations. Callers of KeQueryTickCount can be running at any IRQL. -------------------------- 如果我没理解错的话,意思是[正确的经过时间(系统启动后),应该用KeQueryTickCount的值乘上KeQueryTimeIncrement的值] 我查了KeQueryTimeIncrement的定义 -------------------------- KeQueryTimeIncrement returns the number of 100-nanosecond units that are added to the system time each time the interval clock interrupts. -------------------------- 我调用了KeQueryTimeIncrement, 结果测出的值是10进制的 2152722206 既然它是以100ns为单位的,怎么会那么大? 换成秒的话,就是215秒了.不可能吧? 不知道该如何理解.请指教. [/quote] 我调用了KeQueryTimeIncrement, 结果测出的值是10进制的 2152722206 不可能那么大,你的返回值都快到ULONG最大值的一半了。 我的机器上返回值为2625A,10进制为156250,以100ns算为0.0156250秒,合理 [/quote] 我是用DebugPrint来查看的. DebugPrint(\"DispatchRead() : TimeInc_16 = %x\", KeQueryTimeIncrement); DebugPrint(\"DispatchRead() : TimeInc_10 = %u\", KeQueryTimeIncrement); 结果是 TimeInc_16 = 804FEF1E TimeInc_10 = 2152722206 KeQueryTimeIncrement的返回值是ULONG.DebugPrint上打印ULONG是用%u(10进制)%x(16进制).好象没错呀? 还望大虾指点. |
|
9楼#
发布于:2005-02-28 15:48
[quote][quote][quote]tick最小是100ns,它也是跟处理器无关的,即跟处理器频率无关,也是加工出来的,如果你执行几条或几十条指令,应该是用不了100ns,你需要用这么高精度的计时吗? 用KeQueryTickCount测出的tick数所指的tick到底是几秒呢? 我在DDK上看到这样的记述: -------------------------- The TickCount value increases by one at each interval timer interrupt while the system is running. The preferred method of determining elapsed time is by using TickCount for relative timing and time stamps. To determine the absolute elapsed time multiply the returned TickCount by the KeQueryTimeIncrement return value using compiler support for 64-bit integer operations. Callers of KeQueryTickCount can be running at any IRQL. -------------------------- 如果我没理解错的话,意思是[正确的经过时间(系统启动后),应该用KeQueryTickCount的值乘上KeQueryTimeIncrement的值] 我查了KeQueryTimeIncrement的定义 -------------------------- KeQueryTimeIncrement returns the number of 100-nanosecond units that are added to the system time each time the interval clock interrupts. -------------------------- 我调用了KeQueryTimeIncrement, 结果测出的值是10进制的 2152722206 既然它是以100ns为单位的,怎么会那么大? 换成秒的话,就是215秒了.不可能吧? 不知道该如何理解.请指教. [/quote] 我调用了KeQueryTimeIncrement, 结果测出的值是10进制的 2152722206 不可能那么大,你的返回值都快到ULONG最大值的一半了。 我的机器上返回值为2625A,10进制为156250,以100ns算为0.0156250秒,合理 [/quote] 我是用DebugPrint来查看的. DebugPrint(\"DispatchRead() : TimeInc_16 = %x\", KeQueryTimeIncrement); DebugPrint(\"DispatchRead() : TimeInc_10 = %u\", KeQueryTimeIncrement); 结果是 TimeInc_16 = 804FEF1E TimeInc_10 = 2152722206 KeQueryTimeIncrement的返回值是ULONG.DebugPrint上打印ULONG是用%u(10进制)%x(16进制).好象没错呀? 还望大虾指点. [/quote] 看样子是把KeQueryTimeIncrement所在的内存地址打印出来了,嗯,有点像,804FEF1E差不多 还是将KeQueryTimeIncrement的返回值放入一个变量,再看它的值,最好不要偷懒 |
|
|
10楼#
发布于:2005-02-28 15:57
我的系统是xp sp2,KeQueryTimeIncrement函数的地址是804E6FD5,差不多
|
|
|
11楼#
发布于:2005-03-01 12:35
我的系统是xp sp2,KeQueryTimeIncrement函数的地址是804E6FD5,差不多 真是一针见血!的确是偷懒的结果.修改后调出的结果和你一样是 0.0156250秒 这相当于15625us,怪不得KeQueryTickCount测出的起点和终点值一样,因为经过时间没那么长. 据客户的资料来看,起点和终点间的执行时间在2us到200us之间,也不知道他们究竟是怎么测的. 如果假设测量单位要精确到us的话,除了用KeQueryPerformanceCounter之外,还有其他的计时方法吗? |
|
12楼#
发布于:2005-03-02 09:01
[quote]我的系统是xp sp2,KeQueryTimeIncrement函数的地址是804E6FD5,差不多 真是一针见血!的确是偷懒的结果.修改后调出的结果和你一样是 0.0156250秒 这相当于15625us,怪不得KeQueryTickCount测出的起点和终点值一样,因为经过时间没那么长. 据客户的资料来看,起点和终点间的执行时间在2us到200us之间,也不知道他们究竟是怎么测的. 如果假设测量单位要精确到us的话,除了用KeQueryPerformanceCounter之外,还有其他的计时方法吗? [/quote] 据DDK中实际应用最小的计时只能达到0.1ms,做不到那么精确,以前在DOS下,可以通过执行固定一条指令n遍,计算所用时间,相除算出一条指令执行的时间,这样可以计算两个中断间的精确时间,但在Windows下,情况比较复杂,不知是否可以用了 |
|
|
13楼#
发布于:2005-03-03 08:49
[quote]我的系统是xp sp2,KeQueryTimeIncrement函数的地址是804E6FD5,差不多 真是一针见血!的确是偷懒的结果.修改后调出的结果和你一样是 0.0156250秒 这相当于15625us,怪不得KeQueryTickCount测出的起点和终点值一样,因为经过时间没那么长. 据客户的资料来看,起点和终点间的执行时间在2us到200us之间,也不知道他们究竟是怎么测的. 如果假设测量单位要精确到us的话,除了用KeQueryPerformanceCounter之外,还有其他的计时方法吗? [/quote] 回去查了一下以前做的老程序,发现以前居然用的是KeQueryInterruptTime,实际试了一下,发现这个精度很高,而且对系统压力非常小,老了,记忆力有所减退 |
|
|
14楼#
发布于:2005-03-03 14:21
回去查了一下以前做的老程序,发现以前居然用的是KeQueryInterruptTime,实际试了一下,发现这个精度很高,而且对系统压力非常小,老了,记忆力有所减退 我也曾经试过KeQueryInterruptTime函数.它测出的单位应该是100ns.但是我用下面的程序测时,得出的起点和终点的结果还是相同的.我不相信经过时间小于100ns.难道还是用法不对吗? KeQueryInterruptTime的返回值是用ULONGLONG的.我在DDK上查不到ULONGLONG的定义.在网上看到ULONGLONG好象是一个64位数,就用了__int64来定义,不知道对不对. __int64 ItrTime; //起点 ItrTime = KeQueryInterruptTime(); DebugPrint(\"startTime = %D\", ItrTime); //终点 ItrTime = KeQueryInterruptTime(); DebugPrint(\"endTime = %D\", ItrTime); 测出的结果是: startTime = 189678437500 |
|
15楼#
发布于:2005-03-03 14:24
[quote]回去查了一下以前做的老程序,发现以前居然用的是KeQueryInterruptTime,实际试了一下,发现这个精度很高,而且对系统压力非常小,老了,记忆力有所减退 我也曾经试过KeQueryInterruptTime函数.它测出的单位应该是100ns.但是我用下面的程序测时,得出的起点和终点的结果还是相同的.我不相信经过时间小于100ns.难道还是用法不对吗? KeQueryInterruptTime的返回值是用ULONGLONG的.我在DDK上查不到ULONGLONG的定义.在网上看到ULONGLONG好象是一个64位数,就用了__int64来定义,不知道对不对. __int64 ItrTime; //起点 ItrTime = KeQueryInterruptTime(); DebugPrint(\"startTime = %D\", ItrTime); //终点 ItrTime = KeQueryInterruptTime(); DebugPrint(\"endTime = %D\", ItrTime); 测出的结果是: startTime = 189678437500 [/quote] endTime = 189678437500 |
|
16楼#
发布于:2005-03-05 11:49
反汇编看了一下,这个函数根本不是100ns为单位,而是在每次中断时加一个固定的每次中断之间的Increment,而且很大,大概在3ms左右
|
|
|
17楼#
发布于:2005-03-12 11:18
引自www.sysinternals.com的文章
Copyright ? 1997 Mark Russinovich Last Updated: Last updated July 9, 1997 Note: The information presented here is the result of my own study. No source code was used. Introduction High resolution timers are desirable in a wide variety of different applications. For example, the most common use of such timers in Windows is by multimedia applications that are producing sound or audio that require precise control. MIDI is a perfect example because MIDI sequencers must maintain the pace of MIDI events with 1 millisecond accuracy. This article describes how high resolution timers are implemented in NT and documents NtSetTimerResolution and NtQueryTimerResolution, the NT kernel functions that manipulate and return information about the system clock. Unfortunately, NtSetTimerResolution and NtQueryTimerResolution are not exported by the NT kernel, so they are not available to kernel-mode device drivers. The Timer API Windows NT bases all of its timer support off of one system clock interrupt, which by default runs at a 10 millisecond granularity. This is therefore the resolution of standard Windows timers. When a multimedia application uses the timeBeginPeriod mutlimedia API, which is exported by the Windows NT dynamic link library WINMM.DLL, the call is redirected into the Windows NT kernel-mode function NtSetTimerResolution, which is exported by the native Windows NT library NTDLL.DLL. NtSetTimerResolution and NtQueryTimerResolution are defined as follows. All times are specifified in hundreds of nanoseconds. NTSTATUS NtSetTimerResolution ( IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution ); Parameters RequestedResolution The desired timer resolution. Must be within the legal range of system timer values supported by NT. On standard x86 systems this is 1-10 milliseconds. Values that are within the acceptable range are rounded to the next highest millisecond boundary by the standard x86 HAL. This parameter is ignored if the Set parameter is FALSE. Set This is TRUE if a new timer resolution is being requested, and FALSE if the application is indicating it no longer needs a previously implemented resolution. ActualResolution The timer resolution in effect after the call is returned in this parameter. Comments NtSetTimerResolution returns STATUS_SUCCESS if the resolution requested is within the valid range of timer values. If Set is FALSE, the caller must have made a previous call to NtSetTimerResolution or STATUS_TIMER_RESOLUTION_NOT_SET is returned. NTSTATUS NtQueryTimerResolution ( OUT PULONG MinimumResolution, OUT PULONG Maximum Resolution, OUT PULONG ActualResolution ); Parameters MinimumResolution The minimum timer resolution. On standard x86 systems this is 0x2625A, which is about 10 milliseconds MaximumResolution The maximum timer resolution. On standard x86 systems this is 0x2710, which is about 1 millisecond. ActualResolution This is the current resolution of the system clock. Implementation Details NtSetTimerResolution can be called to set timer resolutions by more than on application. To support a subsequent process setting a timer resolution without violating the resolution assumptions of a previous caller, NtSetTimerResolution never lowers the timer\'s resolution, only raises it. For example, if a process sets the resolution to 5 milliseconds, subequent calls to set the resolution to between 5 and 10 millseconds will return a status code indicating success, but the timer will be left at 5 milliseconds. NtSetTimerResolution also keeps track of whether a process has set the timer resolution in its process control block, so that when a call is made with Set equal to FALSE it can verify that the caller has previously requested a new resolution. Every time a new resolution is set a global counter is incremented, and every time it is reset the counter is decremented. When the counter becomes 0 on a reset call the timer is changed back to its default rate, otherwise no action is taken. Again, this preserves the timer resolution assumptions of all the applications that have requested high resolution timers by guaranteeing that the resolution will be at least as good as what they specified. You can use the ClockRes applet from Sysinternals to view the current clock resolution on your system. 标题不知为什么粘不上 写上Inside Windows Nt High resolution timers 我用ClockRes测了一下,我的机器不用高精度计时器精度只有15.3ms |
|
|