Minuterie À Haute Résolution C++ Multiplateformes

je cherche à implémenter un mécanisme de minuterie simple en C++. Le code devrait fonctionner sous Windows et Linux. La résolution doit être aussi précise que possible (précision d'au moins une milliseconde). Cela servira simplement à suivre le passage du temps, et non à mettre en œuvre tout type de conception axée sur l'événement. Quel est le meilleur outil pour faire ça?

67
demandé sur Amish Programmer 2009-09-28 19:27:17

14 réponses

Pour Le C++03 :

coup de pouce.Timer pourrait fonctionner, mais il dépend de la fonction C clock et donc peut-être pas assez de résolution pour vous.

coup de pouce.Date_Time inclut une ptime classe qui a été recommandé sur le débordement de pile avant. Voir ses docs sur microsec_clock::local_time et microsec_clock::universal_time , mais notez sa mise en garde que " les systèmes Win32 souvent ne parviennent pas à résolution microseconde via cette API."

STLsoft fournit, entre autres choses, des sous-couches (Windows et Linux/Unix) c++ autour D'API spécifiques à OS. Son performance library a plusieurs classes qui feraient ce que vous avez besoin. (Pour le faire traverser la plateforme, choisissez une classe comme performance_counter qui existe à la fois dans les espaces de noms winstl et unixstl , puis utilisez l'espace de noms qui correspond à votre plateforme.)

pour C++11 et plus :

cette fonctionnalité est intégrée à la bibliothèque std::chrono . Voir cette réponse par @HowardHinnant pour plus de détails.

37
répondu Josh Kelley 2017-05-23 10:31:16

mise à jour de la réponse à une ancienne question:

en C++11 Vous pouvez facilement accéder au minuteur de la plus haute résolution avec:

#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';
}

exemple de sortie:

74 nanoseconds

"chrono_io" est une extension pour faciliter les entrées/sorties avec ces nouveaux types et est disponible gratuitement ici .

il ya aussi une mise en œuvre de <chrono> disponible dans boost (pourrait encore être sur bout de tronc, pas sûr qu'il ait été libéré).

mise à Jour

Ceci est en réponse au commentaire de Ben ci-dessous que les appels subséquents à std::chrono::high_resolution_clock prennent plusieurs millisecondes dans VS11. Vous trouverez ci-dessous une solution de contournement compatible <chrono> . Cependant, il ne fonctionne que sur le matériel Intel, vous avez besoin de plonger dans l'assemblage en ligne (la syntaxe pour faire cela varie avec le compilateur), et vous devez hardwire la vitesse d'horloge de la machine dans l'horloge:

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

donc il n'est pas portable. Mais si vous voulez expérimenter avec une horloge à haute résolution sur votre propre matériel intel, ça ne devient pas plus fin que ça. Bien que prévenues, les vitesses d'horloge d'aujourd'hui peuvent changer dynamiquement (elles ne sont pas vraiment une constante de temps de compilation). Et avec une machine multiprocesseur, vous pouvez même obtenir des horodateurs de différents processeurs. Mais quand même, les expériences sur mon matériel fonctionnent assez bien. Si vous êtes coincé avec milliseconde, ce pourrait être une solution de contournement.

cette horloge a une durée en termes de la vitesse d'horloge de votre cpu (comme vous l'avez signalé). I. e. pour moi, cette horloge une fois tous les 1/2,800,000,000 de seconde. Si vous le souhaitez, vous pouvez convertir cette nanosecondes (par exemple) avec:

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

la conversion tronquera les fractions d'un cycle cpu pour former la nanoseconde. D'autres modes sont possibles, mais c'est un autre sujet.

pour cela me ramènera une durée aussi basse que 18 Tic-Tac d'horloge, qui se tronque à 6 nanosecondes.

j'ai ajouté une" vérification invariante "à l'horloge ci-dessus, dont la plus importante est de vérifier que le clock::period est correct pour la machine. Encore une fois, ce n'est pas du code portable, mais si vous utilisez cette horloge, vous vous y êtes déjà engagé. La fonction privée get_clock_speed() affichée ici obtient la fréquence cpu maximale sur OS X, et ce devrait être le même nombre que le dénominateur constant de clock::period .

ajouter ceci vous fera gagner un peu de temps de débogage lorsque vous porterez ce code sur votre nouvelle machine et oublierez de mettre à jour le clock::period à la vitesse de votre nouvelle machine. Toute la vérification est effectuée soit à la compilation ou au démarrage du programme. Cela n'aura donc aucun impact sur la performance de clock::now() .

136
répondu Howard Hinnant 2014-11-29 17:14:17

Matthew Wilson 's stlsoft libraries fournir plusieurs types de minuteries, avec des interfaces congruentes de sorte que vous pouvez plug-and-play. Parmi les offres, il y a des minuteries à faible coût mais à faible résolution, et des minuteries à haute résolution mais à coût élevé. Il y en a aussi pour mesurer les temps de pré-filetage et pour mesurer les temps par processus, ainsi que tout ce qui mesure les temps écoulés.

il y a une liste exhaustive article Le couvrant dans de Dr.Dob d'il y a quelques années, bien qu'il ne couvre que les fenêtres, celles définies dans le sous-projet WinSTL. STLSoft prévoit également des minuteries UNIX dans le sous-projet UNIXSTL, et vous pouvez utiliser le "PlatformSTL", qui inclut le UNIX ou Windows one selon le cas, comme dans:

#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

5
répondu dcw 2009-09-29 20:01:51

Le StlSoft bibliothèque open source fournit une assez bon timer sur windows et plates-formes linux. Si vous voulez le mettre en œuvre vous-même, jetez un coup d'oeil à leurs sources.

4
répondu Malte Clasen 2009-09-28 15:34:57

la bibliothèque ACE a des minuteries haute résolution portatives aussi.

Doxygen pour la haute résolution de la minuterie:

http://www.dre.vanderbilt.edu/Doxygen/5.7.2/html/ace/a00244.html

4
répondu 2009-09-28 15:39:32

ce n'est pas la meilleure réponse, mais voici quelques conversations sur un site de développement de Jeux concernant les minuteurs haute résolution:

  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 /
4
répondu Eric Palakovich Carr 2013-08-28 14:50:34

je recommande fortement boost::posix_time bibliothèque pour cela. Il prend en charge les minuteries dans diverses résolutions jusqu'à microsecondes je crois

3
répondu Maciek 2009-09-28 22:10:04

la première réponse aux questions des bibliothèques C++ est généralement BOOST: http://www.boost.org/doc/libs/1_40_0/libs/timer/timer.htm . Est-ce à faire ce que vous voulez? Probablement pas, mais c'est un début.

le problème est que vous voulez portable et les fonctions de minuterie ne sont pas universels dans OSes.

2
répondu jmucchiello 2009-09-28 15:32:19

j'ai vu cela mis en œuvre à quelques reprises comme des solutions internes à source fermée .... qui ont tous eu recours à des solutions #ifdef autour des temporisateurs hi-res natifs de Windows d'une part et des temporisateurs du noyau Linux utilisant struct timeval (voir man timeradd ) d'autre part.

vous pouvez abstraire ceci et quelques projets Open Source l'ont fait -- le dernier que j'ai regardé était le Classe CoinOR CoinTimer mais il y a sûrement plusieurs d'entre eux.

2
répondu Dirk Eddelbuettel 2009-09-28 15:40:20

STLSoft ont une bibliothèque de performances , qui comprend un ensemble de classes de minuterie, certains qui fonctionnent à la fois pour UNIX et Windows.

2
répondu JamieH 2009-09-29 19:51:56

SDL2 est doté d'une excellente minuterie à haute résolution. Si toutefois vous avez besoin d'une précision de sous-milliseconde, j'ai écrit une très petite bibliothèque de minuterie multiplateformes ici . Il est compatible avec les versions C++03 et C++11/supérieures de C++.

2
répondu metamorphosis 2017-01-11 20:43:58

Je ne suis pas sûr de votre exigence, si vous voulez calculer l'intervalle de temps s'il vous plaît voir le fil ci-dessous

calcul du temps écoulé dans un programme C en millisecondes

1
répondu Satbir 2017-05-23 11:54:48

si l'on utilise le cadre Qt dans le projet, la meilleure solution est probablement D'utiliser QElapsedTimer.

0
répondu lpapp 2014-04-05 13:29:06

la Fin de la partie ici, mais je travaille dans un héritage de la base de code qui ne peut pas être mis à niveau vers c++11 encore. Personne dans notre équipe n'est très compétent en c++, donc l'ajout d'une bibliothèque comme STL s'avère difficile (en plus des préoccupations potentielles que d'autres ont soulevées au sujet des problèmes de déploiement). J'avais vraiment besoin d'un minuteur multiplateformes extrêmement simple qui pourrait vivre par lui-même sans rien au-delà de bare-bones bibliothèques système standard. Voici ce que j'ai trouvé:

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

la Rediffusion de l'intégralité de la source ici juste pour ne pas se perdre si le site ne meurt jamais:

    //////////////////////////////////////////////////////////////////////////////
// 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();
}

et le fichier d'en-tête:

//////////////////////////////////////////////////////////////////////////////
// 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
0
répondu Patrick 2017-06-21 22:11:39