Programing

C ++ 크로스 플랫폼 고해상도 타이머

crosscheck 2020. 11. 3. 07:40
반응형

C ++ 크로스 플랫폼 고해상도 타이머


C ++로 간단한 타이머 메커니즘을 구현하려고합니다. 코드는 Windows 및 Linux에서 작동해야합니다. 해상도는 가능한 한 정확해야합니다 (최소한 밀리 초 정확도). 이것은 이벤트 중심 디자인을 구현하는 것이 아니라 단순히 시간의 흐름을 추적하는 데 사용됩니다. 이를 수행하는 가장 좋은 도구는 무엇입니까?


C ++ 03의 경우 :

Boost.Timer 는 작동 할 수 있지만 C 기능에 따라 다르 clock므로 해상도가 충분하지 않을 수 있습니다.

Boost.Date_Time에는 이전에 Stack Overflow에서 권장되었던 ptime클래스포함되어 있습니다 . microsec_clock::local_time에 대한 문서를 참조 microsec_clock::universal_time하되 "Win32 시스템은 종종이 API를 통해 마이크로 초 해상도를 달성하지 못합니다."라는주의 사항에 유의하십시오.

STLsoft 는 무엇보다도 OS 별 API를 중심으로 씬 크로스 플랫폼 (Windows 및 Linux / Unix) C ++ 래퍼를 제공합니다. 그것의 성능 라이브러리는 당신이 필요로 할 것 몇 가지 클래스가 있습니다. (크로스 플랫폼으로 만들려면 네임 스페이스 performance_counter에 모두 존재 하는 클래스를 선택한 다음 플랫폼과 일치하는 네임 스페이스를 사용하십시오.)winstlunixstl

C ++ 11 이상 :

std::chrono라이브러리에 내장 된이 기능이 있습니다. 참조 이 답변 내용은 @HowardHinnant으로합니다.


이전 질문에 대한 답변 업데이트 :

C ++ 11에서는 다음을 사용하여 가장 높은 해상도 타이머를 이식 할 수 있습니다.

#include <iostream>
#include <chrono>
#include "chrono_io"

int main()
{
    typedef std::chrono::high_resolution_clock Clock;
    auto t1 = Clock::now();
    auto t2 = Clock::now();
    std::cout << t2-t1 << '\n';
}

출력 예 :

74 nanoseconds

"chrono_io"는 이러한 새로운 유형의 I / O 문제를 완화하기위한 확장이며 여기서 무료로 사용할 수 있습니다 .

<chrono>부스트에서 사용할 수 있는 구현도 있습니다 (출시되었는지 확실하지 않지만 여전히 트렁크에있을 수 있음).

최신 정보

이것은 std::chrono::high_resolution_clockVS11에서 몇 밀리 초가 걸리는 후속 호출에 대한 Ben의 의견에 대한 응답 입니다. 다음은 <chrono>호환 가능한 해결 방법입니다. 그러나 인텔 하드웨어에서만 작동하므로 인라인 어셈블리 (컴파일러에 따라 구문이 다름)에 들어가야하며 시스템의 클럭 속도를 클럭에 고정시켜야합니다.

#include <chrono>

struct clock
{
    typedef unsigned long long                 rep;
    typedef std::ratio<1, 2800000000>          period; // My machine is 2.8 GHz
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<clock>     time_point;
    static const bool is_steady =              true;

    static time_point now() noexcept
    {
        unsigned lo, hi;
        asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
        return time_point(duration(static_cast<rep>(hi) << 32 | lo));
    }

private:

    static
    unsigned
    get_clock_speed()
    {
        int mib[] = {CTL_HW, HW_CPU_FREQ};
        const std::size_t namelen = sizeof(mib)/sizeof(mib[0]);
        unsigned freq;
        size_t freq_len = sizeof(freq);
        if (sysctl(mib, namelen, &freq, &freq_len, nullptr, 0) != 0)
            return 0;
        return freq;
    }

    static
    bool
    check_invariants()
    {
        static_assert(1 == period::num, "period must be 1/freq");
        assert(get_clock_speed() == period::den);
        static_assert(std::is_same<rep, duration::rep>::value,
                      "rep and duration::rep must be the same type");
        static_assert(std::is_same<period, duration::period>::value,
                      "period and duration::period must be the same type");
        static_assert(std::is_same<duration, time_point::duration>::value,
                      "duration and time_point::duration must be the same type");
        return true;
    }

    static const bool invariants;
};

const bool clock::invariants = clock::check_invariants();

그래서 그것은 휴대용이 아닙니다. 그러나 자신의 인텔 하드웨어에서 고해상도 클럭을 실험하고 싶다면 이보다 더 세밀하지는 않습니다. 미리 경고하지만 오늘날의 클럭 속도는 동적으로 변경 될 수 있습니다 (실제로 컴파일 시간 상수가 아님). 그리고 다중 프로세서 시스템을 사용하면 다른 프로세서에서 타임 스탬프를 얻을 수도 있습니다. 그러나 여전히 내 하드웨어에 대한 실험은 상당히 잘 작동합니다. 밀리 초 해상도로 멈춘 경우 해결 방법이 될 수 있습니다.

이 클럭은 CPU의 클럭 속도 측면에서 지속 시간이 있습니다 (보고 한대로). 즉,이 시계는 1 / 2,800,000,000 초마다 한 번씩 틱합니다. 원하는 경우 다음을 사용하여이를 나노초 (예 :)로 변환 할 수 있습니다.

using std::chrono::nanoseconds;
using std::chrono::duration_cast;
auto t0 = clock::now();
auto t1 = clock::now();
nanoseconds ns = duration_cast<nanoseconds>(t1-t0);

변환은 CPU주기의 일부를 잘라 나노초를 형성합니다. 다른 반올림 모드도 가능하지만 다른 주제입니다.

나를 위해 이것은 18 클럭 틱만큼 낮은 기간을 반환하며 6 나노초로 잘립니다.

위의 시계에 몇 가지 "불변 검사"를 추가했는데, 그중 가장 중요한 것은 clock::period컴퓨터에 맞는지 검사하는 것입니다. 다시 말하지만, 이것은 이식 가능한 코드가 아니지만,이 시계를 사용하고 있다면 이미 그것을 약속 한 것입니다. get_clock_speed()여기에 표시된 private 함수는 OS X에서 최대 CPU 주파수를 가져 오며, 이는의 상수 분모와 같은 숫자 여야합니다 clock::period.

이 코드를 추가하면이 코드를 새 컴퓨터로 이식하고 새 컴퓨터 clock::period의 속도로 를 업데이트하는 것을 잊었을 때 디버깅 시간을 약간 절약 할 수 있습니다 . 모든 검사는 컴파일시 또는 프로그램 시작시 수행됩니다. 따라서 성능에 clock::now()최소한 의 영향을 미치지 않습니다 .


Matthew WilsonSTLSoft 라이브러리 는 플러그 앤 플레이가 가능하도록 일치하는 인터페이스와 함께 여러 타이머 유형을 제공합니다. 오퍼링 중에는 저비용이지만 저해상도 인 타이머와 고해상도이지만 고비용 인 타이머가 있습니다. 또한 스레드 전 시간을 측정하고 프로세스 당 시간을 측정하기위한 도구와 경과 시간을 측정하는 모든 도구가 있습니다.

WinSTL 하위 프로젝트에 정의 된 Windows 항목 만 다루지 만 몇 년 전 Dr. Dobb에서 다루는 전체 기사 가 있습니다 . STLSoft는 또한 UNIXSTL 하위 프로젝트에서 UNIX 타이머를 제공하며 다음과 같이 UNIX 또는 Windows를 적절하게 포함하는 "PlatformSTL"타이머를 사용할 수 있습니다.

#include <platformstl/performance/performance_counter.hpp>
#include <iostream>

int main()
{
    platformstl::performance_counter c;

    c.start();
    for(int i = 0; i < 1000000000; ++i);
    c.stop();

    std::cout << "time (s): " << c.get_seconds() << std::endl;
    std::cout << "time (ms): " << c.get_milliseconds() << std::endl;
    std::cout << "time (us): " << c.get_microseconds() << std::endl;
}

HTH


StlSoft 오픈 소스 라이브러리는 꽤 제공하는 좋은 타이머 윈도우와 리눅스 플랫폼 모두를. 자체적으로 구현하려면 소스를 살펴보십시오.


ACE 라이브러리에는 휴대용 고해상도 타이머도 있습니다.

고해상도 타이머 용 Doxygen :
http://www.dre.vanderbilt.edu/Doxygen/5.7.2/html/ace/a00244.html


이것이 가장 좋은 대답은 아니지만 다음은 고해상도 타이머에 관한 게임 개발 사이트의 몇 가지 대화입니다.

  1. http://www.gamedev.net/topic/374327-timing-is-everything/
  2. http://www.gamedev.net/topic/471804-high-resolution-timer/
  3. http://www.gamedev.net/topic/40600-high-resolution-timing-in-games/

이를 위해 boost :: posix_time 라이브러리를 적극 권장합니다. 내가 믿는 마이크로 초까지 다양한 해상도의 타이머를 지원합니다.


나는이 모두가 의지 폐쇄 소스 사내 솔루션 ....로 몇 번을 구현 보았다 #ifdef사용하여 기본 Windows 고해상도의 한 손에 타이머와 리눅스 커널 타이머 주위 솔루션 struct timeval(참조 man timeradd반면에).

당신은 이것을 추상화 할 수 있고 몇몇 오픈 소스 프로젝트가 그것을 해냈습니다-제가 마지막으로 본 것은 CoinOR 클래스 CoinTimer 이었지만 확실히 더 많은 것들이 있습니다.


SDL2 에는 탁월한 크로스 플랫폼 고해상도 타이머가 있습니다. 그러나 밀리 초 미만의 정확도가 필요한 경우 여기에 매우 작은 크로스 플랫폼 타이머 라이브러리를 작성 했습니다 . C ++ 03 및 C ++ 11 / 상위 버전의 C ++ 모두와 호환됩니다.


C ++ 라이브러리 질문에 대한 첫 번째 대답은 일반적으로 BOOST : http://www.boost.org/doc/libs/1_40_0/libs/timer/timer.htm 입니다. 이것이 당신이 원하는 것을 수행합니까? 아마 아니 겠지만 그것은 시작입니다.

문제는 당신이 휴대용을 원하고 타이머 기능이 OS에서 보편적이지 않다는 것입니다.


STLSoft 에는 UNIX와 Windows 모두에서 작동하는 타이머 클래스 세트가 포함 성능 라이브러리 가 있습니다.


귀하의 요구 사항에 대해 잘 모르겠습니다. 시간 간격을 계산하려면 아래 스레드를 참조하십시오.

C 프로그램의 경과 시간 (밀리 초) 계산


프로젝트에서 Qt 프레임 워크를 사용하는 경우 가장 좋은 해결책은 QElapsedTimer를 사용하는 것입니다.


파티에 늦었지만 아직 C ++ 11로 업그레이드 할 수없는 레거시 코드베이스에서 작업하고 있습니다. 우리 팀의 어느 누구도 C ++에 능숙하지 않기 때문에 STL과 같은 라이브러리를 추가하는 것은 어렵습니다 (다른 사람들이 배포 문제에 대해 제기 한 잠재적 인 우려 사항 외에도). 나는 베어 본 표준 시스템 라이브러리를 넘어서는 어떤 것도없이 스스로 살 수있는 매우 단순한 크로스 플랫폼 타이머가 정말로 필요했습니다. 내가 찾은 내용은 다음과 같습니다.

http://www.songho.ca/misc/timer/timer.html

사이트가 죽어도 손실되지 않도록 여기에 전체 소스를 다시 게시합니다.

    //////////////////////////////////////////////////////////////////////////////
// Timer.cpp
// =========
// High Resolution Timer.
// This timer is able to measure the elapsed time with 1 micro-second accuracy
// in both Windows, Linux and Unix system 
//
//  AUTHOR: Song Ho Ahn (song.ahn@gmail.com) - http://www.songho.ca/misc/timer/timer.html
// CREATED: 2003-01-13
// UPDATED: 2017-03-30
//
// Copyright (c) 2003 Song Ho Ahn
//////////////////////////////////////////////////////////////////////////////

#include "Timer.h"
#include <stdlib.h>

///////////////////////////////////////////////////////////////////////////////
// constructor
///////////////////////////////////////////////////////////////////////////////
Timer::Timer()
{
#if defined(WIN32) || defined(_WIN32)
    QueryPerformanceFrequency(&frequency);
    startCount.QuadPart = 0;
    endCount.QuadPart = 0;
#else
    startCount.tv_sec = startCount.tv_usec = 0;
    endCount.tv_sec = endCount.tv_usec = 0;
#endif

    stopped = 0;
    startTimeInMicroSec = 0;
    endTimeInMicroSec = 0;
}



///////////////////////////////////////////////////////////////////////////////
// distructor
///////////////////////////////////////////////////////////////////////////////
Timer::~Timer()
{
}



///////////////////////////////////////////////////////////////////////////////
// start timer.
// startCount will be set at this point.
///////////////////////////////////////////////////////////////////////////////
void Timer::start()
{
    stopped = 0; // reset stop flag
#if defined(WIN32) || defined(_WIN32)
    QueryPerformanceCounter(&startCount);
#else
    gettimeofday(&startCount, NULL);
#endif
}



///////////////////////////////////////////////////////////////////////////////
// stop the timer.
// endCount will be set at this point.
///////////////////////////////////////////////////////////////////////////////
void Timer::stop()
{
    stopped = 1; // set timer stopped flag

#if defined(WIN32) || defined(_WIN32)
    QueryPerformanceCounter(&endCount);
#else
    gettimeofday(&endCount, NULL);
#endif
}



///////////////////////////////////////////////////////////////////////////////
// compute elapsed time in micro-second resolution.
// other getElapsedTime will call this first, then convert to correspond resolution.
///////////////////////////////////////////////////////////////////////////////
double Timer::getElapsedTimeInMicroSec()
{
#if defined(WIN32) || defined(_WIN32)
    if(!stopped)
        QueryPerformanceCounter(&endCount);

    startTimeInMicroSec = startCount.QuadPart * (1000000.0 / frequency.QuadPart);
    endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);
#else
    if(!stopped)
        gettimeofday(&endCount, NULL);

    startTimeInMicroSec = (startCount.tv_sec * 1000000.0) + startCount.tv_usec;
    endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;
#endif

    return endTimeInMicroSec - startTimeInMicroSec;
}



///////////////////////////////////////////////////////////////////////////////
// divide elapsedTimeInMicroSec by 1000
///////////////////////////////////////////////////////////////////////////////
double Timer::getElapsedTimeInMilliSec()
{
    return this->getElapsedTimeInMicroSec() * 0.001;
}



///////////////////////////////////////////////////////////////////////////////
// divide elapsedTimeInMicroSec by 1000000
///////////////////////////////////////////////////////////////////////////////
double Timer::getElapsedTimeInSec()
{
    return this->getElapsedTimeInMicroSec() * 0.000001;
}



///////////////////////////////////////////////////////////////////////////////
// same as getElapsedTimeInSec()
///////////////////////////////////////////////////////////////////////////////
double Timer::getElapsedTime()
{
    return this->getElapsedTimeInSec();
}

및 헤더 파일 :

//////////////////////////////////////////////////////////////////////////////
// Timer.h
// =======
// High Resolution Timer.
// This timer is able to measure the elapsed time with 1 micro-second accuracy
// in both Windows, Linux and Unix system 
//
//  AUTHOR: Song Ho Ahn (song.ahn@gmail.com) - http://www.songho.ca/misc/timer/timer.html
// CREATED: 2003-01-13
// UPDATED: 2017-03-30
//
// Copyright (c) 2003 Song Ho Ahn
//////////////////////////////////////////////////////////////////////////////

#ifndef TIMER_H_DEF
#define TIMER_H_DEF

#if defined(WIN32) || defined(_WIN32)   // Windows system specific
#include <windows.h>
#else          // Unix based system specific
#include <sys/time.h>
#endif


class Timer
{
public:
    Timer();                                    // default constructor
    ~Timer();                                   // default destructor

    void   start();                             // start timer
    void   stop();                              // stop the timer
    double getElapsedTime();                    // get elapsed time in second
    double getElapsedTimeInSec();               // get elapsed time in second (same as getElapsedTime)
    double getElapsedTimeInMilliSec();          // get elapsed time in milli-second
    double getElapsedTimeInMicroSec();          // get elapsed time in micro-second


protected:


private:
    double startTimeInMicroSec;                 // starting time in micro-second
    double endTimeInMicroSec;                   // ending time in micro-second
    int    stopped;                             // stop flag 
#if defined(WIN32) || defined(_WIN32)
    LARGE_INTEGER frequency;                    // ticks per second
    LARGE_INTEGER startCount;                   //
    LARGE_INTEGER endCount;                     //
#else
    timeval startCount;                         //
    timeval endCount;                           //
#endif
};

#endif // TIMER_H_DEF

참고 URL : https://stackoverflow.com/questions/1487695/c-cross-platform-high-resolution-timer

반응형