• 타이머의 해상도

    2014. 12. 31.

    by. xxx123

     

     

     

    1. 해상도란?

     

    모든 함수들은 시간을 측정하기 위한 자기 나름대로의 Tick 계산 법이 있고,

    1분을 기준으로 얼마나 많은 프레임으로 쪼개냐. 즉 1분동안 얼마나 많은 Tick으로 쪼개서 표현하고자 하는 시간의 정확도를 높이느냐가 고해상도냐 저해상도냐를 판단하는 것이 된다.

     

    여기서 저해상도는 0.1 minute의 해상도를 갖는다고 할수 있고 고해상도는 0.05minute의 해상도를 갖는다고 할 수 있다.

     

     

     

    2. GetTickCount()

     

    kernel.dll에 존재하며 시스템이 시작된 이후. 즉 커널이 부팅된 이후부터의 경과 시간을 millisecond 단위로 나타내준다.

    시스템 타이머의 해상도에 따라 GetTickCount()의 해상도가 제한되며, 일반적으로 10~16 milliseconds의 해상도를 갖는다.

     

    해당 시간은 DWORD 형으로 저장되며 이것은 49.7일 후면 해당 변수의 MAX치를 넘게 되어 0으로 값이 바뀌게 된다.

    이것을 Wrap-around라고 한다.

    이 현상을 피하기 위해서 GetTickCount64() 함수를 사용하거나 오버플로어 체크를 해서 처리해주는 부분을 넣어야한다.

    GetTickCount64() 함수의 경우 부호 없는 64bit 정수 값을 반환하므로 더 오랜 시간 MAX치를 넘지 않고 버틸 수 있다.

    하지만 이는 Windows Vista 또는 Windows Server 2008 이후 버전에서만 사용 가능하다.

    참고로  SetTimer도 시스템 타이머에 해당하며 호출에 의한 시스템 마비 현상을 없애기 위해 주어진 시간에 단 하나의 타이머 메세지(WM_TIMER)만을 받고 나머지는 무시 해버리는 단점이 있다.

    또한 WM_TIMER 메세지가 WM_PAINT 메세지를 제외한 다른 메세지 보다 우선순위가 낮기 때문에 원래 정해진 시간과는 다소 오차가 발생한다. 

    메세지 기반이기 때문에 콘솔에서는 당연 사용할 수 도 없다.

    SetTimer는 TimeGetTime()과 많이 비교되어 설명되기도 한다.

     

     

     

     

    3. timeGetTime()

    멀티미디어 타이머에 영향을 받으며 머신에 따라 디폴트 해상도가 다르지만 보통 5ms이상의 해상도를 갖는다.

    timeBeginPeriod, timeEndPeriod 함수를 이용해 정밀도를 조정할 수 있으며, 최대 1ms까지 얻을 수 있다.

    멀티미디어 라이브러리인 winmm.lib를 필요로 한다.

    하지만 이 역시도 INT_MAX 범위를 넘어가면 Wrap-around 문제가 발생하게 된다.

     

     

     

     

    4. QueryPerformanceCounter()

     

    ① 설명

    QPC의 경우 RDTSC(Read Time Stamp Counter)를 사용 할 수도 있지만 메인보드의 타이머 디바이스나 고정밀도의 타이머 정보를 제공하는 다른 시스템 서비스를 사용할 수도 있다. 그것들을 이용해서 QPC는 고해상도의 타이머를 제공한다.

    QPC는 일단 API 함수 호출이므로 RDTSC에 비해서 훨씬 느리다.

    그렇지만 이 API를 한 프레임에 수백번 호출해도 특별한 성능저하는 일어나지 않는다.

     

     

    ② 함수 및 변수

    -  LARGE_INTEGER 타입

    이 타입은 공용체(union)으로 만들어져 있으며 64비트 정수형 데이터를 저장하기위해 만들어졌다.

    만약 컴파일러가 64비트를 지원할 때에는 공용체에 선언된 QuadPart라는 64비트 정수형 변수에다사 측정값을 저장하고,

    32비트만 지원되는 경우에는 LowPart와 HightPart라는 32비트 정수형 변수에 64비트 측정값을 나누어 저장한다.

     

    - QueryPerformanceFrequency(LARGE_INTEGER *p)

    고해상도 타이머의 초당 진동(틱)수를 반환한다.

    타이머가 지원되지 않을 경우에는 p가 0값을 반환한다.

     

    - QueryPerformanceCounter(LARGE_INTEGER *p)

    고해상도 타이머의 현재 값을 얻는 함수.

    타이머가 지원되지 않을 경우에는 p가 0값을 반환한다.

     

     

     주의점

     

    - RDTSC와 마찬가지로 멀티코어/멀티프로세서에서는 코어간의 사이클 카운터가 동기화 되지 않는다. 

    BIOS나 HAL 레이어의 버그로 인해 프로세서간 서로 다른 값을 넘기는 경우가 있기 때문이다.

    그러므로 하나의 스레드에서 수행하고 해당 스레드를 하나의 프로세서에 고정시켜야한다.(SetThreadAffinityMast 함수이용)

     

    - 인텔 네할렘 계역 CPU에는 터보부스터 기능이 있는데. 이 기능이 각 코어의 주파수를 맘대로 바꾸어 버린다.

    즉, 시작할 때 CPU 주파수 값과 나중 CPU 주파수 값이 다르다는것.

    하지만 이 문제는 windows7부터는 사라졌다고한다.

     

     

     

    5. 정리

    ① 해상도의 순서는 GetTickCount < timeGetTime < QueryPerformanceCounter 이다.

     

    ② GetTickCount,timeGetTime은 경과한 밀리 세컨드 값을 반환하며, QPC는 경과한 틱값을 반환한다. 그래서  QPC의 경우 초당 틱수로 나누어서 경과시간을 도출해 내야한다.

     

    ③ QPC는 멀티코어에 안전하지 않다. 그래서 한 스레드에서만 사용하고 해당 스레드는 하나의 프로세서에 고정시켜야한다.

     

     

     

     

     

     

     

     

     

     

     

     

    [참고]

    http://sweeper.egloos.com/2820035

    http://msdn.microsoft.com/ko-kr/library/windows/desktop/ms724408(v=vs.85).aspx      // MSDN GetTickCount

    http://msdn.microsoft.com/ja-jp/library/ee417693%28v=VS.85%29.aspx                // QPC 문제 MSDN

    http://msdn.microsoft.com/en-us/library/ms644904

     

    'Programming > System' 카테고리의 다른 글

    Lock-free VS Wait-free  (0) 2016.10.19
    ABA Problem  (0) 2016.10.19
    SSE (Streaming SIMD eXtensions)  (0) 2014.07.23

    댓글