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?
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.
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()
.
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
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.
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
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:
je recommande fortement boost::posix_time bibliothèque pour cela. Il prend en charge les minuteries dans diverses résolutions jusqu'à microsecondes je crois
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.
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.
STLSoft ont une bibliothèque de performances , qui comprend un ensemble de classes de minuterie, certains qui fonctionnent à la fois pour UNIX et Windows.
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++.
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
si l'on utilise le cadre Qt dans le projet, la meilleure solution est probablement D'utiliser QElapsedTimer.
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