programing

시간 간격을 C로 측정하려면 어떻게 해야 하나요?

goodsources 2022. 11. 1. 00:04
반응형

시간 간격을 C로 측정하려면 어떻게 해야 하나요?

시간을 C로 측정하고 싶은데, 파악이 어려운데, 제가 원하는 것은 다음과 같습니다.

  • 타이머를 켜다
  • 메서드를 실행하다.
  • 타이머를 멈추다
  • 소요된 시간을 보고한다(적어도 마이크로 정밀도까지).

어떤 도움이라도 주시면 감사하겠습니다.

(mingw를 사용하여 창으로 컴파일 중)

1마이크로초의 분해능을 제공하는 고해상도 타이머는 시스템마다 다르므로 OS 플랫폼마다 다른 방법을 사용해야 합니다.다음 문서에서 아래 함수를 기반으로 크로스 플랫폼 C++ 타이머 클래스를 구현합니다.

  • [안송호 - 고해상도 타이머][1]

창문들

Windows API windows windows windows windows windows windows windows windows windows 。QueryPerformanceCounter()과 "진행된 틱"이 QueryPerformanceFrequency()초당 틱 수를 반환합니다.

예:

#include <stdio.h>
#include <windows.h>                // for Windows APIs

int main(void)
{
    LARGE_INTEGER frequency;        // ticks per second
    LARGE_INTEGER t1, t2;           // ticks
    double elapsedTime;

    // get ticks per second
    QueryPerformanceFrequency(&frequency);

    // start timer
    QueryPerformanceCounter(&t1);

    // do something
    // ...

    // stop timer
    QueryPerformanceCounter(&t2);

    // compute and print the elapsed time in millisec
    elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
    printf("%f ms.\n", elapsedTime);
}

Linux, Unix 및 Mac

또는 시스템의 Unix Linux 를 사용할 수 .gettimeofday()'sys/time'은 'sys/time'..h'는 'sys/time'은 'sys.h.

예:

#include <stdio.h>
#include <sys/time.h>                // for gettimeofday()

int main(void)
{
    struct timeval t1, t2;
    double elapsedTime;

    // start timer
    gettimeofday(&t1, NULL);

    // do something
    // ...

    // stop timer
    gettimeofday(&t2, NULL);

    // compute and print the elapsed time in millisec
    elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0;      // sec to ms
    elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0;   // us to ms
    printf("%f ms.\n", elapsedTime);
}

Linux 에서는 다음을 사용할 수 있습니다.

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); // get initial time-stamp

// ... do stuff ... //

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);   // get final time-stamp

double t_ns = (double)(end.tv_sec - start.tv_sec) * 1.0e9 +
              (double)(end.tv_nsec - start.tv_nsec);
                                                 // subtract time-stamps and
                                                 // multiply to get elapsed
                                                 // time in ns

다음은 gettime of day() 시스템콜에 기초한 타이머 관리용 다목적 C 함수 그룹입니다.모든 타이머 속성은 단일 틱타이머 구조에 포함되어 있습니다.필요한 간격, 타이머 초기화 후의 총 실행 시간, 호출하는 콜백에 대한 포인터, 콜백이 호출된 횟수입니다.콜백 함수는 다음과 같습니다.

void your_timer_cb (struct ticktimer *t) {
  /* do your stuff here */
}

타이머를 초기화 및 시작하려면 ticktimer_init(your_timer, interval, TICTIMER_RUN, your_timer_cb, 0)을 호출합니다.

프로그램의 메인 루프에서 ticktimer_tick(your_timer)을 호출하면 콜백을 호출하는 데 적절한 시간이 경과했는지 여부가 결정됩니다.

타이머를 정지하려면 ticktimer_ctl(your_timer, TICKTIMER_STOP)을 호출합니다.

틱타이머h:

#ifndef __TICKTIMER_H
#define __TICKTIMER_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

#define TICKTIMER_STOP         0x00
#define TICKTIMER_UNCOMPENSATE 0x00
#define TICKTIMER_RUN          0x01
#define TICKTIMER_COMPENSATE   0x02

struct ticktimer {
  u_int64_t tm_tick_interval;
  u_int64_t tm_last_ticked;
  u_int64_t tm_total;
  unsigned ticks_total;
  void (*tick)(struct ticktimer *);
  unsigned char flags;
  int id;
};

void ticktimer_init (struct ticktimer *, u_int64_t, unsigned char, void (*)(struct ticktimer *), int);
unsigned ticktimer_tick (struct ticktimer *);
void ticktimer_ctl (struct ticktimer *, unsigned char);
struct ticktimer *ticktimer_alloc (void);
void ticktimer_free (struct ticktimer *);
void ticktimer_tick_all (void);

#endif

ticktimer.c:

#include "ticktimer.h"

#define TIMER_COUNT 100

static struct ticktimer timers[TIMER_COUNT];
static struct timeval tm;

/*!
  @brief
    Initializes/sets the ticktimer struct.

  @param timer
    Pointer to ticktimer struct.
  @param interval
    Ticking interval in microseconds.
  @param flags
    Flag bitmask. Use TICKTIMER_RUN | TICKTIMER_COMPENSATE
    to start a compensating timer; TICKTIMER_RUN to start
    a normal uncompensating timer.
  @param tick
    Ticking callback function.
  @param id
    Timer ID. Useful if you want to distinguish different
    timers within the same callback function.
*/
void ticktimer_init (struct ticktimer *timer, u_int64_t interval, unsigned char flags, void (*tick)(struct ticktimer *), int id) {
  gettimeofday(&tm, NULL);
  timer->tm_tick_interval = interval;
  timer->tm_last_ticked = tm.tv_sec * 1000000 + tm.tv_usec;
  timer->tm_total = 0;
  timer->ticks_total = 0;
  timer->tick = tick;
  timer->flags = flags;
  timer->id = id;
}

/*!
  @brief 
    Checks the status of a ticktimer and performs a tick(s) if 
    necessary.

  @param timer
    Pointer to ticktimer struct.

  @return
    The number of times the timer was ticked.
*/
unsigned ticktimer_tick (struct ticktimer *timer) {
  register typeof(timer->tm_tick_interval) now;
  register typeof(timer->ticks_total) nticks, i;

  if (timer->flags & TICKTIMER_RUN) {
    gettimeofday(&tm, NULL);
    now = tm.tv_sec * 1000000 + tm.tv_usec;

    if (now >= timer->tm_last_ticked + timer->tm_tick_interval) {
      timer->tm_total += now - timer->tm_last_ticked;

      if (timer->flags & TICKTIMER_COMPENSATE) {
        nticks = (now - timer->tm_last_ticked) / timer->tm_tick_interval;
        timer->tm_last_ticked = now - ((now - timer->tm_last_ticked) % timer->tm_tick_interval);

        for (i = 0; i < nticks; i++) {
          timer->tick(timer);
          timer->ticks_total++;

          if (timer->tick == NULL) {
            break;
          }
        }

        return nticks;
      } else {
        timer->tm_last_ticked = now;
        timer->tick(timer);
        timer->ticks_total++;
        return 1;
      }
    }
  }

  return 0;
}

/*!
  @brief
    Controls the behaviour of a ticktimer.

  @param timer
    Pointer to ticktimer struct.
  @param flags
    Flag bitmask.
*/
inline void ticktimer_ctl (struct ticktimer *timer, unsigned char flags) {
  timer->flags = flags;
}

/*!
  @brief
    Allocates a ticktimer struct from an internal
    statically allocated list.

  @return
    Pointer to the newly allocated ticktimer struct
    or NULL when no more space is available.
*/
struct ticktimer *ticktimer_alloc (void) {
  register int i;

  for (i = 0; i < TIMER_COUNT; i++) {
    if (timers[i].tick == NULL) {
      return timers + i;
    }
  }

  return NULL;
}

/*!
  @brief
    Marks a previously allocated ticktimer struct as free.

  @param timer
    Pointer to ticktimer struct, usually returned by 
    ticktimer_alloc().
*/
inline void ticktimer_free (struct ticktimer *timer) {
  timer->tick = NULL;
}

/*!
  @brief
    Checks the status of all allocated timers from the 
    internal list and performs ticks where necessary.

  @note
    Should be called in the main loop.
*/
inline void ticktimer_tick_all (void) {
  register int i;

  for (i = 0; i < TIMER_COUNT; i++) {
    if (timers[i].tick != NULL) {
      ticktimer_tick(timers + i);
    }
  }
}

다음은 간단한 성능 프로파일링을 수행하기 위해 쓴 헤더 파일입니다(수동 타이머 사용).

#ifndef __ZENTIMER_H__
#define __ZENTIMER_H__

#ifdef ENABLE_ZENTIMER

#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#else
typedef unsigned char uint8_t;
typedef unsigned long int uint32_t;
typedef unsigned long long uint64_t;
#endif

#ifdef __cplusplus
extern "C" {
#pragma }
#endif /* __cplusplus */

#define ZTIME_USEC_PER_SEC 1000000

/* ztime_t represents usec */
typedef uint64_t ztime_t;

#ifdef WIN32
static uint64_t ztimer_freq = 0;
#endif

static void
ztime (ztime_t *ztimep)
{
#ifdef WIN32
    QueryPerformanceCounter ((LARGE_INTEGER *) ztimep);
#else
    struct timeval tv;

    gettimeofday (&tv, NULL);

    *ztimep = ((uint64_t) tv.tv_sec * ZTIME_USEC_PER_SEC) + tv.tv_usec;
#endif
}

enum {
    ZTIMER_INACTIVE = 0,
    ZTIMER_ACTIVE   = (1 << 0),
    ZTIMER_PAUSED   = (1 << 1),
};

typedef struct {
    ztime_t start;
    ztime_t stop;
    int state;
} ztimer_t;

#define ZTIMER_INITIALIZER { 0, 0, 0 }

/* default timer */
static ztimer_t __ztimer = ZTIMER_INITIALIZER;

static void
ZenTimerStart (ztimer_t *ztimer)
{
    ztimer = ztimer ? ztimer : &__ztimer;

    ztimer->state = ZTIMER_ACTIVE;
    ztime (&ztimer->start);
}

static void
ZenTimerStop (ztimer_t *ztimer)
{
    ztimer = ztimer ? ztimer : &__ztimer;

    ztime (&ztimer->stop);
    ztimer->state = ZTIMER_INACTIVE;
}

static void
ZenTimerPause (ztimer_t *ztimer)
{
    ztimer = ztimer ? ztimer : &__ztimer;

    ztime (&ztimer->stop);
    ztimer->state |= ZTIMER_PAUSED;
}

static void
ZenTimerResume (ztimer_t *ztimer)
{
    ztime_t now, delta;

    ztimer = ztimer ? ztimer : &__ztimer;

    /* unpause */
    ztimer->state &= ~ZTIMER_PAUSED;

    ztime (&now);

    /* calculate time since paused */
    delta = now - ztimer->stop;

    /* adjust start time to account for time elapsed since paused */
    ztimer->start += delta;
}

static double
ZenTimerElapsed (ztimer_t *ztimer, uint64_t *usec)
{
#ifdef WIN32
    static uint64_t freq = 0;
    ztime_t delta, stop;

    if (freq == 0)
        QueryPerformanceFrequency ((LARGE_INTEGER *) &freq);
#else
#define freq ZTIME_USEC_PER_SEC
    ztime_t delta, stop;
#endif

    ztimer = ztimer ? ztimer : &__ztimer;

    if (ztimer->state != ZTIMER_ACTIVE)
        stop = ztimer->stop;
    else
        ztime (&stop);

    delta = stop - ztimer->start;

    if (usec != NULL)
        *usec = (uint64_t) (delta * ((double) ZTIME_USEC_PER_SEC / (double) freq));

    return (double) delta / (double) freq;
}

static void
ZenTimerReport (ztimer_t *ztimer, const char *oper)
{
    fprintf (stderr, "ZenTimer: %s took %.6f seconds\n", oper, ZenTimerElapsed (ztimer, NULL));
}

#ifdef __cplusplus
}
#endif /* __cplusplus */

#else /* ! ENABLE_ZENTIMER */

#define ZenTimerStart(ztimerp)
#define ZenTimerStop(ztimerp)
#define ZenTimerPause(ztimerp)
#define ZenTimerResume(ztimerp)
#define ZenTimerElapsed(ztimerp, usec)
#define ZenTimerReport(ztimerp, oper)

#endif /* ENABLE_ZENTIMER */

#endif /* __ZENTIMER_H__ */

ztime()함수는 필요한 주요 로직입니다.현재 시각을 취득하여 마이크로초 단위로 64비트 uint에 저장합니다.그런 다음 나중에 간단한 계산을 수행하여 경과 시간을 확인할 수 있습니다.

ZenTimer*()함수는 단순한 타이머 구조에 대한 포인터를 얻기 위한 도우미 함수일 뿐입니다.ztimer_t시작 시간과 종료 시간을 기록합니다.ZenTimerPause()/ZenTimerResume()예를 들어, 타이머를 일시 정지했다가 다시 시작할 수 있습니다.

원본 헤더 파일의 복사본은 http://www.gnome.org/~fej/code/zentimer.h 에서 찾을 수 있습니다.혹시 제가 <<고객명>님의 HTML 이스케이프를 망쳤을 수도 있습니다.이것은 MIT/X11에 의거한 라이선스가 있기 때문에, 어느 프로젝트에나 카피할 수 있습니다.

time.h 라이브러리를 사용하여 다음과 같이 시도합니다.

long start_time, end_time, elapsed;

start_time = clock();
// Do something
end_time = clock();

elapsed = (end_time - start_time) / CLOCKS_PER_SEC * 1000;

Linux 시스템이 지원하는 경우 clock_gettime(CLOCK_MONOTONIC)은 시스템 날짜 변경(NTP 데몬 등)의 영향을 받지 않는 고해상도 타이머여야 합니다.

위와 아래의 GNU 환경에 대한 훌륭한 답변...

그러나 OS 상에서 동작하고 있지 않은 경우는?(또는 PC에서 동작하고 있지 않은 경우는, 타이머가 자동적으로 중단되는 타이밍을 설정할 필요가 있습니다).다음은 x86 CPU 타임스탬프 카운터를 직접 사용하는 솔루션입니다.이것이 좋은 프랙티스이기 때문은 아닙니다.OS에서 실행할 때는, 절대로 실행할 필요가 없습니다.

  • 주의: 주파수 스케일링이 비활성화되어 있는 x86에서만 동작합니다.
  • Linux 에서는, 체크리스 이외의 커널에서만 동작합니다.

rdtsc.c:

#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned long long int64;

static __inline__ int64 getticks(void)
{
     unsigned a, d;
     asm volatile("rdtsc" : "=a" (a), "=d" (d));
     return (((int64)a) | (((int64)d) << 32));
}

int main(){

     int64 tick,tick1;
     unsigned time=0,mt;

     // mt is the divisor to give microseconds

     FILE *pf;
     int i,r,l,n=0;
     char s[100];

     // time how long it takes to get the divisors, as a test 
     tick = getticks();

     // get the divisors  - todo: for max performance this can 
     // output a new binary or library with these values hardcoded 
     // for the relevant CPU - if you use the equivalent assembler for
     // that CPU
     pf = fopen("/proc/cpuinfo","r");
     do {
      r=fscanf(pf,"%s",&s[0]);
      if (r<0) {
       n=5; break;
      } else if (n==0) {
       if (strcmp("MHz",s)==0) n=1;
      } else if (n==1) {
       if (strcmp(":",s)==0) n=2;
      } else if (n==2) {
       n=3;
      };
     } while (n<3);
     fclose(pf);

     s[9]=(char)0;
     strcpy(&s[4],&s[5]);
     mt=atoi(s);

     printf("#define mt %u // (%s Hz) hardcode this for your a CPU-specific binary ;-)\n",mt,s);

     tick1 = getticks();
     time = (unsigned)((tick1-tick)/mt);
     printf("%u ms\n",time);

     // time the duration of sleep(1) - plus overheads ;-)
     tick = getticks();

     sleep(1);

     tick1 = getticks();
     time = (unsigned)((tick1-tick)/mt);
     printf("%u ms\n",time);

     return 0;
}

컴파일하여 실행하다

$ gcc rdtsc.c - o rdtsc & . / rdtsc

/proc/cpuinfo에서 CPU의 제수를 읽고 읽는데 걸린 시간(마이크로초)과 sleep(1)을 실행하는 데 걸린 시간(마이크로초)을 나타냅니다./proc/cpuinfo의 Mhz 정격에 항상 소수점 3자리가 포함되어 있다고 가정합니다.-o

언급URL : https://stackoverflow.com/questions/2150291/how-do-i-measure-a-time-interval-in-c

반응형