|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『楼 主』:
一直存在的疑问:PC上8253计时器的精确频率到底是多少?
PC机上8253计时器芯片的精确的输入频率到底是多少?
很多书上说PC机的8253的计时器#0的输出频率是每秒18.2次(每隔55ms触发一次),但都说这个只是约值,精确值有很长一串小数。计算机应该是靠整数运算的,那些小数值应该只是换算成现实时间的结果。所以我想知道精确的频率,于是查找了大量的资料,结果发现都有一点出入:
1.许多书上所说的(计数器#0)精确值:
F: 每秒18.2064819336次
T: 每隔54.925ms。
2.Terrv Dettmann《DOS Programmer's Reference》:
H: 由系统时钟每秒大约调用18.2次(每小时65536次)。
D: int 1Ah的00h功能: 该中断获取系统时钟计数器,该计数器从零点开始,每秒计数18.2065次。从零点(midnight)开始的一整天共需计86400秒,这段时间内的计数次数(时钟计数1573040次,经过的时间为86399.9129秒)。
3.Mazid《汇编语言、设计与接口技术》:8284芯片连接到一个14.31818MHz的晶振源,输出的Clr引脚是(8088中)CPU、内存(系统总线)的主频,1/3分频,4.772776MHz。PClk接8253/54计时器,1/6分频,2.386383MHz。在8284与8253之间存在一个72LS175的D触发器,所以频率又除以了2,1.1931817MHz。
4.在某些接口技术的书上说晶振源的频率周期是70ns,与内存速度匹配。
5.在很多计算机上,QueryPerformanceFrequency(Win32 API)的返回值是3579545。3579545 * 4 = 14318180,与3一致。
常数分析
~~~~~~~~
现在对这些常数进行计算分析:
[1F]第1种,根据频率(每秒18.2064819336次)
晶振源频率:18.2064819336Hz * 65536 * 12 = 14,318,160.0000049152Hz
周期:1s / 14,318,160.0000049152Hz = 0.000000069841376266200176256402804053989s = 69.841376266200176256402804053989ns
8253输入频率:18.2064819336Hz * 65536 = 1,193,180.0000004096Hz
周期:1s / 1,193,180.0000004096Hz = 0.00000083809651519440211507683364864787s = 838.09651519440211507683364864787ns
计时器#0输出频率:18.2064819336Hz
周期:1s / 18.2064819336Hz = 0.054925493219780337013675369997787s = 54.925493219780337013675369997787ms
计时器#0触发65536次:(1s / 18.2064819336Hz) * 65536 = 65536s / 18.2064819336Hz = 3599.597123651524166528229048175s
计时器#0触发1573040次:(1s / 18.2064819336Hz) * 1573040 = 1573040s / 18.2064819336Hz = 86399.997854443261335991904021318s
[1T]第1种,根据周期(每隔54.925ms)
晶振源频率:(1s / 54.925ms) * 65536 * 12 = (65536 * 12)s / 0.054925s = 14,318,288.575329995448338643604916Hz
周期:54.925ms / (65536 * 12) = 0.000000069840749104817708333333333333333s = 69.840749104817708333333333333333ns
8253输入频率:(1s / 54.925ms) * 65536 = 65536s / 0.054925s = 1,193,190.7146108329540282203004096Hz
周期:54.925ms / 65536 = 0.0000008380889892578125s = 838.0889892578125ns
计时器#0输出频率:1s / 54.925ms = 18.206645425580336822940373236231Hz
周期:54.925ms
计时器#0触发65536次:54.925ms * 65536 = 3599.5648s
计时器#0触发1573040次:54.925ms * 1573040 = 86399.222s
[2H]第2种,根据小时(每小时65536次)
晶振源频率:1s / (3600s / 65536 / 65536 / 12) = (65536 * 65536 * 12)s / 3600s = 14,316,557.653333333333333333333333Hz
周期:3600s / 65536 / 65536 / 12 = 3600s / (65536 * 65536 * 12) = 0.000000069849193096160888671875s = 69.849193096160888671875ns
8253输入频率:1s / (3600s / 65536 / 65536) = (65536*65536)s / 3600s = 1,193,046.4711111111111111111111111Hz
周期:3600s / 65536 / 65536 = 3600s / (65536 * 65536) = 0.0000008381903171539306640625s = 838.1903171539306640625ns
计时器#0输出频率:1s / (3600s / 65536) = 65536s / 3600s = 18.204444444444444444444444444444Hz
周期:3600s / 65536 = 0.054931640625s = 54.931640625ms
计时器#0触发65536次:3600s
计时器#0触发1573040次:(3600s / 65536) * 1573040 = (3600s * 1573040) / 65536 = 86409.66796875s
[2D]第2种,根据天(时钟计数1573040次,经过的时间为86399.9129秒)
晶振源频率:1s / (86399.9129s / 1573040 / 65536 / 12) = (1573040 * 65536 * 12)s / 86399.9129s = 14,318,174.078622248240715529702808Hz
周期:86399.9129s / 1573040 / 65536 / 12 = 86399.9129s / (1573040 * 65536 * 12) = 0.000000069841307593336928084579328349353s = 69.841307593336928084579328349353ns
8253输入频率:1s / (86399.9129s / 1573040 / 65536) = (1573040 * 65536)s / 86399.9129s = 1,193,181.1732185206867262941419007Hz
周期:86399.9129s / 1573040 / 65536 = 86399.9129s / (1573040 * 65536) = 0.00000083809569112004313701495194019224s = 838.09569112004313701495194019224ns
计时器#0输出频率:1s / (86399.9129s / 1573040) = 1573040s / 86399.9129s = 18.206499835487681377049165983592Hz
周期:86399.9129s / 1573040 = 0.054925439213243147027411890352439s = 54.925439213243147027411890352439ms
计时器#0触发65536次:(86399.9129s / 1573040) * 65536Hz = (86399.9129s * 65536) / 1573040 = 3599.5935842791028835884656461374s
计时器#0触发1573040次:86399.9129s
[3]第3种(8284芯片连接到一个14.31818MHz的晶振源)
晶振源频率:14.31818MHz = 14,318,180Hz
周期:1s / 14,318,180Hz = 0.000000069841278710003645714748662190306s = 69.841278710003645714748662190306ns
8253输入频率:14,318,180Hz / 12 = 1,193,181.6666666666666666666666667Hz
周期:1s / (14,318,180Hz / 12) = 12s / 14,318,180Hz = 0.00000083809534452004374857698394628368s = 838.09534452004374857698394628368ns
计时器#0输出频率:14,318,180Hz / 12 / 65536 = 14,318,180Hz / (12 * 65536) = 18.206507364908854166666666666667Hz
周期:1s / (14,318,180Hz / 12 / 65536) = (12 * 65536)s / 14,318,180Hz = 0.054925416498465587106741219903647s = 54.925416498465587106741219903647ms
计时器#0触发65536次:(1s / (14,318,180Hz / 12 / 65536)) * 65536 = (12 * 65536 * 65536)s / 14,318,180Hz = 3599.5920956434407166273925876054s
计时器#0触发1573040次:(1s / (14,318,180Hz / 12 / 65536)) * 1573040 = (12 * 65536 * 1573040)s / 14,318,180Hz = 86399.877168746307142388208557233s
[4]第4种(晶振源的频率周期是70ns,与内存速度匹配)
晶振源频率:1s / 0.00000007s = 14,285,714.285714285714285714285714Hz
周期:70ns = 0.00000007s
8253输入频率:1s / (0.00000007s * 12) = 1,190,476.1904761904761904761904762Hz
周期:0.00000007s * 12 = 0.00000084s = 840ns
计时器#0输出频率:1s / (0.00000007s * 12 * 65536) = 18.165225074404761904761904761905Hz
周期:0.00000007s * 12 * 65536 = 0.05505024s = 55.05024ms
计时器#0触发65536次:(0.00000007s * 12 * 65536) * 65536 = 3607.77252864s
计时器#0触发1573040次:(0.00000007s * 12 * 65536) * 1573040 = 86596.2295296s
总表
~~~~
晶振源频率(Hz):
1F: 14,318,160.0000049152
1T: 14,318,288.575329995448338643604916
2H: 14,316,557.653333333333333333333333
2D: 14,318,174.078622248240715529702808
3 : 14,318,180
4 : 14,285,714.285714285714285714285714
晶振源周期(ns):
1F: 69.841376266200176256402804053989
1T: 69.840749104817708333333333333333
2H: 69.849193096160888671875
2D: 69.841307593336928084579328349353
3 : 69.841278710003645714748662190306
4 : 70
8253输入频率(Hz):
1F: 1,193,180.0000004096
1T: 1,193,190.7146108329540282203004096
2H: 1,193,046.4711111111111111111111111
2D: 1,193,181.1732185206867262941419007
3 : 1,193,181.6666666666666666666666667
4 : 1,190,476.1904761904761904761904762
8253输入周期(ns):
1F: 838.09651519440211507683364864787
1T: 838.0889892578125
2H: 838.1903171539306640625
2D: 838.09569112004313701495194019224
3 : 838.09534452004374857698394628368
4 : 840
计时器#0输出频率(Hz):
1F: 18.2064819336
1T: 18.206645425580336822940373236231
2H: 18.204444444444444444444444444444
2D: 18.206499835487681377049165983592
3 : 18.206507364908854166666666666667
4 : 18.165225074404761904761904761905
计时器#0输出周期(ms):
1F: 54.925493219780337013675369997787
1T: 54.925
2H: 54.931640625
2D: 54.925439213243147027411890352439
3 : 54.925416498465587106741219903647
4 : 55.05024
计时器#0触发65536次(s):
1F: 3599.597123651524166528229048175
1T: 3599.5648
2H: 3600
2D: 3599.5935842791028835884656461374
3 : 3599.5920956434407166273925876054
4 : 3607.77252864
计时器#0触发1573040次(s):
1F: 86399.997854443261335991904021318
1T: 86399.222
2H: 86409.66796875
2D: 86399.9129
3 : 86399.877168746307142388208557233
4 : 86596.2295296
结论
~~~~
个人认为最可信的是《汇编语言、设计与接口技术》上的说法,晶振源频率为14,318,180Hz,因为它跟许多数字吻合。
PS: 我一直存在这个疑问,但是一直没有去研究。直到前两天看到风云的一篇文章《不太精准的时钟》(http://blog.codingnow.com/2006/05/iaeeoeo.html)后,才认识到这个问题的严重性,引起我关注这个问题。
[ Last edited by zyl910 on 2006-6-3 at 12:44 ]
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-6-3 12:40 |
|
|
Scott0902
中级用户
积分 466
发帖 237
注册 2005-10-12
状态 离线
|
|
2006-6-3 14:03 |
|
|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『第
3 楼』:
刚才又翻了一下《图形程序开发人员指南(Michael Abrash's Graphics Programming Black Book Special Editior)》的“Zen timer”,发现该代码采用的(输入频率周期)是0.8381ms(ZTimerReport函数):
;
; *** Listing 3-1 ***
;
; The precision Zen timer (PZTIMER.ASM)
;
; Uses the 8253 timer to time the performance of code that takes
; less than about 54 milliseconds to execute, with a resolution
; of better than 10 microseconds.
;
; By Michael Abrash
;
; Externally callable routines:
;
; ZTimerOn: Starts the Zen timer, with interrupts disabled.
;
; ZTimerOff: Stops the Zen timer, saves the timer count,
; times the overhead code, and restores interrupts to the
; state they were in when ZTimerOn was called.
;
; ZTimerReport: Prints the net time that passed between starting
; and stopping the timer.
;
; Note: If longer than about 54 ms passes between ZTimerOn and
; ZTimerOff calls, the timer turns over and the count is
; inaccurate. When this happens, an error message is displayed
; instead of a count. The long-period Zen timer should be used
; in such cases.
;
; Note: Interrupts *MUST* be left off between calls to ZTimerOn
; and ZTimerOff for accurate timing and for detection of
; timer overflow.
;
; Note: These routines can introduce slight inaccuracies into the
; system clock count for each code section timed even if
; timer 0 doesn't overflow. If timer 0 does overflow, the
; system clock can become slow by virtually any amount of
; time, since the system clock can't advance while the
; precison timer is timing. Consequently, it's a good idea
; to reboot at the end of each timing session. (The
; battery-backed clock, if any, is not affected by the Zen
; timer.)
;
; All registers, and all flags except the interrupt flag, are
; preserved by all routines. Interrupts are enabled and then disabled
; by ZTimerOn, and are restored by ZTimerOff to the state they were
; in when ZTimerOn was called.
;
Code segment word public 'CODE'
assume cs:Code, ds:nothing
public ZTimerOn, ZTimerOff, ZTimerReport
;
; Base address of the 8253 timer chip.
;
BASE_8253 equ 40h
;
; The address of the timer 0 count registers in the 8253.
;
TIMER_0_8253 equ BASE_8253 + 0
;
; The address of the mode register in the 8253.
;
MODE_8253 equ BASE_8253 + 3
;
; The address of Operation Command Word 3 in the 8259 Programmable
; Interrupt Controller (PIC) (write only, and writable only when
; bit 4 of the byte written to this address is 0 and bit 3 is 1).
;
OCW3 equ 20h
;
; The address of the Interrupt Request register in the 8259 PIC
; (read only, and readable only when bit 1 of OCW3 = 1 and bit 0
; of OCW3 = 0).
;
IRR equ 20h
;
; Macro to emulate a POPF instruction in order to fix the bug in some
; 80286 chips which allows interrupts to occur during a POPF even when
; interrupts remain disabled.
;
MPOPF macro
local p1, p2
jmp short p2
p1: iret ;jump to pushed address & pop flags
p2: push cs ;construct far return address to
call p1 ; the next instruction
endm
;
; Macro to delay briefly to ensure that enough time has elapsed
; between successive I/O accesses so that the device being accessed
; can respond to both accesses even on a very fast PC.
;
DELAY macro
jmp $+2
jmp $+2
jmp $+2
endm
OriginalFlags db ? ;storage for upper byte of
; FLAGS register when
; ZTimerOn called
TimedCount dw ? ;timer 0 count when the timer
; is stopped
ReferenceCount dw ? ;number of counts required to
; execute timer overhead code
OverflowFlag db ? ;used to indicate whether the
; timer overflowed during the
; timing interval
;
; String printed to report results.
;
OutputStr label byte
db 0dh, 0ah, 'Timed count: ', 5 dup (?)
ASCIICountEnd label byte
db ' microseconds', 0dh, 0ah
db '$'
;
; String printed to report timer overflow.
;
OverflowStr label byte
db 0dh, 0ah
db '****************************************************'
db 0dh, 0ah
db '* The timer overflowed, so the interval timed was *'
db 0dh, 0ah
db '* too long for the precision timer to measure. *'
db 0dh, 0ah
db '* Please perform the timing test again with the *'
db 0dh, 0ah
db '* long-period timer. *'
db 0dh, 0ah
db '****************************************************'
db 0dh, 0ah
db '$'
;********************************************************************
;* Routine called to start timing. *
;********************************************************************
ZTimerOn proc near
;
; Save the context of the program being timed.
;
push ax
pushf
pop ax ;get flags so we can keep
; interrupts off when leaving
; this routine
mov cs:[OriginalFlags],ah ;remember the state of the
; Interrupt flag
and ah,0fdh ;set pushed interrupt flag
; to 0
push ax
;
; Turn on interrupts, so the timer interrupt can occur if it's
; pending.
;
sti
;
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
; linear counting rather than count-by-two counting. Also
; leaves the 8253 waiting for the initial timer 0 count to
; be loaded.
;
mov al,00110100b ;mode 2
out MODE_8253,al
;
; Set the timer count to 0, so we know we won't get another
; timer interrupt right away.
; Note: this introduces an inaccuracy of up to 54 ms in the system
; clock count each time it is executed.
;
DELAY
sub al,al
out TIMER_0_8253,al ;lsb
DELAY
out TIMER_0_8253,al ;msb
;
; Wait before clearing interrupts to allow the interrupt generated
; when switching from mode 3 to mode 2 to be recognized. The delay
; must be at least 210 ns long to allow time for that interrupt to
; occur. Here, 10 jumps are used for the delay to ensure that the
; delay time will be more than long enough even on a very fast PC.
;
rept 10
jmp $+2
endm
;
; Disable interrupts to get an accurate count.
;
cli
;
; Set the timer count to 0 again to start the timing interval.
;
mov al,00110100b ;set up to load initial
out MODE_8253,al ; timer count
DELAY
sub al,al
out TIMER_0_8253,al ;load count lsb
DELAY
out TIMER_0_8253,al ;load count msb
;
; Restore the context and return.
;
MPOPF ;keeps interrupts off
pop ax
ret
ZTimerOn endp
;********************************************************************
;* Routine called to stop timing and get count. *
;********************************************************************
ZTimerOff proc near
;
; Save the context of the program being timed.
;
push ax
push cx
pushf
;
; Latch the count.
;
mov al,00000000b ;latch timer 0
out MODE_8253,al
;
; See if the timer has overflowed by checking the 8259 for a pending
; timer interrupt.
;
mov al,00001010b ;OCW3, set up to read
out OCW3,al ; Interrupt Request register
DELAY
in al,IRR ;read Interrupt Request
; register
and al,1 ;set AL to 1 if IRQ0 (the
; timer interrupt) is pending
mov cs:[OverflowFlag],al ;store the timer overflow
; status
;
; Allow interrupts to happen again.
;
sti
;
; Read out the count we latched earlier.
;
in al,TIMER_0_8253 ;least significant byte
DELAY
mov ah,al
in al,TIMER_0_8253 ;most significant byte
xchg ah,al
neg ax ;convert from countdown
; remaining to elapsed
; count
mov cs:[TimedCount],ax
; Time a zero-length code fragment, to get a reference for how
; much overhead this routine has. Time it 16 times and average it,
; for accuracy, rounding the result.
;
mov cs:[ReferenceCount],0
mov cx,16
cli ;interrupts off to allow a
; precise reference count
RefLoop:
call ReferenceZTimerOn
call ReferenceZTimerOff
loop RefLoop
sti
add cs:[ReferenceCount],8 ;total + (0.5 * 16)
mov cl,4
shr cs:[ReferenceCount],cl ;(total) / 16 + 0.5
;
; Restore original interrupt state.
;
pop ax ;retrieve flags when called
mov ch,cs:[OriginalFlags] ;get back the original upper
; byte of the FLAGS register
and ch,not 0fdh ;only care about original
; interrupt flag...
and ah,0fdh ;...keep all other flags in
; their current condition
or ah,ch ;make flags word with original
; interrupt flag
push ax ;prepare flags to be popped
;
; Restore the context of the program being timed and return to it.
;
MPOPF ;restore the flags with the
; original interrupt state
pop cx
pop ax
ret
ZTimerOff endp
;
; Called by ZTimerOff to start timer for overhead measurements.
;
ReferenceZTimerOn proc near
;
; Save the context of the program being timed.
;
push ax
pushf ;interrupts are already off
;
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
; linear counting rather than count-by-two counting.
;
mov al,00110100b ;set up to load
out MODE_8253,al ; initial timer count
DELAY
;
; Set the timer count to 0.
;
sub al,al
out TIMER_0_8253,al ;load count lsb
DELAY
out TIMER_0_8253,al ;load count msb
;
; Restore the context of the program being timed and return to it.
;
MPOPF
pop ax
ret
ReferenceZTimerOn endp
;
; Called by ZTimerOff to stop timer and add result to ReferenceCount
; for overhead measurements.
;
ReferenceZTimerOff proc near
;
; Save the context of the program being timed.
;
push ax
push cx
pushf
;
; Latch the count and read it.
;
mov al,00000000b ;latch timer 0
out MODE_8253,al
DELAY
in al,TIMER_0_8253 ;lsb
DELAY
mov ah,al
in al,TIMER_0_8253 ;msb
xchg ah,al
neg ax ;convert from countdown
; remaining to amount
; counted down
add cs:[ReferenceCount],ax
;
; Restore the context of the program being timed and return to it.
;
MPOPF
pop cx
pop ax
ret
ReferenceZTimerOff endp
;********************************************************************
;* Routine called to report timing results. *
;********************************************************************
ZTimerReport proc near
pushf
push ax
push bx
push cx
push dx
push si
push ds
;
push cs ;DOS functions require that DS point
pop ds ; to text to be displayed on the screen
assume ds:Code
;
; Check for timer 0 overflow.
;
cmp [OverflowFlag],0
jz PrintGoodCount
mov dx,offset OverflowStr
mov ah,9
int 21h
jmp short EndZTimerReport
;
; Convert net count to decimal ASCII in microseconds.
;
PrintGoodCount:
mov ax,[TimedCount]
sub ax,[ReferenceCount]
mov si,offset ASCIICountEnd - 1
;
; Convert count to microseconds by multiplying by .8381.
;
mov dx,8381
mul dx
mov bx,10000
div bx ;* .8381 = * 8381 / 10000
;
; Convert time in microseconds to 5 decimal ASCII digits.
;
mov bx,10
mov cx,5
CTSLoop:
sub dx,dx
div bx
add dl,'0'
mov [si],dl
dec si
loop CTSLoop
;
; Print the results.
;
mov ah,9
mov dx,offset OutputStr
int 21h
;
EndZTimerReport:
pop ds
pop si
pop dx
pop cx
pop bx
pop ax
MPOPF
ret
ZTimerReport endp
Code ends
end 以下是《图形程序开发人员指南》对8253的说明,与《汇编语言、设计与接口技术》一致:
Quote: | The 8253 actually contains three timers, as shown in Figure 3.1. All three timers are driven by the system board’s 14.31818 MHz crystal, divided by 12 to yield a 1.19318 MHz clock to the timers, so the timers count once every 838.1 ns. Each of the three timers counts down in a programmable way, generating a signal on its output pin when it counts down to 0. Each timer is capable of being halted at any time via a 0 level on its gate inputw; hen a timer’s gate input is 1, that timer counts constantly. All in all, the 8253’s timers are inherently very flexible timing devices; unfortunately, much of that flexibility depends on how the timers are connected to external circuitry, and in the PC the timers are connected with specific purposes in mind. |
|
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-6-3 14:27 |
|
|
jawbin
高级用户
积分 994
发帖 444
注册 2005-1-29
状态 离线
|
『第
4 楼』:
在通常的使用中,我就当是 18 次,没要求那么精密过. 可以设置成更高频率的( UCOS/II 好象就更改了),但是好象影响性能.
|
|
2006-6-8 19:29 |
|
|
fqljwdyq
新手上路
积分 14
发帖 7
注册 2006-2-18 来自 江苏
状态 离线
|
『第
5 楼』:
其实在实际应用当中,精确定时从来不用系统提供的8253,一般用扩展卡中的定时,对系统的这个18.2秒不是太关心
|
|
2006-6-9 08:15 |
|
|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『第
6 楼』:
但是我想在DOS下实现毫秒级定时啊!
是为了编动画、游戏程序
不可能希望别人装扩展卡
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-6-9 09:02 |
|
|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『第
7 楼』:
我的目的是:编写类似Win32 API——QueryPerformanceFrequency、QueryPerformanceCounter——那样的函数来实现高精度计时
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-6-9 09:08 |
|
|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『第
8 楼』:
菜菜的问一下:
TSC、ACPI是什么东西?
怎么利用它们来计时?
ACPI貌似是那个高级电源管理,它也有计时功能?昏,现在硬件接口资料真的好难找
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-6-9 09:14 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
9 楼』:
TSC是奔腾及以上处理器新增的一个64bit的register,在每个CPU基础时钟,该计数器会自动增一(基础时钟是指:流水的stage)。TSC可以使用RDTSC指令读取。
Win32API 中的 QueryPerformanceCounter 确实应该是使用了 TSC,一是它的精度很高,二是MSDN也说了这个API使用了某些硬件相关的特性,在一些CPU上可能不支持。
TSC主要的设计用意是 profiling,在大多数情况下,用它做计时是不合适的,主要是开销较高。
大多数情况下,8253本身最高可以工作在纳秒级的精度上。这个精度对于绝大部分应用来说应该是足够了,但是包括Windows在内的任何操作系统通常不可能让自己的工作粒度保持在这个频率,这会使操作系统本身的维护性开销过大。
再加上Windows处理中断的时候,为了进一步降低开销,还专门使用了DPC机制,所以NT系列的Windows客户端产品的Timer粒度一般在10ms~15ms,服务器产品的粒度一般在15ms~30ms。
通过Windows Native API(不是Win32 API):NtSetTimerResolution,可以改变系统的工作粒度。不过,这个改变会影响当前系统的所有进程,而且不恰当的设置可能会增加系统的管理负担。
更为不爽的是,有迹向表明这个设置很可能也影响系统内核的工作状态,例如:线程调度、阻塞事件和异步IO状态查询等等,调整这个值也相应的增加了这些工作的频率,导致系统性能进一步下滑。
|
|
2006-6-9 13:05 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
|
2006-6-9 13:14 |
|
|
zyl910
中级用户
积分 282
发帖 126
注册 2006-5-17
状态 离线
|
『第
11 楼』:
昏
原来TSC是指RDTSC
平时没注意其缩写
非常感谢asbai兄
现在硬件接口编程资料真的好难找
想在DOS下编写一个精确点的计时函数都好麻烦
|
人类存在的目的就是试图理解人类为何存在 |
|
2006-6-10 12:56 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
『第
12 楼』:
Quote: | Originally posted by zyl910 at 2006-6-10 12:56:
昏
原来TSC是指RDTSC
平时没注意其缩写
非常感谢asbai兄
现在硬件接口编程资料真的好难找
想在DOS下编写一个精确点的计时函数都好麻烦 |
|
zyl910兄太客气了,现在硬件资料确实不好找,Intel和AMD发布的x86开发者手册既权威又详细(特别是AMD的),应该是首选资料来源。其它的还有一个网站:http://www.powernet.co.za/info/index.htm,速度虽然慢点,但是资料蛮全的。
俺就知道这么多了,各位兄台有什么好去处,拿出来share一下。
|
|
2006-6-10 14:16 |
|
|