programing

ANSI C를 사용하여 밀리초 단위로 시간을 측정하는 방법은 무엇입니까?

prostudy 2022. 6. 9. 22:07
반응형

ANSI C를 사용하여 밀리초 단위로 시간을 측정하는 방법은 무엇입니까?

ANSI C만을 사용하여 밀리초 이상의 정밀도로 시간을 측정하는 방법이 있습니까?time.h를 브라우징하고 있었는데 2차 정밀함수밖에 찾을 수 없었습니다.

1초 이상의 분해능을 제공하는 ANSI C 함수는 없지만 POSIX 함수는 마이크로초 분해능을 제공합니다.클럭 함수는 프로세스가 실행에 소요된 시간만 측정할 뿐 대부분의 시스템에서는 정확하지 않습니다.

이 기능은 다음과 같이 사용할 수 있습니다.

struct timeval tval_before, tval_after, tval_result;

gettimeofday(&tval_before, NULL);

// Some code you want to time, for example:
sleep(1);

gettimeofday(&tval_after, NULL);

timersub(&tval_after, &tval_before, &tval_result);

printf("Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);

값은 반환됩니다.Time elapsed: 1.000870내 기계로.

휴대용 솔루션 구현

시간 측정 문제에 대해 충분한 정밀도를 갖춘 적절한 ANSI 솔루션이 없다고 이미 언급했듯이, 저는 휴대용 및 가능하면 고해상도 시간 측정 솔루션을 얻는 방법에 대해 쓰고 싶습니다.

단조로운 시계와 타임스탬프

일반적으로 시간 측정에는 두 가지 방법이 있습니다.

  • 단조 클럭
  • 현재(날짜) 타임스탬프

첫 번째는 미리 정의된 빈도로 틱을 카운트하는 단조 클럭 카운터(때로는 틱 카운터라고도 함)를 사용하기 때문에 틱 값이 있고 빈도가 알려진 경우 틱을 경과 시간으로 쉽게 변환할 수 있습니다.단조 클럭이 현재의 시스템 시각을 반영한다고는 보증되지 않습니다.시스템 기동 후에 틱을 카운트 할 수도 있습니다.단, 시스템 상태에 관계없이 클럭이 항상 증가하도록 보장합니다.일반적으로 주파수는 하드웨어의 고해상도 소스에 바인딩되어 있기 때문에 정확도가 높습니다(하드웨어에 의존하지만 최신 하드웨어의 대부분은 고해상도 클럭 소스에 문제가 없습니다).

두 번째 방법은 현재 시스템클럭 값을 기반으로 (날짜) 시간 값을 제공합니다.해상도는 높을 수 있지만 큰 단점이 하나 있습니다.이러한 종류의 시간 값은 다양한 시스템 시간 조정(타임존 변경, 여름 시간(DST) 변경, NTP 서버 업데이트, 시스템 휴지 상태 등)에 의해 영향을 받을 수 있습니다.경우에 따라서는 음의 경과 시간 값을 얻을 수 있으며 이로 인해 정의되지 않은 동작이 발생할 수 있습니다.사실 이런 종류의 타임소스는 처음보다 신뢰성이 떨어집니다.

따라서 시간 간격 측정의 첫 번째 규칙은 가능하면 단조 시계를 사용하는 것입니다.일반적으로 정밀도가 높고, 설계상 신뢰성이 높습니다.

폴백 전략

휴대용 솔루션을 구현할 때는 폴백 전략을 고려할 필요가 있습니다.사용 가능한 경우 단조 클럭을 사용하고 시스템에 단조 클럭이 없을 경우 타임스탬프로 폴백합니다.

창문들

Windows에서의 시간 측정에 관한 MSDN의 고해상도 타임스탬프 취득이라는 훌륭한 기사가 있습니다.이 기사에는 소프트웨어 및 하드웨어 지원에 대해 알아야 할 모든 세부 정보가 기재되어 있습니다.Windows 로 고정밀 타임스탬프를 취득하려면 , 다음의 조작을 실시할 필요가 있습니다.

  • Query Performance Frequency를 사용하여 타이머 빈도(초당 틱 수)를 쿼리합니다.

    LARGE_INTEGER tcounter;
    LARGE_INTEGER freq;    
    
    if (QueryPerformanceFrequency (&tcounter) != 0)
        freq = tcounter.QuadPart;
    

    타이머 주파수는 시스템 부팅 시 고정되므로 1회만 취득하면 됩니다.

  • Query Performance Counter를 사용하여 현재 틱 값을 쿼리합니다.

    LARGE_INTEGER tcounter;
    LARGE_INTEGER tick_value;
    
    if (QueryPerformanceCounter (&tcounter) != 0)
        tick_value = tcounter.QuadPart;
    
  • 경과 시간(마이크로초)까지 눈금 눈금 조정:

    LARGE_INTEGER usecs = (tick_value - prev_tick_value) / (freq / 1000000);
    

Microsoft에 따르면 대부분의 경우 Windows XP 이후의 버전에서는 이 접근법에 문제가 없습니다.Windows 에서는, 다음의 2개의 폴백 솔루션을 사용할 수도 있습니다.

  • GetTickCount는 시스템 시작 후 경과한 밀리초 수를 제공합니다.49.7일마다 감겨지므로 더 긴 간격을 측정할 때 주의하십시오.
  • GetTickCount64는 의 64비트 버전입니다.GetTickCountWindows Vista の windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows 。

OS X(macOS)

OS X(macOS)에는 단조 클럭을 나타내는 자체 마하 절대 시간 단위가 있습니다.시작하기에 가장 좋은 방법은 Apple 기사 Technical Q&A QA1398: Mach Absolute Time Units입니다.이 기사에서는 마하 고유의 API를 사용하여 단조로운 틱을 얻는 방법을 (코드 예제를 사용하여) 설명하고 있습니다.또한 Mac OS X에서는 clock_gettime 대안이라고 불리는 로컬 질문도 있습니다.이것은 카운터 주파수가 분자와 분모의 형태로 사용되기 때문에 마지막에 발생할 수 있는 값의 오버플로를 어떻게 처리해야 할지 약간 혼란스러울 수 있습니다.다음으로 경과시간을 취득하는 간단한 예를 제시하겠습니다.

  • 클럭 주파수 분자와 분모를 가져옵니다.

    #include <mach/mach_time.h>
    #include <stdint.h>
    
    static uint64_t freq_num   = 0;
    static uint64_t freq_denom = 0;
    
    void init_clock_frequency ()
    {
        mach_timebase_info_data_t tb;
    
        if (mach_timebase_info (&tb) == KERN_SUCCESS && tb.denom != 0) {
            freq_num   = (uint64_t) tb.numer;
            freq_denom = (uint64_t) tb.denom;
        }
    }
    

    그거는 딱 한 번만 하면 돼요.

  • mach_absolute_time:

    uint64_t tick_value = mach_absolute_time ();
    
  • 이전에 쿼리한 분자와 분모를 사용하여 경과 시간(마이크로초)까지 눈금을 조정합니다.

    uint64_t value_diff = tick_value - prev_tick_value;
    
    /* To prevent overflow */
    value_diff /= 1000;
    
    value_diff *= freq_num;
    value_diff /= freq_denom;
    

    분자와 분모를 사용하기 전에 눈금 크기를 원하는 정확도로 줄이는 것이 오버플로를 방지하는 주요 방법입니다.이므로 이 을 '나노초로 나눕니다.1000microseconds를 취득합니다.크롬의 time_mac.c에서 사용된 것과 동일한 방법을 찾을 수 있습니다.나노초의 정확도가 필요한 경우 "오버플로 없이 mach_absolute_time을 사용하는 방법"을 읽어보십시오.

Linux 및 UNIX

clock_gettimePOSIX pos pos pos pos pos pos pos pos pos pos pos pos pos pos pos pos pos pos pos pos 。소스에서 할 수 은 '하다'입니다.필요한 건CLOCK_MONOTONIC 시스템이 .을 있는 것은 .clock_gettimeCLOCK_MONOTONIC따라서 가장 먼저 그 가용성을 확인해야 합니다.

  • _POSIX_MONOTONIC_CLOCK는 값 "으로 됩니다.>= 0즉,CLOCK_MONOTONIC이용할 수 있습니다.
  • _POSIX_MONOTONIC_CLOCK is is is is is is로 되어 있다.0이기 때문에 저는 이 기능을 사용할 합니다.sysconf:

    #include <unistd.h>
    
    #ifdef _SC_MONOTONIC_CLOCK
    if (sysconf (_SC_MONOTONIC_CLOCK) > 0) {
        /* A monotonic clock presents */
    }
    #endif
    
  • 그렇지 않으면 단조 클럭은 지원되지 않으므로 폴백 전략을 사용해야 합니다(아래 참조).

「 」의 clock_gettime매우 간단합니다.

  • 시간 값 가져오기:

    #include <time.h>
    #include <sys/time.h>
    #include <stdint.h>
    
    uint64_t get_posix_clock_time ()
    {
        struct timespec ts;
    
        if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
            return (uint64_t) (ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
        else
            return 0;
    }
    

    여기서 시간을 마이크로초로 줄였습니다.

  • 동일한 방법으로 수신된 이전 시간 값과의 차이를 계산합니다.

    uint64_t prev_time_value, time_value;
    uint64_t time_diff;
    
    /* Initial time */
    prev_time_value = get_posix_clock_time ();
    
    /* Do some work here */
    
    /* Final time */
    time_value = get_posix_clock_time ();
    
    /* Time difference */
    time_diff = time_value - prev_time_value;
    

은 '폴백'을 입니다.gettimeofday로운 것은 꽤합니다.call: "Call" : "Call" : "Call" : "Col" : "Col" : "Col" : "Col" : "Col" : "Col" : "Col" : "Col" 。은 '아까보다'와요.clock_gettime , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

#include <time.h>
#include <sys/time.h>
#include <stdint.h>

uint64_t get_gtod_clock_time ()
{
    struct timeval tv;

    if (gettimeofday (&tv, NULL) == 0)
        return (uint64_t) (tv.tv_sec * 1000000 + tv.tv_usec);
    else
        return 0;
}

다시 시간 값은 마이크로초로 축소됩니다.

SGI IRIX

IRIX는clock_gettime단, 「」, 「」가 없습니다.CLOCK_MONOTONIC. , 음음음음음음음 source source source source source source source source defined defined defined 로 정의된 독자적인 가 있습니다CLOCK_SGI_CYCLE 문구는 꼭 합니다.CLOCK_MONOTONICclock_gettime.

Solaris 및 HP-UX

Solaris가 .gethrtime현재 타이머 값(나노초)을 반환합니다. 버전의 Solaris에는 Solaris가 탑재되어 있는 가 있습니다만,clock_gettime 하면 됩니다.gethrtimeSolaris 버전전 。

사용법은 간단합니다.

#include <sys/time.h>

void time_measure_example ()
{
    hrtime_t prev_time_value, time_value;
    hrtime_t time_diff;

    /* Initial time */
    prev_time_value = gethrtime ();

    /* Do some work here */

    /* Final time */
    time_value = gethrtime ();

    /* Time difference */
    time_diff = time_value - prev_time_value;
}

에는 HP-UX가 없습니다.clock_gettime, ,를 지원합니다gethrtimeSolaris solaris solaris solaris solaris 。

BeOS

또한 BeOS에는 자체 고해상도 타이머 인터페이스가 있습니다.system_time컴퓨터가 부팅된 후 경과한 시간(마이크로초)을 반환합니다.

사용 예:

#include <kernel/OS.h>

void time_measure_example ()
{
    bigtime_t prev_time_value, time_value;
    bigtime_t time_diff;

    /* Initial time */
    prev_time_value = system_time ();

    /* Do some work here */

    /* Final time */
    time_value = system_time ();

    /* Time difference */
    time_diff = time_value - prev_time_value;
}

OS/2

OS/2에는 고정밀 타임스탬프를 취득하기 위한 자체 API가 있습니다.

  • 주파수최대)를DosTmrQueryFreq 컴파일러의 경우 (GCC 컴파일러의 경우):

    #define INCL_DOSPROFILE
    #define INCL_DOSERRORS
    #include <os2.h>
    #include <stdint.h>
    
    ULONG freq;
    
    DosTmrQueryFreq (&freq);
    
  • DosTmrQueryTime:

    QWORD    tcounter;
    unit64_t time_low;
    unit64_t time_high;
    unit64_t timestamp;
    
    if (DosTmrQueryTime (&tcounter) == NO_ERROR) {
        time_low  = (unit64_t) tcounter.ulLo;
        time_high = (unit64_t) tcounter.ulHi;
    
        timestamp = (time_high << 32) | time_low;
    }
    
  • 경과 시간(마이크로초)까지 눈금 눈금 조정:

    uint64_t usecs = (prev_timestamp - timestamp) / (freq / 1000000);
    

구현 예시

의 모든 전략을 구현하는 plibsys 라이브러리를 볼 수 있습니다(자세한 내용은 ptimeprofiler*.c 참조).

#include <time.h>
clock_t uptime = clock() / (CLOCKS_PER_SEC / 1000);

항상 clock_gettime() 함수를 사용하여 CLOCK_MONOTIC 클럭에서 시간을 반환합니다.반환되는 시간은 에폭의 시스템 기동 등 과거의 미지정 시점으로부터 경과한 시간(초단위 및 나노초단위)입니다.

#include <stdio.h>
#include <stdint.h>
#include <time.h>

int64_t timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)
{
  return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) -
           ((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
}

int main(int argc, char **argv)
{
  struct timespec start, end;
  clock_gettime(CLOCK_MONOTONIC, &start);

  // Some code I am interested in measuring 

  clock_gettime(CLOCK_MONOTONIC, &end);

  uint64_t timeElapsed = timespecDiff(&end, &start);
}

timespec_get

구현 해상도로 반올림된 최대 나노초를 반환합니다.

POSIX로부터의 ANSI 것 .clock_gettime.

a: aprintf우분투 15.10초 100밀리초

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static long get_nanos(void) {
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    return (long)ts.tv_sec * 1000000000L + ts.tv_nsec;
}

int main(void) {
    long nanos;
    long last_nanos;
    long start;
    nanos = get_nanos();
    last_nanos = nanos;
    start = nanos;
    while (1) {
        nanos = get_nanos();
        if (nanos - last_nanos > 100000000L) {
            printf("current nanos: %ld\n", nanos - start);
            last_nanos = nanos;
        }
    }
    return EXIT_SUCCESS;
}

C11 N1570 표준 드래프트 7.27.2.5 "timespec_get 함수는 다음과 같습니다."

베이스가 TIME_UTC인 경우, tv_sec 멤버는 실장 정의 에폭 이후의 초수로 설정되며, 정수로 잘라지고, tv_nsec 멤버는 시스템 클럭의 분해능으로 반올림된 나노초의 정수수로 설정됩니다(321).

321) structure timespec 객체는 나노초 분해능을 가진 시간을 나타내지만 사용 가능한 분해능은 시스템에 따라 다르며 1초보다 클 수도 있습니다.

C++11을 취득했습니다.std::chrono::high_resolution_clock: C++ 크로스 플랫폼 고해상도 타이머

glibc 2.21 구현

다음 항목에 있습니다.

int
timespec_get (struct timespec *ts, int base)
{
  switch (base)
    {
    case TIME_UTC:
      if (__clock_gettime (CLOCK_REALTIME, ts) < 0)
        return 0;
      break;

    default:
      return 0;
    }

  return base;
}

매우 선명하게:

  • only만.TIME_UTC되고 있습니다.

  • 로로로 __clock_gettime (CLOCK_REALTIME, ts)POSIX API:http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html

    에는 Linux x86-64가 되어 있습니다.clock_gettime시스템 콜을 실행합니다.

    다음 이유로 이 방법은 장애 방지 마이크로벤치마킹 방식이 아닙니다.

    • man clock_gettime프로그램 실행 중에 시스템 시간 설정을 변경하면 이 측정이 중단될 수 있습니다.이것은 물론 드문 일이므로 무시할 수 있습니다.

    • 이 기능은 벽면 시간을 측정하기 때문에 스케줄러가 작업을 잊기로 결정하면 작업이 더 오래 실행되는 것처럼 보입니다.

    에, 「 」getrusage()최대 정밀도는 마이크로초이지만 POSIX 벤치마크 툴이 더 나을 수 있습니다.

    자세한 내용은 Linux에서 시간 측정 - 시간 vs clock vs getrusage vs clock_gettime vs gettime of day vs timespec_get?

인정된 답변으로 충분합니다.하지만 제 해결책은 더 간단합니다.Linux에서 테스트만 하면 gcc(Ubuntu 7.2.0-8ubuntu 3.2) 7.2.0을 사용합니다.

를 사용하다gettimeofday , . . . . . . . .tv_sec 번째 두 번째 부분, 두 번째 부분, 세 번째 부분, 세 번째 부분, 세 번째 부분, 세 번째 부분.tv_usec밀리초가 아니라 마이크로초입니다.

long currentTimeMillis() {
  struct timeval time;
  gettimeofday(&time, NULL);

  return time.tv_sec * 1000 + time.tv_usec / 1000;
}

int main() {
  printf("%ld\n", currentTimeMillis());
  // wait 1 second
  sleep(1);
  printf("%ld\n", currentTimeMillis());
  return 0;
 }

인쇄 내용:

1522139691342
1522139692342 1초면 됩니다.
^

창 아래:

SYSTEMTIME t;
GetLocalTime(&t);
swprintf_s(buff, L"[%02d:%02d:%02d:%d]\t", t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);

가능한 최고의 정밀도는 클럭 수준의 해상도를 제공할 수 있는 x86만의 "rdtsc" 명령을 사용하는 것입니다(물론 rdtsc 호출 자체의 비용을 고려해야 하며, 이는 애플리케이션 부팅 시 쉽게 측정할 수 있습니다).

여기서 가장 중요한 것은 초당 클럭 수를 측정하는 것인데, 이는 그리 어렵지 않을 것입니다.

언급URL : https://stackoverflow.com/questions/361363/how-to-measure-time-in-milliseconds-using-ansi-c

반응형