관리 메뉴

Linux Programmer

gettimeofday를 대체하는 clock_gettime 함수 본문

컴퓨터 관련/프로그래밍 일반

gettimeofday를 대체하는 clock_gettime 함수

sunyzero 2012.09.25 00:19

gettimeofday는 유닉스, 리눅스 시스템 프로그래밍에서 시간을 구할 때 쓰던 함수이다. 마이크로초(백만분의 1초)단위로 구할 수 있는 기능을 가지고 있어서 많이 사용되는 함수이다.


그러나 앞으로는 gettimeofday는 사용하지 말아야할 함수가 되었다. 왜냐하면 gettimeofday는 2008년도 유닉스 표준인 SUSv4-2008에서 앞으로 제거될 구식(obsolescent) 함수로 지정했기 때문이다. 


물론 하위 호환성을 위해서 gettimeofday 함수는 계속 제공될 것이다. 하지만 기본 시스템 라이브러리에서는 제거되고, 구식 라이브러리를 따로 포함해야 사용할 수 있게 될지도 모르기 때문에 차후에는 gettimeofday는 쓰지 않는 편이 좋다. 참고로 지금까지의 표준안의 행보로 봤을 때 obsolescent 함수로 지정되면 약 10여년의 유예를 거치는 것 같다. 따라서 지금 당장부터 쓰지 말아야 하는 것은 아니다. 물론 기능적인 문제가 생길 수 있는 곳에서는 당장 교체해야 한다. (gettimeofday의 문제점은 아래 monotonic clock의 필요성을 보면 되겠다.)


대신에 새로운 함수인 clock_gettime을 사용하면 된다.


gettimeofday는 1988년도에 SVR4에서 표준에 지정되어 20여년을 넘게 사용되던 함수이다. 아직도 수많은 프로그래밍 서적이나 소스 코드의 예제에서 사용되고 있다. 실제로 최근에 개발되던 몇몇 실무 코드 조차 gettimeofday를 사용하고 있는 실정이다.


하지만 가까운 장래에는 퇴출될 함수이므로 지양하는 편이 좋다. 본인도 가끔 졸린 상태에서 기계적으로 코딩하다보면 gettimeofday를 쓰곤 하는데 지양하도록 주의하는 중이다.

 

그러면 새로운 함수인 clock_gettime의 프로토 타입부터 살펴보자. 비교를 위해 과거 gettimeofday 도 같이 적어두었다.

#include <time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tp);
    struct timespec {
            time_t   tv_sec;        /* seconds */
            long     tv_nsec;       /* nanoseconds */
    };
--------------------------------------------------------------
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
    struct timeval {
            time_t      tv_sec;     /* seconds */
            suseconds_t tv_usec;    /* microseconds */
    };


먼저 clock_gettime은 시간 관련 구조체가 struct timespec으로 바뀌었는데 나노초까지 지정할 수 있다. 물론 모든 시스템이 나노초까지 정밀한 시계를 제공하는 것은 아니다. 각 시스템 시계의 정밀도는 clock_getres로 확인할 수 있다.


또한 clock_gettime은 멀티코어 CPU 시대에 걸맞게 쓰레드 안전(thread safety)을 만족하고 있다.


인수로 쓰이는 clockid_t 타입은 시계의 종류를 나타내는 ID로서 POSIX 시스템은 기본적으로 2가지 타입(CLOCK_REALTIME, CLOCK_MONOTONIC)의 시계를 제공한다. 그리고 추가적으로 몇 개의 시계를 더 제공할 수 있다. 아래 표를 보면 몇몇 시계 ID를 정리해두었다. 그러나 실제 시스템에서는 이보다 더 많은 비표준 시계 ID를 제공하기도 한다.


 CLOCK_REALTIME 

 시스템 전역의 실제 시계(The UNIX Epoch 시간)

 CLOCK_MONOTONIC  단조 시계 (특정 시점에서 흐른 시간, 대체적으로 부팅후 시간)
 CLOCK_PROCESS_CPUTIME_ID  프로세스 단위 CPU 사용 시간
 CLOCK_THREAD_CPUTIME_ID  쓰레드 단위 CPU 사용 시간


여기서 CLOCK_REALTIME을 사용하면 실제 시간을 구하므로 gettimeofday의 기능과 같은 기능을 제공한다. 


CLOCK_MONOTONIC은 단조시계이므로 NTP에 의해서 시스템 시간이 바뀌더라도 영향을 받지 않는다. 따라서 (t1 - t0) 처럼 두 이벤트의 시간차이를 알고자 할 때 유용하다. 과거 gettimeofday의 경우는 NTP나 관련 기능에 의해서 시스템 시계가 보정될 때 오차가 발생하는 문제가 생길 수 있다. 따라서 최근에는 사용을 지양하도록 하는 기능이다. (이는 logging 관련 부분에서 diff. time의 정밀도가 중요할 때에도 나쁜 영향을 미칠 수 있다.)


이제 현재 시각을 버퍼에 저장하는 간단한 예제 코드를 살펴보자. 

main 함수는 생략했으니 적당히 붙여서 코딩하면 될 것이다. 화면에 출력되는 것을 보고 싶다면 printf로 buf 문자열을 출력하면 된다. 다시 말하지만 두 시간의 차(difference)를 구할 경우에는 CLOCK_MONOTONIC을 사용하도록 코딩해야 한다.


#define STR_TIME_FORMAT      "%y-%m-%d/%H:%M:%S"
char  buf[32];
size_t sz_buf = sizeof(buf);
struct timespec tspec;
struct tm   tm_now;

/* 리얼타임 시계로부터 현재 시간을 구한다. */
if (clock_gettime(CLOCK_REALTIME, &tspec) == -1) {  
    /* 에러 처리*/
}

/* timespec 구조체의 초수 필드(tv_sec)를 tm 구조체로 변환 */
localtime_r((time_t *)&tspec.tv_sec, &tm_now); 

/* 문자열로 저장 */
if (strftime(buf, sz_buf, STR_TIME_FORMAT, &tm_now) == 0) { 
    /* 에러 처리*/
}


참고로 gettimeofday 외에 usleep, getitimer, setitimer도 구식(obsolescent) 함수로 지정되어 나중에는 사라질 함수이므로 되도록이면 쓰지 않는 편이 좋다.


17 Comments
  • 프로필사진 드래곤포토 2012.09.28 12:39 신고 즐거운 추석되세요 ^^
  • 프로필사진 sunyzero 2012.09.28 15:27 신고 감사합니다. 즐거운 추석 되세요
  • 프로필사진 이세형 2012.12.17 14:07 안녕하세요^^ 좋은정보 감사합니다. 제 블로그로 퍼갈게요^^
  • 프로필사진 sunyzero 2012.12.17 16:38 신고 네 퍼가셔도 됩니다. 공지에도 적었듯이 다른 분들도 쉽게 퍼갈 수 있도록 해주시면 좋겠어요. ^^
  • 프로필사진 상사꽃 2013.10.07 16:37 하악~ @_@ 좋은 정보 감사합니다. 컴파일 시 -lrt 들어가야한다는 설명도 있었으면 하는 아쉬움이 0.2% 있긴 하지만... ^^
  • 프로필사진 sunyzero 2013.10.08 19:37 신고 도움이 되셨다면 다행입니다. 즐거운 한글날 되시기 바랍니다 ^^
  • 프로필사진 예스베이비 2014.04.01 11:39 신고 리눅스 관련해서 밀리세컨 이하로 측정할 일이 생겨서 고민이었는데 잘 읽고 갑니다^^
  • 프로필사진 sunyzero 2014.04.03 01:30 신고 도움이 되어 다행입니다. ^^
  • 프로필사진 후추나 2014.09.11 13:33 블로그 포스팅에 참고링크 걸었습니다. 좋은 정보 감사합니다.
  • 프로필사진 sunyzero 2014.09.11 23:34 신고 반갑습니다. ^^
  • 프로필사진 컴공맨 2015.05.25 02:39 파일시스템 성능측정관련 iops를 직접 코드를 짜서 측정중으로 나노초 단위도 궁금했었는데 배워갑니다.
    감사합니다 ! 리눅스 초보라 많은 도움이 되었습니다 ㅠㅠ
  • 프로필사진 sunyzero 2015.05.29 15:28 신고 아키텍처에 따라 나노초를 지원하지 않을수도 있으니 꼭 clock_getres로 resolution을 확인해보시기 바랍니다.
  • 프로필사진 컴공맨2 2018.04.13 06:14 와 글이 너무 좋네요ㅠ 오래전 글이지만 정말 큰 도움 되었습니다.

    궁금한 것이 두가지 있는데요,

    1. CLOCK_MONOTONIC 를 지원하지 않는 시스템도 있나요? (스택오버플로우에서 CLOCK_MONOTONIC 를 지원하는 시스템에서는 CLOCK_REALTIME 대신 사용하라는 애매한 답변을 본적이 있어서요)

    2. '아키텍처에 따라 나노초를 지원하지 않을수도 있으니' <- 지원하지 않으면 함수 호출시 에러가 발생하나요?
    아니면 작동에는 문제가 없으나 나노초 단위의 정밀한 값은 기대할 수 없다는 것인가요?
    (저는 어차피 밀리세컨드 단위로 반올림 하여 리턴하는 함수를 만들어서 쓰기 때문에 나노초의 정밀함은 필요가 없어요!)
  • 프로필사진 sunyzero 2018.04.15 16:19 신고 답변)
    1. CLOCK_MONOTONIC은 IEEE std 1003.1-1998에서 소개된 기능입니다. 즉 1998년도에 소개된 기능이니 지금으로부터 약 20년전에 나왔습니다.

    정말 심각하게 구형 시스템이 아니고서야 지원하지 않는 시스템은 없을겁니다. 리눅스는 당연히 잘 지원합니다.

    2. clock_getres로 나노초를 지원하는지 확인하시면 됩니다. 정밀도가 떨어지면 떨어지는대로 쓰시면 됩니다.

    그리고 세밀한 정밀도가 필요없고, 시스템이 리눅스라면 성능 부담을 덜 주는 coarse clock도 지원합니다. 시계는 CLOCK_MONOTONIC_COARSE을 대신 사용하면 됩니다.
  • 프로필사진 컴공맨2 2018.05.02 04:00 질문을 올려놓고 주소를 못찾았다가 이제야 겨우 도착했습니다 ㅠㅠ
    너무 감사합니다!
    심각하게 사랑합니다!
  • 프로필사진 코딩은어려워 2019.05.09 11:07 안녕하세요. 좋은 글 잘 읽었습니다!
    궁금한 것이 있어 여쭤봅니다.

    지금 제가 하려는 것이 NTP 로 두 랩탑 동기화를 시켜놓은 무선 인터페이스로 통신 딜레이를 측정하려는 것인데요.
    예를 들어 송신 측에서 송신할 때 불리는 함수가 있고 수신 측에서 수신할 때 불리는 함수가 있을 때 함수가 불리는 시점을 커널 단에서 출력하여 계산하면 (두 기기가 동기화가 잘 되어있다고 가정하면) 된다고 생각을 했었습니다.
    제가 궁금한 점은 gettimeofday 는 NTP를 써서 시스템 시간을 바꿨을 때 오류가 발생할 수 있다고 하셨는데 clock_gettime 을 쓰면 별 문제가 발생하지 않는지 궁금합니다.
  • 프로필사진 sunyzero 2019.05.12 20:33 신고 예를 들어 편의상 두 랩탑을 A, B라고 할 때, NTP로 동기화 했다고 하더라도 서로 동기적 오차가 있기 때문에 각각 측정하는 방식은 좋지 않고, A에서만 라운드 트립을 계산하여 2로 나누는게 좋습니다. 반복 측정하면 표준편차도 구할 수 있겠죠.

    원래 NTP 프로토콜 자체도 4개의 시간을 구해서 하는 방식인데, 해당 프로토콜 방식을 보고 비슷하게 구현하시는게 좋습니다.
댓글쓰기 폼
Prev 1 2 3 4 5 6 7 8 Next