코드의 수행시간 체크하기

Jooss·2023년 8월 16일
0

cpp

목록 보기
3/7
post-custom-banner

2021-04-16 github.io에서 작성

C++ 작업을 진행하다 보면 내가 만든 코드의 수행시간이 얼마나 될지 체크해야하는 경우가 생깁니다. 프로그램이 더 빨리 혹은 긴밀하게 연계되어 돌아가는 코드에서는 더욱더 이러한 수행시간을 체크하는것이 중요해집니다.

Windows OS에는 다양한 Time Check 방법들이 존재합니다.

  • clock_t
  • GetTickCount()
  • timeGetTime()
  • chrono::system_clock::now()
  • QueryPerformenceCounter

하나하나 정리하며 추가로 알게 된 정보에 대해서는 아래에 더 추가하도록 하겠습니다.

기본적으로 모든 함수들을 0.1ms, 5ms, 20ms, 100ms, 1000ms 다섯가지 방법으로 10번 반복하여 정리하도록 하겠습니다.
코드의 수행시간을 체크하려면 수행시간동안 딜레이를 줄 함수가 필요합니다. 이번 실험에서는 chrono함수를 이용하여 nanosecond~second의 딜레이를 주었습니다. 딜레이 함수에 대해서는 따로 포스팅해보독 할게요.

결과 정리


GetTickCount: Win32 기본 API로 헤더파일 추가 필요 없이 동작하는 Time Check 함수입니다. OS의 Interrupt Request에 영향을 받으므로 msdn에 따르면 10ms ~ 16ms정도의 resolution을 가진다고 합니다. IRQ는 약 15.625ms로 동작하는 내부 Interrupt 입니다. Return type이 DWORD라서 49.7일까지밖에 체크가 불가능합니다. 대체 함수로 GetTickCount64가 있습니다.

timeGetTime: 윈도우가 시작되어서 지금까지 흐른 시간을 ms단위로 리턴하는 함수입니다. 이 함수를 사용하기 위해서는 windows.hWinmm.lib를 추가해야 합니다(코드설명 참조). 이 함수의 기본 정밀도는 5ms이며 timeBeginPeriodtimeEndPeriod를 사용하여 정밀도를 올릴 수 있습니다. return type이 GetTickCount와 같이 DWORD이라 49.7일까지 측정 가능합니다. msdn 에 따르면 더 정밀하게 측정하려면 QueryPerformanceCounter함수를 사용하여야 합니다.

clock_t: CRT(Universal C runtime library) 초기화 이후 경과된 시간으로 Wall clock을 알려줍니다. msdn에 따르면 이 함수는 ISO C를 엄격하게 준수하지 않으며 순수 CPU시간을 반환값으로 지정합니다. 경과된 시간을 확인하려면 CLOCK_PER_SEC으로 나누어야 합니다. 최대 clock반환 값인 약 24.8일까지 표현가능하고 그 이상일 경우에는 64비트 시간함수 또는 Queryperformancecounter함수를 사용하라고 나와 있습니다.

system_clock::now: C++11에서 추가된 C++ 언어 레벨에서의 time check 함수입니다. 다른 시간 함수들은 Windows에서 제공하는 API인 반면에 chrono는 OS에 영향을 받지 않고 사용 할 수 있습니다. 그 정확도도 매우 높은편입니다.

QueryPerformanceCounter : windows.h헤더에 추가된 API입니다. performance counter의 현재 value를 리턴하면서 1us 이하의 high resolution을 보장합니다(MSDN). 메인보드에 고성능 타이머를 이용하여 카운팅해서 고성능을 보장 할 수 있습니다. QueryPerformanceFrequency를 통해서 메인보드 타이머의 주파수를 알아내고 QueryPerformanceCounter를 사용하여 CPU의 클럭 수를 받습니다.

함수 별 수행시간 체크


  • GetTickCount가 0 or 16ms인 것이 눈에 띕니다. IRQ에 영향을 받아 시간 분해능(Resolution)이 16ms가량 되는 것을 알 수 있습니다.
수행시간 0.1ms1회2회3회4회5회6회7회8회9회10회
clock_t2ms2ms2ms2ms1ms2ms2ms3ms2ms2ms
GetTickCount()0ms0ms0ms0ms0ms0ms16ms0ms0ms0ms
timeGetTime()1ms3ms2ms2ms1ms2ms2ms2ms2ms2ms
system_clock::now()1.39ms1.94ms1.58ms1.70ms1.70ms1.56ms1.72ms1.57ms1.62ms1.69ms
QueryPerformenceCounter1.89ms1.64ms1.71ms1.72ms1.71ms1.60ms1.43ms1.64ms1.53ms1.67ms
수행시간 1ms1회2회3회4회5회6회7회8회9회10회
clock_t2ms2ms1ms2ms1ms2ms2ms2ms1ms2ms
GetTickCount()0ms0ms15ms0ms0ms0ms0ms0ms0ms0ms
timeGetTime()1ms2ms2ms2ms2ms2ms2ms1ms2ms2ms
system_clock::now()1.50ms1.59ms1.46ms1.39ms1.07ms1.33ms1.57ms1.51ms1.37ms1.39ms
QueryPerformenceCounter2.31ms1.42ms1.91ms1.31ms1.38ms1.49ms1.52ms1.69ms1.49ms1.42ms
수행시간 5ms1회2회3회4회5회6회7회8회9회10회
clock_t5ms6ms5ms6ms6ms6ms6ms6ms6ms6ms
GetTickCount()15ms0ms16ms0ms0ms15ms0ms0ms16ms0ms
timeGetTime()6ms5ms7ms5ms6ms6ms5ms6ms6ms6ms
system_clock::now()6.14ms5.03ms5.51ms5.82ms5.88ms5.18ms6.01ms5.13ms5.25ms5.11ms
QueryPerformenceCounter5.93ms5.76ms5.40ms5.44ms5.79ms5.07ms5.89ms5.66ms5.04ms5.82ms
수행시간 20ms1회2회3회4회5회6회7회8회9회10회
clock_t21ms21ms21ms20ms21ms20ms21ms21ms21ms20ms
GetTickCount()32ms15ms31ms16ms16ms31ms16ms15ms15ms16ms
timeGetTime()20ms20ms21ms21ms21ms21ms21ms21ms22ms20ms
system_clock::now()20.35ms20.67ms20.84ms20.97ms20.96ms20.21ms20.93ms20.14ms20.37ms20.45ms
QueryPerformenceCounter20.51ms20.89ms20.17ms20.49ms20.56ms20.93ms20.67ms20.03ms20.94ms20.65ms
수행시간 100ms1회2회3회4회5회6회7회8회9회10회
clock_t101ms101ms100ms101ms101ms101ms101ms101ms101ms100ms
GetTickCount()109ms94ms109ms94ms109ms94ms109ms94ms109ms94ms
timeGetTime()101ms101ms101ms101ms101ms101ms100ms101ms100ms101ms
system_clock::now()100.41ms100.30ms100.21ms100.19ms100.26ms100.17ms101.26ms100.89ms100.43ms100.93ms
QueryPerformenceCounter100.33ms100.38ms100.07ms100.98ms100.79ms100.41ms100.53ms100.23ms100.70ms100.35ms
수행시간 1000ms1회2회3회4회5회6회7회8회9회10회
clock_t1000ms1001ms1001ms1001ms1001ms1001ms1000ms1001ms1001ms1000ms
GetTickCount()1000ms1016ms1000ms1000ms1000ms1000ms1000ms1000ms1000ms1000ms
timeGetTime()1000ms1000ms1002ms1002ms1001ms1001ms1002ms1001ms1001ms1002ms
system_clock::now()1000.76ms1001.05ms1000.46ms1000.64ms1001.29ms1000.79ms1000.34ms1001.06ms1000.28ms1000.51ms
QueryPerformenceCounter1000.85ms1002.72ms1000.76ms1000.60ms1000.43ms1001.16ms1007.37ms1000.64ms1001.13ms1000.44ms
  • 사실상 수행시간이 1s단위까지 오게 되면 모든 시간 함수들의 time check 능력이 크게 차이나지 않습니다.

clock_t 함수

int micro_sec = 1000;
cout << "Coock_t time check" << endl;
int i = 10;
while (i-- > 0)
{
    clock_t start = clock();
    this_thread::sleep_for(chrono::microseconds(micro_sec));
    clock_t end = clock();

    cout << (end - start) << "ms\t";
}
cout << endl;

GetTickCount() 함수

중복되는부분을 제외하고 반복문 안에만 표현하겠습니다.

auto start = GetTickCount();
this_thread::sleep_for(chrono::microseconds(micro_sec));
auto end = GetTickCount();

cout << (end - start) << "ms\t";

timeGetTime() 함수

auto start = timeGetTime();
this_thread::sleep_for(chrono::microseconds(micro_sec));
auto end = timeGetTime();

cout << (end - start) << "ms\t";

system_clock::now() 함수

auto start = chrono::system_clock::now();
this_thread::sleep_for(chrono::microseconds(micro_sec));
auto end = chrono::system_clock::now();

chrono::microseconds delta = chrono::duration_cast<chrono::microseconds>(end - start);
cout << fixed;
cout.precision(2);
cout << delta.count()/1000.0 << "ms\t";

QueryPerformenceCounter 함수

LARGE_INTEGER freq, start, end;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
this_thread::sleep_for(chrono::microseconds(micro_sec));
QueryPerformanceCounter(&end);

double delta = static_cast<double>((end.QuadPart - start.QuadPart) / (freq.QuadPart / 1000.0));
cout << fixed;
cout.precision(2);
cout << delta << "ms\t";

Reference

profile
개발자 세상을 여행중인 히치하이커입니다.
post-custom-banner

0개의 댓글