Кросс-Платформенный Таймер Высокого Разрешения C++



Я ищу, чтобы реализовать простой механизм таймера в C++. Код должен работать в Windows и Linux. Разрешение должно быть максимально точным (не менее миллисекундной точности). Это будет использоваться для простого отслеживания хода времени, а не для реализации какого-либо событийного дизайна. Что является лучшим инструментом для достижения этой цели?

159   14  

14 ответов:

Для C++03:

импульс.Таймер может работать, но это зависит от функции C clock и поэтому не может иметь достаточно хорошее разрешение для вас.

импульс.Дата_время включает в себя ptime класс это было рекомендовано при переполнении стека раньше. Смотрите его документы на microsec_clock::local_time и microsec_clock::universal_time, но обратите внимание на его предостережение, что " системы Win32 часто не достигают разрешения микросекунды с помощью этого ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС."

STLsoft предоставляет, среди прочего, тонкие кросс-платформенные (Windows и Linux/Unix) оболочки C++ вокруг специфичных для ОС API. Его библиотеки производительности есть несколько классов, которые будут делать то, что вам нужно. (Чтобы сделать его кросс-платформенным, выберите класс, например performance_counter который существует в обоих winstl и unixstl пространства имен, затем используйте то пространство имен, которое соответствует вашей платформе.)

для C++11 и выше:

The 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" является расширением для облегчения проблем ввода/вывода с этими новыми типами и находится в свободном доступе здесь.

существует также реализация <chrono> доступно в boost (может все еще быть на кончике ствола, не уверен, что это было освобожденный.)

обновление

это в ответ на комментарий Бена ниже, что последующие звонки std::chrono::high_resolution_clock возьмите несколько миллисекунд в VS11. Ниже-это <chrono>-совместимое решение. Однако он работает только на оборудовании Intel, вам нужно окунуться в встроенную сборку (синтаксис для этого зависит от компилятора), и вам нужно жестко подключить тактовую частоту машины в часы:

#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();

так что это не портативный. Но если ты хочешь ... поэкспериментируйте с часами высокого разрешения на вашем собственном оборудовании intel, это не становится лучше, чем это. Хотя будьте предупреждены, сегодняшние тактовые частоты могут динамически меняться (они на самом деле не являются константой времени компиляции). И с многопроцессорной машиной вы даже можете получить отметки времени от разных процессоров. Но все же, эксперименты на моем оборудовании работают довольно хорошо. Если вы застряли с разрешением миллисекунды, это может быть обходной путь.

эти часы имеют продолжительность с точки зрения вашего тактовая частота процессора (как вы сообщили). То есть для меня эти часы тикают раз в 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);

преобразование будет усекать доли цикла процессора, чтобы сформировать наносекунду. Другие режимы округления возможны, но это другая тема.

для меня это вернет длительность до 18 тактов, которая усекается до 6 наносекунд.

у меня есть добавлена некоторая "инвариантная проверка" к вышеуказанным часам, наиболее важной из которых является проверка того, что clock::period правильно для машины. Опять же, это не портативный код, но если вы используете эти часы, вы уже сделали это. Рядовой get_clock_speed() функция, показанная здесь, получает максимальную частоту процессора на OS X, и это должно быть то же число, что и постоянный знаменатель clock::period.

добавление этого позволит вам сэкономить немного времени отладки при переносе этого кода на ваш новая машина и забудьте обновить clock::period к скорости вашей новой машины. Вся проверка выполняется либо во время компиляции, либо во время запуска программы. Так что это не повлияет на производительность clock::now() по меньшей мере.

Мэтью Уилсон ' s библиотеки STLSoft обеспечить несколько типов таймера, с конгруэнтными интерфейсами, так что вы можете подключи и играй. Среди предложений есть таймеры, которые являются недорогими, но с низким разрешением, и те, которые имеют высокое разрешение, но имеют высокую стоимость. Также одни для измерять времена пре-потока и для измерять в-отростчатые времена, так же, как все это измеряют истекшие времена.

есть исчерпывающий статьи, охватывающие его в доктора С некоторых лет назад, хотя он охватывает только те окна, которые определены в подпроекте WinSTL. STLSoft также предоставляет таймеры UNIX в подпроекте UNIXSTL, и вы можете использовать "PlatformSTL", который включает UNIX или Windows, как это уместно, например:

#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

The StlSoft библиотека с открытым исходным кодом предоставляет достаточно хороший таймер на платформах windows и linux. Если вы хотите его реализовать самостоятельно, просто посмотрите на их источники.

библиотека ACE также имеет портативные таймеры высокого разрешения.

Doxygen для высокого разрешения timer:
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 библиотека для этого. Он поддерживает таймеры в различных разрешениях вплоть до микросекунд я считаю

первый ответ на вопросы библиотеки C++, как правило, BOOST: http://www.boost.org/doc/libs/1_40_0/libs/timer/timer.htm. это делает то, что вы хотите? Наверное, нет, но это только начало.

проблема в том, что вы хотите, чтобы портативные и таймерные функции не были универсальными в ОС.

Я видел, что это реализовано несколько раз как внутренние решения с закрытым исходным кодом .... к которому все прибегали #ifdef решения вокруг собственных таймеров Windows hi-res с одной стороны и таймеров ядра Linux с использованием struct timeval (см. man timeradd) С другой стороны.

вы можете абстрагироваться от этого, и несколько проектов с открытым исходным кодом сделали это-последний, на который я смотрел, был CoinOR класс CoinTimer но их наверняка больше.

STLSoft есть Библиотеки Производительности, который включает в себя набор классов таймера, некоторые из которых работают как для UNIX, так и для Windows.

SDL2 имеет превосходный кросс-платформенный таймер высокого разрешения. Если, однако, вам нужна суб-миллисекундная точность, я написал очень маленькую кросс-платформенную библиотеку таймеров здесь. Он совместим как с C++03, так и с++11/более высокими версиями C++.

Я не уверен в вашем требовании, если вы хотите рассчитать интервал времени, пожалуйста, смотрите поток ниже

вычисление затраченного времени в программе C в миллисекундах

Если вы используете Qt framework в проекте, лучшим решением, вероятно, является использование 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
    Ничего не найдено.

Добавить ответ:
Отменить.