Mesurer facilement le temps écoulé
je suis en train d'utiliser time() pour mesurer les différents points de mon programme.
Ce que je ne comprends pas, c'est pourquoi les valeurs avant et après sont les mêmes? Je comprends que ce n'est pas la meilleure façon de profiler mon programme, je veux juste voir combien de temps ça prend.
printf("**MyProgram::before time= %ldn", time(NULL));
doSomthing();
doSomthingLong();
printf("**MyProgram::after time= %ldn", time(NULL));
j'ai essayé:
struct timeval diff, startTV, endTV;
gettimeofday(&startTV, NULL);
doSomething();
doSomethingLong();
gettimeofday(&endTV, NULL);
timersub(&endTV, &startTV, &diff);
printf("**time taken = %ld %ldn", diff.tv_sec, diff.tv_usec);
Comment lire un résultat de **time taken = 0 26339
? Est-ce que ça veut dire 26.339 nanosecondes = 26.3 ms?
et **time taken = 4 45025
, ça veut dire 4 secondes et 25 msec?
22 réponses
#include <ctime>
void f() {
using namespace std;
clock_t begin = clock();
code_to_time();
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
}
la fonction time()
n'est précise qu'à une seconde près, mais il y a CLOCKS_PER_SEC
"horloges" dans une seconde. Il s'agit d'une mesure facile et portable, même si elle est trop simplifiée.
Vous pouvez résumé de la mesure du temps d'mécanisme de et ont chacun appelable du temps d'exécution mesuré avec supplémentaire minimal code , tout en étant appelé par le biais d'une minuterie de la structure. De plus, au moment de la compilation, vous pouvez paramétrer le type de timing (millisecondes, nanosecondes etc).
merci à la revue Loki Astari et la suggestion d'utiliser des gabarits variadiques. Ce est pourquoi l'envoyé de l'appel de fonction.
#include <iostream>
#include <chrono>
template<typename TimeT = std::chrono::milliseconds>
struct measure
{
template<typename F, typename ...Args>
static typename TimeT::rep execution(F&& func, Args&&... args)
{
auto start = std::chrono::steady_clock::now();
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
auto duration = std::chrono::duration_cast< TimeT>
(std::chrono::steady_clock::now() - start);
return duration.count();
}
};
int main() {
std::cout << measure<>::execution(functor(dummy)) << std::endl;
}
selon le commentaire de Howard Hinnant il est préférable de ne pas s'échapper du système chrono jusqu'à ce que nous devons. Si la classe ci-dessus pourrait donner à l'utilisateur le choix d'appeler count
manuellement en fournissant une méthode statique supplémentaire (indiquée en C++14)
template<typename F, typename ...Args>
static auto duration(F&& func, Args&&... args)
{
auto start = std::chrono::steady_clock::now();
std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
return std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now()-start);
}
// call .count() manually later when needed (eg IO)
auto avg = (measure<>::duration(func) + measure<>::duration(func)) / 2.0;
et être le plus utile pour les clients que
"voulez de post-traiter un tas de durées avant I/O (p. ex. moyenne)"
le code complet peut être trouvé ici . Ma tentative de construire un outil de benchmarking basé sur chrono est enregistré ici .
si C++17 std::invoke
est disponible, l'invocation du callable dans execution
pourrait être faite comme ceci:
invoke(forward<decltype(func)>(func), forward<Args>(args)...);
pour fournir des callables qui sont des pointeurs vers les fonctions des membres.
//***C++11 Style:***
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() <<std::endl;
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds> (end - begin).count() <<std::endl;
Comme je peux le voir dans votre question, il semble que vous voulez savoir le temps écoulé après l'exécution d'un morceau de code. Je suppose que vous seriez à l'aise de voir les résultats en seconde(s). Si c'est le cas, essayez d'utiliser la fonction difftime()
comme indiqué ci-dessous. Espérons que cela résout votre problème.
#include <time.h>
#include <stdio.h>
time_t start,end;
time (&start);
.
.
.
<your code>
.
.
.
time (&end);
double dif = difftime (end,start);
printf ("Elasped time is %.2lf seconds.", dif );
Windows only: (la balise Linux a été ajoutée après que j'ai posté cette réponse)
vous pouvez utiliser GetTickCount () pour obtenir le nombre de millisecondes qui se sont écoulées depuis le démarrage du système.
long int before = GetTickCount();
// Perform time-consuming operation
long int after = GetTickCount();
time(NULL)
renvoie le nombre de secondes écoulées depuis le 01/01/1970 à 00:00 ( l'Époque ). Donc, la différence entre les deux valeurs est le nombre de secondes de votre traitement pris.
int t0 = time(NULL);
doSomthing();
doSomthingLong();
int t1 = time(NULL);
printf ("time = %d secs\n", t1 - t0);
vous pouvez obtenir des résultats plus précis avec getttimeofday()
, qui renvoient le temps courant en secondes, comme time()
le fait et aussi en microsecondes.
la fonction Time (NULL) retournera le nombre de secondes écoulées depuis le 01/01/1970 à 00:00. Et parce que, cette fonction est appelée à un moment différent dans votre programme, elle sera toujours différente de Temps en C++
#include<time.h> // for clock
#include<math.h> // for fmod
#include<cstdlib> //for system
#include <stdio.h> //for delay
using namespace std;
int main()
{
clock_t t1,t2;
t1=clock(); // first time capture
// Now your time spanning loop or code goes here
// i am first trying to display time elapsed every time loop runs
int ddays=0; // d prefix is just to say that this variable will be used for display
int dhh=0;
int dmm=0;
int dss=0;
int loopcount = 1000 ; // just for demo your loop will be different of course
for(float count=1;count<loopcount;count++)
{
t2=clock(); // we get the time now
float difference= (((float)t2)-((float)t1)); // gives the time elapsed since t1 in milliseconds
// now get the time elapsed in seconds
float seconds = difference/1000; // float value of seconds
if (seconds<(60*60*24)) // a day is not over
{
dss = fmod(seconds,60); // the remainder is seconds to be displayed
float minutes= seconds/60; // the total minutes in float
dmm= fmod(minutes,60); // the remainder are minutes to be displayed
float hours= minutes/60; // the total hours in float
dhh= hours; // the hours to be displayed
ddays=0;
}
else // we have reached the counting of days
{
float days = seconds/(24*60*60);
ddays = (int)(days);
float minutes= seconds/60; // the total minutes in float
dmm= fmod(minutes,60); // the rmainder are minutes to be displayed
float hours= minutes/60; // the total hours in float
dhh= fmod (hours,24); // the hours to be displayed
}
cout<<"Count Is : "<<count<<"Time Elapsed : "<<ddays<<" Days "<<dhh<<" hrs "<<dmm<<" mins "<<dss<<" secs";
// the actual working code here,I have just put a delay function
delay(1000);
system("cls");
} // end for loop
}// end of main
les valeurs imprimées par votre second programme sont des secondes, et des microsecondes.
0 26339 = 0.026'339 s = 26339 µs
4 45025 = 4.045'025 s = 4045025 µs
struct profiler
{
std::string name;
std::chrono::high_resolution_clock::time_point p;
profiler(std::string const &n) :
name(n), p(std::chrono::high_resolution_clock::now()) { }
~profiler()
{
using dura = std::chrono::duration<double>;
auto d = std::chrono::high_resolution_clock::now() - p;
std::cout << name << ": "
<< std::chrono::duration_cast<dura>(d).count()
<< std::endl;
}
};
#define PROFILE_BLOCK(pbn) profiler _pfinstance(pbn)
utilisation est ci-dessous::
{
PROFILE_BLOCK("Some time");
// your code or function
}
ce champ d'application est similaire à celui de la Rai I
notez que ce n'est pas le mien, mais j'ai pensé que c'était pertinent ici
#include <ctime>
#include <cstdio>
#include <iostream>
#include <chrono>
#include <sys/time.h>
using namespace std;
using namespace std::chrono;
void f1()
{
high_resolution_clock::time_point t1 = high_resolution_clock::now();
high_resolution_clock::time_point t2 = high_resolution_clock::now();
double dif = duration_cast<nanoseconds>( t2 - t1 ).count();
printf ("Elasped time is %lf nanoseconds.\n", dif );
}
void f2()
{
timespec ts1,ts2;
clock_gettime(CLOCK_REALTIME, &ts1);
clock_gettime(CLOCK_REALTIME, &ts2);
double dif = double( ts2.tv_nsec - ts1.tv_nsec );
printf ("Elasped time is %lf nanoseconds.\n", dif );
}
void f3()
{
struct timeval t1,t0;
gettimeofday(&t0, 0);
gettimeofday(&t1, 0);
double dif = double( (t1.tv_usec-t0.tv_usec)*1000);
printf ("Elasped time is %lf nanoseconds.\n", dif );
}
void f4()
{
high_resolution_clock::time_point t1 , t2;
double diff = 0;
t1 = high_resolution_clock::now() ;
for(int i = 1; i <= 10 ; i++)
{
t2 = high_resolution_clock::now() ;
diff+= duration_cast<nanoseconds>( t2 - t1 ).count();
t1 = t2;
}
printf ("high_resolution_clock:: Elasped time is %lf nanoseconds.\n", diff/10 );
}
void f5()
{
timespec ts1,ts2;
double diff = 0;
clock_gettime(CLOCK_REALTIME, &ts1);
for(int i = 1; i <= 10 ; i++)
{
clock_gettime(CLOCK_REALTIME, &ts2);
diff+= double( ts2.tv_nsec - ts1.tv_nsec );
ts1 = ts2;
}
printf ("clock_gettime:: Elasped time is %lf nanoseconds.\n", diff/10 );
}
void f6()
{
struct timeval t1,t2;
double diff = 0;
gettimeofday(&t1, 0);
for(int i = 1; i <= 10 ; i++)
{
gettimeofday(&t2, 0);
diff+= double( (t2.tv_usec-t1.tv_usec)*1000);
t1 = t2;
}
printf ("gettimeofday:: Elasped time is %lf nanoseconds.\n", diff/10 );
}
int main()
{
// f1();
// f2();
// f3();
f6();
f4();
f5();
return 0;
}
en interne, la fonction accédera à l'horloge du système, c'est pourquoi elle renvoie des valeurs différentes chaque fois que vous l'appelez. En général, avec les langages non fonctionnels, il peut y avoir beaucoup d'effets secondaires et d'États cachés dans les fonctions que vous ne pouvez pas voir simplement en regardant le nom et les arguments de la fonction.
l'appel de fonction time(NULL)
retournera le nombre de secondes écoulées depuis epoc: 1er janvier 1970. Peut-être voulez-vous faire la différence entre deux repères temporels:
size_t start = time(NULL);
doSomthing();
doSomthingLong();
printf ("**MyProgram::time elapsed= %lds\n", time(NULL) - start);
de ce qui est voir, tv_sec stocke les secondes écoulées tandis que tv_usec stocke les microsecondes écoulées séparément. Et ce ne sont pas des conversions les unes des autres. Par conséquent, ils doivent être changés en unité appropriée et ajoutés pour obtenir le temps total écoulé.
struct timeval startTV, endTV;
gettimeofday(&startTV, NULL);
doSomething();
doSomethingLong();
gettimeofday(&endTV, NULL);
printf("**time taken in microseconds = %ld\n",
(endTV.tv_sec * 1e6 + endTV.tv_usec - (startTV.tv_sec * 1e6 + startTV.tv_usec))
);
Sur linux, clock_gettime() est l'un des bons choix. Vous devez relier la bibliothèque temps réel(-lrt).
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#define BILLION 1000000000L;
int main( int argc, char **argv )
{
struct timespec start, stop;
double accum;
if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) {
perror( "clock gettime" );
exit( EXIT_FAILURE );
}
system( argv[1] );
if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) {
perror( "clock gettime" );
exit( EXIT_FAILURE );
}
accum = ( stop.tv_sec - start.tv_sec )
+ ( stop.tv_nsec - start.tv_nsec )
/ BILLION;
printf( "%lf\n", accum );
return( EXIT_SUCCESS );
}
comme d'autres l'ont déjà noté, la fonction time() de la bibliothèque standard C n'a pas de résolution meilleure qu'une seconde. La seule fonction c entièrement portable qui peut fournir une meilleure résolution semble être clock(), mais qui mesure le temps processeur plutôt que wallclock time. Si l'on se contente de se limiter aux plates-formes POSIX (par exemple Linux), alors la fonction clock_gettime() est un bon choix.
depuis C++11, Il ya beaucoup mieux installations disponibles qui offrent une meilleure résolution sous une forme qui devrait être très portable à travers différents compilateurs et systèmes d'exploitation. De même, la bibliothèque boost::datetime fournit de bonnes classes de synchronisation à haute résolution qui devraient être hautement portables.
l'un des défis que pose l'utilisation de l'une ou l'autre de ces installations est le délai introduit par la vérification de l'horloge du système. D'expérimenter avec clock_gettime (), boost:: datetime et std:: chrono, ce délai peut facilement être une question de microsecondes. Ainsi, lorsque vous mesurez la durée de n'importe quelle partie de votre code, vous devez tenir compte de l'existence d'une erreur de mesure d'environ cette taille, ou essayer de corriger cette erreur zéro d'une façon ou d'une autre. Idéalement, vous pourriez vouloir recueillir de multiples mesures du temps pris par votre fonction, et de calculer la moyenne, ou le temps maximum/minimum pris à travers de nombreux passages.
pour aider avec toutes ces portabilité et la collecte de statistiques questions, j'ai été le développement de la cxx-rtimers bibliothèque disponible sur Github qui tente de fournir une API simple pour le calendrier des blocs de code C++, informatique zéro des erreurs, et des rapports statistiques à partir de plusieurs minuteries intégrées dans votre code. Si vous avez un compilateur C++11, Vous avez simplement #include <rtimers/cxx11.hpp>
, et utilisez quelque chose comme:
void expensiveFunction() {
static rtimers::cxx11::DefaultTimer timer("expensiveFunc");
auto scopedStartStop = timer.scopedStart();
// Do something costly...
}
à la sortie du programme, vous obtiendrez un résumé des statistiques de temps écrit à std:: cerr tel que:
Timer(expensiveFunc): <t> = 6.65289us, std = 3.91685us, 3.842us <= t <= 63.257us (n=731)
qui montre le temps moyen, son écart-type, les limites supérieure et inférieure, et le nombre de fois que cette fonction a été appelée.
si vous voulez utiliser des fonctions de synchronisation spécifiques à Linux, vous pouvez #include <rtimers/posix.hpp>
, ou si vous avez les bibliothèques Boost mais un ancien compilateur C++, vous pouvez #include <rtimers/boost.hpp>
. Il existe également des versions de ces classes de minuterie qui peuvent recueillir des informations statistiques sur le temps à partir de plusieurs fils. Il y a également d'autres méthodes permet d'estimer l'erreur zéro associée à deux requêtes consécutives de l'horloge du système.
ce sont les mêmes parce que votre fonction doSomething arrive plus vite que la granularité du minuteur. Essayez:
printf ("**MyProgram::before time= %ld\n", time(NULL));
for(i = 0; i < 1000; ++i) {
doSomthing();
doSomthingLong();
}
printf ("**MyProgram::after time= %ld\n", time(NULL));
la raison pour laquelle les deux valeurs sont les mêmes est que votre longue procédure ne prend pas que longtemps - moins d'une seconde. Vous pouvez essayer juste d'ajouter une longue boucle (pour (int i = 0; i < 100000000; I++) ; ) à la fin de la fonction pour s'assurer que c'est le problème, alors nous pouvons partir de là...
dans le cas où ce qui précède s'avère être vrai, vous aurez besoin de trouver une fonction système différente (je comprends que vous travaillez sur linux, donc je ne peux pas vous aider avec le nom de la fonction) pour mesurer le temps avec plus de précision. Je suis sûr qu'il y a une fonction similaire à GetTickCount() dans linux, vous avez juste besoin de la trouver.
j'utilise habituellement ce qui suit:
#include <chrono>
#include <type_traits>
using perf_clock = std::conditional<
std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock,
std::chrono::steady_clock
>::type;
using floating_seconds = std::chrono::duration<double>;
template<class F, class... Args>
floating_seconds run_test(Func&& func, Args&&... args)
{
const auto t0 = perf_clock::now();
std::forward<Func>(func)(std::forward<Args>(args)...);
return floating_seconds(perf_clock::now() - t0);
}
c'est la même chose que @nikos-athanasiou a proposé sauf que j'évite d'utiliser une horloge non stable et utilise un nombre de secondes flottant comme Durée.
c++ std::chrono a un avantage évident d'être multiplateforme.
Cependant, il introduit également un frais généraux significatif par rapport à POSIX clock_gettime().
Sur ma Linux box tous les std::chrono::xxx_clock::now()
saveurs effectuer à peu près la même chose:
std::chrono::system_clock::now()
std::chrono::steady_clock::now()
std::chrono::high_resolution_clock::now()
bien que POSIX clock_gettime(CLOCK_MONOTONIC, &time)
devrait être identique à steady_clock::now()
mais il est plus de x3 fois plus rapide!
Voici mon test, pour être complet.
#include <stdio.h>
#include <chrono>
#include <ctime>
void print_timediff(const char* prefix, const struct timespec& start, const
struct timespec& end)
{
double milliseconds = (end.tv_nsec - start.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec) * 1e3;
printf("%s: %lf milliseconds\n", prefix, milliseconds);
}
int main()
{
int i, n = 1000000;
struct timespec start, end;
// Test stopwatch
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i) {
struct timespec dummy;
clock_gettime(CLOCK_MONOTONIC, &dummy);
}
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("clock_gettime", start, end);
// Test chrono system_clock
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i)
auto dummy = std::chrono::system_clock::now();
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("chrono::system_clock::now", start, end);
// Test chrono steady_clock
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i)
auto dummy = std::chrono::steady_clock::now();
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("chrono::steady_clock::now", start, end);
// Test chrono high_resolution_clock
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < n; ++i)
auto dummy = std::chrono::high_resolution_clock::now();
clock_gettime(CLOCK_MONOTONIC, &end);
print_timediff("chrono::high_resolution_clock::now", start, end);
return 0;
}
et c'est la sortie I obtenez lorsque compilé avec gcc7.2-O3:
clock_gettime: 24.484926 milliseconds
chrono::system_clock::now: 85.142108 milliseconds
chrono::steady_clock::now: 87.295347 milliseconds
chrono::high_resolution_clock::now: 84.437838 milliseconds
En réponse à des OP trois questions spécifiques.
"Ce que je ne comprends pas, c'est pourquoi les valeurs avant et après sont les mêmes? "
la première question et le code d'exemple montre que time()
a une résolution de 1 seconde, donc la réponse doit être que les deux fonctions s'exécutent en moins d'une seconde. mais de temps en temps (apparemment illogique) informer 1 seconde si les deux marques de minuterie chevauchent une limite d'une seconde.
L'exemple suivant utilise gettimeofday()
qui remplit cette structure
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
et le seconde question , demande: "Comment puis-je lire la suite de **time taken = 0 26339
? Est-ce que ça veut dire 26.339 nanosecondes = 26.3 msec?"
ma deuxième réponse est le temps pris est 0 secondes et 26339 microsecondes, soit 0,026339 secondes, ce qui confirme le premier exemple exécuté en moins d'une seconde.
la troisième question demande: " Qu'en est-il de **time taken = 4 45025
, est-ce que cela signifie 4 secondes et 25 msec?"
ma troisième réponse est le temps pris est de 4 secondes et 45025 microsecondes, soit 4.045025 secondes, ce qui montre que L'OP a modifié les tâches effectuées par les deux fonctions qu'il avait programmé.
vous pouvez utiliser bibliothèque SFML , qui est une bibliothèque multimédia Simple et rapide. Il comprend de nombreuses classes utiles et bien définies comme L'horloge, Socket, son, graphiques, etc. Il est si facile à utiliser et fortement recommandé.
ceci est un exemple pour cette question.
sf::Clock clock;
...
Time time1 = clock.getElapsedTime();
...
Time time2 = clock.restart();