이 문서는 CPU의 정확한 클럭을 구하는 내용을 포함하고 있습니다.
Intel 계열의 CPU에는 Time Stamp Clock이라는 것이 존재합니다. 줄여서 TSC라고 부르죠. 64bit로 구성된 TSC의 역할은 CPU가 클럭을 받을때마다 1씩 증가하는 일을 합니다. 따라서 특정 시간안의 이 TSC의 변화량을 측정하게 되면 그것을 CPU의 클럭 수로 사용할 수 있습니다.
TSC를 구하는 윈도우 API가 존재하지 않기 때문에, 직접 어셈블리어로 구현을 하는 방법 외에는 없습니다. 아래는 TSC를 읽는 ReadTSC함수를 보여주고 있습니다. dwLo는 TSC의 하위 32bit를, dwHi는 상위 32bit를 저장해서 돌려주게 됩니다.
많은 구형 컴파일러의 경우 rdtsc라는 CPU 명령어를 인식하지 못합니다. 따라서 아래는 rdtsc의 OP코드인 0x0f, 0x31을 넣어서 명령을 수행하고 있습니다. VC++ .net 버전에서는 0x0f, 0x31 두 줄을 rdtsc 명령어로 대체하여도 재대로 컴파일이 됩니다.
VOID CCpuInfo::ReadTSC(DWORD \*dwLo, DWORD \*dwHi)
{
\_asm
{
\_emit 0x0F
\_emit 0x31
mov ecx, dword ptr dwLo
mov dword ptr[ecx], eax
mov ecx, dword ptr dwHi
mov dword ptr[ecx], edx
}
}
이제 CPU의 클럭 변화량을 측정할 준비는 다 되었습니다. 다음으로 필요한 것은 정확한 시간을 재는 것입니다. 클럭의 변화량을 정확한 시간으로 나누어야 제대로된 클럭 수를 구할 수 있기 때문이죠. 윈도우에서 이렇게 가장 정밀한 시간을 계산할 수 있는 방법으로는 고해상도 타이머를 쓰는 방법이 있습니다. 이 고해상도 타이머는 특정 주기에 따라서 값이 변하게 됩니다. 마치 CPU의 TSC와 동일한 역할을 하는 놈이죠.
QueryPerformanceFrequency는 고해상도 타이머의 주기를 구하는 함수입니다. 즉, 초당 몇번 타이머가 증가하는가를 구하는 함수죠. QueryPerformanceCounter는 현재의 고해상도 타이머를 구하는 함수입니다.
그러면 이제 우리는 다음과 같은 수식을 통해서 CPU의 클럭 수를 계산할 수 있습니다.
고해상도 타이머 주기 : 고해상도 타이머 변화량 = CPU 클럭 : TSC 변화량
비례식을 돌려서 곱하고 나누고 하면 CPU 클럭이라는 미지 항이 풀리게 되겠죠. 아래는 CPU 클럭을 Hz단위로 반환해 주는 함수입니다.
ULONGLONG CCpuInfo::GetClockHz()
{
LARGE\_INTEGER PerfCt, OldPerfCt, PerfFreq;
ULARGE\_INTEGER Cycle,OldCycle,ClockHz;
QueryPerformanceFrequency(&PerfFreq);
QueryPerformanceCounter(&OldPerfCt);
ReadTSC(&OldCycle.LowPart, &OldCycle.HighPart);
Sleep ( m\_nWaitMs );
QueryPerformanceCounter(&PerfCt);
ReadTSC(&Cycle.LowPart, &Cycle.HighPart);
ClockHz.QuadPart = (ULONGLONG) (Cycle.QuadPart - OldCycle.QuadPart);
ClockHz.QuadPart = (ULONGLONG) (ClockHz.QuadPart \* PerfFreq.QuadPart)
/ (PerfCt.QuadPart - OldPerfCt.QuadPart);
return ClockHz.QuadPart;
}
참고사이트