윈도 우즈 에서 밀리초 까지 정확 한 시계 가 직면 한 문제 와 해결 방법 을 실현 하 다

8777 단어 windows
질문 1: 15ms 에서 GetSystemTime / GetLocalTime (자바 에 대응 하 는 함 수 는 System. currentTimeMillis ()) 를 여러 번 호출 하여 같은 값 으로 되 돌려 줍 니 다.
해결 방법 은 GetSystemTime 을 baseline 으로 사용 한 다음 windows 가 제공 하 는 고밀도 타이머 Query PerformanceCounter (자바 에 해당 하 는 함 수 는 System. nanoTime () 로 시간 을 계산 하고 정확 한 시 계 는 baseline + 타이머 시간 입 니 다.
질문 2: Query PerformanceCounter / Query PerformanceFrequency 의 질문
이 문 제 는 주로 windows Query PerformanceCounter 와 의 실현 에 달 려 있다. 초기의 실현 은 the CPU - level timestamp - counter (TSC) 를 사용 하 는 것 이 었 다. tick count 는 서로 다른 핵 에서 의 값 차이 가 비교적 크기 때문에 이 타 이 머 를 사용 하여 계산 한 값 은 전혀 예측 할 수 없 었 다. 초기 에 비교적 간단 한 해결 방법 은 특정한 스 레 드 에서 만 타 이 머 를 사용 하 는 것 이 었 다.그리고 이 스 레 드 를 핵 에 묶 습 니 다. (그러나 자바 의 스 레 드 는 cpu affinity 를 설정 할 수 없습니다)
windows xp sp2 와 windows server 2003 sp2 및 이후 시스템 에 서 는 Query Performance Counter 를 사용 하여 power management timer PMTimer 를 선택 할 수 있 습 니 다. boot. ini 에 / usepmtimer 옵션 을 추가 하여 Query Performance Counter 의 실현 방식 을 설정 할 수 있 습 니 다. PMTimer 는 메인보드 의 타 이 머 를 사용 하기 때문에 다 핵 동기 화 문제 가 없습니다.
 요약: 1. Query PerformanceFrequency 의 반환 값 (매개 변수) 을 검사 합 니 다.
   반환 값 = 3, 579, 545 는 현재 시스템 에서 PMTimer 를 사용 합 니 다.  --> step 3
   반환 값 = CPU 주파수, 시스템 사용 TSC  --> step 2 
2. 운영 체제 가 windows xp sp2 / windows server 2003 sp2 or later 라면 c: \ boot. ini 에 인자 / usepmtimer 를 추가 하고 시스템 을 다시 시작 합 니 다.
 
3. GetSystem Time + QueryPerformanceCounter 를 사용 하여 정확 한 시계 참 조 를 실현 합 니 다. 
---------------------------------------------------------------------------------
 
http://msdn.microsoft.com/zh-cn/windows/hardware/gg463347
 
http://support.microsoft.com/kb/833721
http://support.microsoft.com/kb/895980
http://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks
 
Windows use of clocks and timers varies considerably from platform to platform and is plagued by problems - again this isn't necessarily Window's fault, just as it wasn't the VM's fault: the hardware support for clocks/timers is actually not very good - the references at the end lead you to more information on the timing hardware available. The following relates to the "NT" family (win 2k, XP, 2003) of Windows.
There are a number of different "clock" API's available in Windows. Those used by Hotspot are as follows:
  • System.currentTimeMillis() is implemented using the GetSystemTimeAsFileTime method, which essentially just reads the low resolution time-of-day value that Windows maintains. Reading this global variable is naturally very quick - around 6 cycles according to reported information. This time-of-day value is updated at a constant rate regardless of how the timer interrupt has been programmed - depending on the platform this will either be 10ms or 15ms (this value seems tied to the default interrupt period).
  • System.nanoTime() is implemented using the QueryPerformanceCounter/QueryPerformanceFrequency API (if available, else it returns currentTimeMillis\*10\^6). QueryPerformanceCounter(QPC) is implemented in different ways depending on the hardware it's running on. Typically it will use either the programmable-interval-timer (PIT), or the ACPI power management timer (PMT), or the CPU-level timestamp-counter (TSC). Accessing the PIT/PMT requires execution of slow I/O port instructions and as a result the execution time for QPC is in the order of microseconds. In contrast reading the TSC is on the order of 100 clock cycles (to read the TSC from the chip and convert it to a time value based on the operating frequency). You can tell if your system uses the ACPI PMT by checking if QueryPerformanceFrequency returns the signature value of 3,579,545 (ie 3.57MHz). If you see a value around 1.19Mhz then your system is using the old 8245 PIT chip. Otherwise you should see a value approximately that of your CPU frequency (modulo any speed throttling or power-management that might be in effect.) The default mechanism used by QPC is determined by the Hardware Abstraction layer(HAL), but some systems allow you to explicitly control it using options in boot.ini, such as /usepmtimer that explicitly requests use of the power management timer. This default changes not only across hardware but also across OS versions. For example Windows XP Service Pack 2 changed things to use the power management timer (PMTimer) rather than the processor timestamp-counter (TSC) due to problems with the TSC not being synchronized on different processors in SMP systems, and due the fact its frequency can vary (and hence its relationship to elapsed time) based on power-management settings. (The issues with the TSC, in particular for AMD systems, and how AMD aims to provide a stable TSC in future processors is discussed in Rich Brunner's article referenced below. You can also read how the Linux kernel folk have abandoned use of the TSC until a new stable version appears in CPUs.)

  • The timer related API's for doing timed-waits all use the waitForMultipleObjects API as previously mentioned. This API only accepts timeout values in milliseconds and its ability to recognize the passage of time is based on the timer interrupt programmed through the hardware.
    Typically a Windows machine has a default 10ms timer interrupt period, but some systems have a 15ms period. This timer interrupt period may be modified by application programs using the timeBeginPeriod/timeEndPeriod API's. The period is still limited to milliseconds and there is no guarantee that a requested period will be supported. However, usually you can request a 1ms timer interrupt period (though its accuracy has been questioned in some reports). The hotspot VM in fact uses this 1ms period to allow for higher resolution Thread.sleep calls than would otherwise be possible. The sample Sleeper.java will cause this higher interrupt rate to be used, thus allowing experimentation with a 1ms versus 10ms period. It simply calls Thread.sleep(Integer.MAX_VALUE) which (because it is not a multiple of 10ms) causes the VM to switch to a 1ms period for the duration of the sleep - which in this case is "forever" and you'll have to ctrl-C the "java Sleeper" execution.
     public class Sleeper {   public static void main(String[] args) throws Throwable {     Thread.sleep(Integer.MAX_VALUE);   } } 

    You can see what interrupt period is being used in Windows by running the perfmon tool. After you bring it up you'll need to add a new item to watch (click the + icon above the graph - even if it appears grayed/disabled). Select the interrupts/sec items and add it. Then right click on interrupts/sec under the graph and edit its properties. On the "data" tab, change the "scale" to 1 and on the graph tab, the vertical max to be 1000. Let the system settle for a few seconds and you should see the graph drawing a steady line. If you have a 10ms interrupt then it will be 100, for 1ms it will be 1000, for 15ms it will be 66.6, etc. Note: on a multiprocessor system show the interrupts/sec for each processor individually, not the total - one processor will be fielding the timer interrupts.
    Note that any application can change the timer interrupt and that it affects the whole system. Windows only allows the period to be shortened, thus ensuring that the shortest requested period by all applications is the one that is used. If a process doesn't reset the period then Windows takes care of it when the process terminates. The reason why the VM doesn't just arbitrarily change the interrupt rate when it starts - it could do this - is that there is a potential performance impact to everything on the system due to the 10x increase in interrupts. However other applications do change it, typically multi-media viewers/players. Be aware that a browser running the JVM as a plug-in can also cause this change in interrupt rate if there is an applet running that uses the Thread.sleep method in a similar way to Sleeper.
    Further note, that after Windows suspends or hibernates, the timer interrupt is restored to the default, even if an application using a higher interrupt rate was running at the time of suspension/hibernation.
     
     

    좋은 웹페이지 즐겨찾기