Spaurh의 느긋한 블로그



Windows에서 gettimeofday() 함수 사용하기 Programming Tip

리눅스 프로그램을 가끔 포팅하다 보면 win32 버전으로 맞춰주지 않는 부분들이 많다.
그런 부분에서 가장 많이 띄는게 gettimeofday()함수일 것이다.
목차
1 gettimeofday in linux
2 gettimeofday in windows
2.1 Approach to gettimeofday in windows
2.2 code of gettimeofday in windows
2.3 usage of gettimeofday in windows
3 gettimeofday를 이용한 실행 시간 구하기
4 gettimeofday와 이 것을 이용한 전체 코드
5 References
1 gettimeofday in linux #
gettimeofday()는 아래 signature와 값이 system의 현재 시간을 가지고 온다.
#include <sys/time.h>
#include <unistd.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
첫 번째 인자는 다음과 같이 seconds와 microseconds를 가지고 있다. 즉, 현재 시간을 초와 마이크로초로 알 수 있는 유용한 api이다.
struct timeval
{
    long tv_sec;       // 초
    long tv_usec;      // 마이크로초
}
//
그리고 두 번째 인자는 쓰이지 않으면 NULL을 던져 주면 될 것이다.
[edit]
2 gettimeofday in windows #
[edit]
2.1 Approach to gettimeofday in windows #
Windows에는 gettimeofday()가 없다. 하지만 GetSystemTimeAsFileTime()을 이용해서 gettimeofday()를 만들 수 있다.
GetSystemTimeAsFileTime()은 다음과 같은 Signature를 가지고 현재 system의 date와 time을 Universal Time (UTC) format으로 반환해준다.
VOID GetSystemTimeAsFileTime(
  LPFILETIME lpSystemTimeAsFileTime  // file time
);
//
out parameter는 FILETIME struct로 다음과 같이 32bit 하위 bit와 32bit 상위 bit를 가지고 있다. 시간은 64bit 값으로 100 nanosecond단위이다.
typedef struct _FILETIME {
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME, *PFILETIME;
//
이 것을 FileTimeToSystemTime()을 이용해서 SYSTEMTIME으로 변경해서 사용하기도 할 것이다.
아무튼 windows에서 gettimeofday()를 만들기 위해서 우리는 다음과 같은 step을 따르면 될 것이다.
GetSystemTimeAsFileTime()으로 system time을 구한다.
구한 시간인 FILETIME을 64bit로 합친다. (unsigned __int64)
UNIX EPOCH time으로 변환한다. (웹을 검색해보면 쉽게 상수를 찾을 수 있다)
100nao를 micro로 변환하기 위해서 10을 나누어준다.
second와 microsecond로 변환한다. 
[edit]
2.2 code of gettimeofday in windows #
위의 approach를 따른 코드는 다음과 같다.
#include < time.h >
// epoch time으로 변환할 상수
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
#else
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
#endif
// for timezone
struct timezone
{
  int  tz_minuteswest; /- minutes W of Greenwich *-
  int  tz_dsttime;     /- type of dst correction *-
};
// gettimeofday in windows
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
  FILETIME ft;
  unsigned __int64 tmpres = 0;
  static int tzflag;
  if (NULL != tv)
  {
    // system time을 구하기
    GetSystemTimeAsFileTime(&ft);
    // unsigned 64 bit로 만들기
    tmpres |= ft.dwHighDateTime;
    tmpres <<= 32;
    tmpres |= ft.dwLowDateTime;
    // epoch time으로 변환하기
    tmpres -= DELTA_EPOCH_IN_MICROSECS;
        // 100nano를 1micro로 변환하기
    tmpres /= 10;
        // sec와 micorsec으로 맞추기
        tv->tv_sec = (tmpres / 1000000UL);
        tv->tv_usec = (tmpres % 1000000UL);
  }
  // timezone 처리
  if (NULL != tz)
  {
    if (!tzflag)
    {
      _tzset();
      tzflag++;
    }
    tz->tz_minuteswest = _timezone / 60;
    tz->tz_dsttime = _daylight;
  }
  return 0;
}
//
[edit]
2.3 usage of gettimeofday in windows #
gettimeofday()는 아래와 같이 사용할 수 있을 것이다.
struct timeval now;
gettimeofday(&now, NULL);
printf("time: %ld sec %ld msec\n", now.tv_sec, now.tv_usec);
//
[edit]
3 gettimeofday를 이용한 실행 시간 구하기 #
우리는 gettimeofday를 이용해서 코드의 수행 시간을 microsecond까지 측정할 수 있는 다음 함수를 만들 수 있을 것이다.
// 시간 측정
// event 1은 측정 시작
// event 2는 측정 완료 & print
void log_time(int event)
{
  static struct timeval tv_start;
  struct timeval tv_end;
  struct timeval *tv;
  tv = ((event==2)?&tv_end:&tv_start);
  gettimeofday(tv, NULL);
  if(event==2)
  {
          printf("Time: %ld  Seconds %ld  Microseconds\n",
           tv_end.tv_sec - tv_start.tv_sec,
           tv_end.tv_usec - tv_start.tv_usec);
  }
}
//
[edit]
4 gettimeofday와 이 것을 이용한 전체 코드 #
#include < time.h >
#include <windows.h>
#include <iostream>
#include <stdio.h>
// epoch time으로 변환할 상수
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
#else
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
#endif
// for timezone
struct timezone
{
  int  tz_minuteswest; /- minutes W of Greenwich *-
  int  tz_dsttime;     /- type of dst correction *-
};
// gettimeofday in windows
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
  FILETIME ft;
  unsigned __int64 tmpres = 0;
  static int tzflag;
  if (NULL != tv)
  {
    // system time을 구하기
    GetSystemTimeAsFileTime(&ft);
    // unsigned 64 bit로 만들기
    tmpres |= ft.dwHighDateTime;
    tmpres <<= 32;
    tmpres |= ft.dwLowDateTime;
    // epoch time으로 변환하기
    tmpres -= DELTA_EPOCH_IN_MICROSECS;
        // 100nano를 1micro로 변환하기
    tmpres /= 10;
        // sec와 micorsec으로 맞추기
        tv->tv_sec = (tmpres / 1000000UL);
        tv->tv_usec = (tmpres % 1000000UL);
  }
  // timezone 처리
  if (NULL != tz)
  {
    if (!tzflag)
    {
      _tzset();
      tzflag++;
    }
    tz->tz_minuteswest = _timezone / 60;
    tz->tz_dsttime = _daylight;
  }
  return 0;
}
// 시간 측정
// event 1은 측정 시작
// event 2는 측정 완료 & print
void log_time(int event)
{
  static struct timeval tv_start;
  struct timeval tv_end;
  struct timeval *tv;
  tv = ((event==2)?&tv_end:&tv_start);
  gettimeofday(tv, NULL);
  if(event==2)
  {
          printf("Time: %ld Seconds %ld Microseconds\n",
           tv_end.tv_sec - tv_start.tv_sec,
           tv_end.tv_usec - tv_start.tv_usec);
  }
}
void main()
{
        // method 1. directly use gettimeofday
        struct timeval now;
        struct timeval now2;
        gettimeofday(&now, NULL);
        Sleep(100);
        gettimeofday(&now2, NULL);
        long elpase_sec = now2.tv_sec - now.tv_sec;
        long elpase_usec = now2.tv_usec - now.tv_usec;
        printf("elapse: %ld sec %ld msec\n",
                               elpase_sec, elpase_usec);
        // method2. use log_time
        log_time(1);
        Sleep(1050);
        log_time(2);
}