Verstrichene Zeit einfach messen


297

Ich versuche, time () zu verwenden, um verschiedene Punkte meines Programms zu messen.

Was ich nicht verstehe ist, warum die Werte im Vorher und Nachher gleich sind? Ich verstehe, dass dies nicht der beste Weg ist, mein Programm zu profilieren. Ich möchte nur sehen, wie lange etwas dauert.

printf("**MyProgram::before time= %ld\n", time(NULL));

doSomthing();
doSomthingLong();

printf("**MyProgram::after time= %ld\n", time(NULL));

Ich habe versucht:

struct timeval diff, startTV, endTV;

gettimeofday(&startTV, NULL); 

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL); 

timersub(&endTV, &startTV, &diff);

printf("**time taken = %ld %ld\n", diff.tv_sec, diff.tv_usec);

Wie lese ich ein Ergebnis von **time taken = 0 26339? Bedeutet das 26.339 Nanosekunden = 26,3 ms?

Was ist mit **time taken = 4 450254 Sekunden und 25 ms?


10
Ich verstehe die Frage nicht. Natürlich sind die Werte unterschiedlich. Die dazwischen verstrichene Zeit time()gibt also einen anderen Wert zurück.
Thomas

1
Was meinst du mit "Ich verstehe nicht, warum die Werte im Vorher und Nachher unterschiedlich sind"? Sie erhalten die aktuelle Zeit (in Sekunden seit dem 1. Januar 1970) mit time(NULL)... das zweite Mal, wenn Sie sie aufrufen, sind N Sekunden nach dem ersten und somit ... anders (es sei denn, was auch immer Sie tun, tut es nicht. ' Es dauert keine Sekunde, bis der Vorgang abgeschlossen ist. In diesem Fall ist er derselbe wie der erste.
Brian Roach

1
Können Sie uns sagen, was gedruckt wird und wie lange es dauert, wenn Sie es mit einer Stoppuhr oder einer Wanduhr (oder einem Kalender) messen?
Matt Curtis

4
Entschuldigung, ich meine, beide Werte sind die GLEICHEN. Ich habe meine Frage falsch eingegeben.
Hap497

Antworten:


336
//***C++11 Style:***
#include <chrono>

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() << "[µs]" << std::endl;
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds> (end - begin).count() << "[ns]" << std::endl;

10
Ja, das sollte die Antwort sein
Ferenc Dajka

23
So führen Sie dies müssen Sie die Add - #include <chrono>Richtlinie und ich würde die Meldezeit ändern: std::cout << "Time difference (sec) = " << (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) /1000000.0 <<std::endl;(und nicht zu vergessen die C ++ 11 - Flag beim Kompilieren: -std=c++11)
Antonello

1
Dies misst übrigens die CPU-Zeit, nicht die Wanduhrzeit. Richtig?
Nikos

4
@ RestlessC0bra Laut den Dokumenten zu cppreference "hängt diese Uhr nicht mit der Wanduhrzeit zusammen (zum Beispiel kann es die Zeit seit dem letzten Neustart sein) und eignet sich am besten zum Messen von Intervallen."
Zylus

1
Welcher Datentyp ist das? Std :: chrono :: duration_cast <std :: chrono :: microseconds> (Ende - Anfang) .count ()
sqp_125

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

Die time()Funktion ist nur auf eine Sekunde genau, aber es gibt CLOCKS_PER_SEC"Uhren" innerhalb einer Sekunde. Dies ist eine einfache, tragbare Messung, obwohl sie zu stark vereinfacht ist.


129
Beachten Sie, dass clock()die CPU-Zeit gemessen wird und nicht die tatsächlich verstrichene Zeit (die viel größer sein kann).
Jlstrecker

12
Bei der Programmierung von parallelem Code für Cluster spiegelt diese Methode nicht die reale Zeit wider ...
Nicholas Hamilton

3
Dies scheint der einfachste Weg zu sein. Möchten Sie den Kommentar von @jlstrecker aktualisieren oder adressieren?
Lorah Attkins

5
Die oben beschriebene Lösung ist aus vielen Gründen keine gute Lösung. Dies ist die richtige Antwort - stackoverflow.com/questions/2962785/…
Xofo

1
Ich habe diese Lösung ausprobiert, und wie aus den Kommentaren hervorgeht, lief mein Timer viel schneller als in der realen Welt.
RTbecard

267

Sie können den Zeitmessmechanismus abstrahieren und die Laufzeit jedes aufrufbaren Objekts mit minimalem zusätzlichen Code messen lassen , indem Sie einfach über eine Timer-Struktur aufgerufen werden. Außerdem können Sie zur Kompilierungszeit den Timing-Typ (Millisekunden, Nanosekunden usw.) parametrisieren .

Dank der Bewertung von Loki Astari und dem Vorschlag, verschiedene Vorlagen zu verwenden. Dies ist , warum der weitergeleitet Funktionsaufruf.

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

Demo

Nach dem Kommentar von Howard Hinnant ist es am besten, nicht aus dem Chronosystem herauszukommen, bis wir müssen. Die obige Klasse kann dem Benutzer also die Möglichkeit geben,countmanuellaufzurufen,indem eine zusätzliche statische Methode bereitgestellt wird (siehe 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;

und am nützlichsten für Kunden sein, die

"Ich möchte eine Reihe von Zeiträumen vor der E / A nachbearbeiten (z. B. Durchschnitt)."


Den vollständigen Code finden Sie hier . Mein Versuch, ein auf Chrono basierendes Benchmarking-Tool zu erstellen, wird aufgezeichnet hier.


Wenn C ++ 17 std::invoke verfügbar ist, kann der Aufruf des aufrufbaren In executionfolgendermaßen erfolgen:

invoke(forward<decltype(func)>(func), forward<Args>(args)...);

um Callables bereitzustellen, die Zeiger auf Mitgliedsfunktionen sind.


2
Nett; Ich habe etwas Ähnliches in meinem Code, verwende aber eine andere Schnittstelle zur Klasse: Ich habe eine Klasse ( code_timer), die die Startzeit ( std::chrono::system_clock::now();) im Konstruktor benötigt, eine Methode code_timer::ellapsed, die den Unterschied zwischen einem neuen now()Aufruf und dem im Konstruktor misst und eine code_timer::resetMethode, die die Startzeit auf ein neues now()Ergebnis zurücksetzt . Um die Ausführung eines Funktors in meinem Code zu messen, verwende ich eine kostenlose Funktion außerhalb der Klasse. Dies ermöglicht die Messung der Zeit vom Aufbau eines Objekts bis zum Ende eines asynchronen Aufrufs.
utnapistim

7
<nitpick>: Verlassen Sie das chronoSystem erst, wenn Sie es müssen (vermeiden Sie die Verwendung von .count()). Lassen Sie den Client anrufen, .count()wenn er dazu gezwungen wird (z. B. für E / A, was in der Tat unglücklich ist). Der Client möchte möglicherweise eine Reihe von Zeiträumen vor der E / A nachbearbeiten (z. B. Durchschnitt). Dies geschieht am besten innerhalb des chronoSystems.
Howard Hinnant

1
@ user3241228 1. VS2013 unterstützt keine automatischen Rückgabetypen (nur nachfolgende Rückgabetypen - eine C ++ 14-Funktion ist noch nicht verfügbar). 2. Ich glaube, das ist der Grund, aber ich habe aq nur um sicher zu gehen
Nikos Athanasiou

2
Warum nicht std::forward<F>(func)?
Oliora

3
@oliora Es ist das gleiche. Ich bevorzuge es, std::forward<decltype(func)>(func)weil es für Argumente von generischen Lambdas ( auto&& func) gelten kann, bei denen Fes nicht syntaktisch vorhanden ist und die in einem Dienstprogrammmakro, #define fw(arg) std::forward<decltype(arg)>(arg)das ich in meiner Benchmark-Bibliothek verwende , leicht zu abstrahieren sind (es handelt sich also um eine syntaktische Überbleibsel, auf die ich nicht viel eingehen möchte die Antwort)
Nikos Athanasiou

56

Wie ich aus Ihrer Frage ersehen kann, möchten Sie anscheinend die verstrichene Zeit nach der Ausführung eines Codeteils wissen. Ich denke, Sie würden sich wohl fühlen, wenn Sie die Ergebnisse in Sekunden sehen würden. Versuchen Sie in diesem Fall difftime(), die unten gezeigte Funktion zu verwenden. Hoffe das löst dein Problem.

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

4
Dies gibt mir immer ganzzahlige Sekunden. Soll das passieren?
Natriumnitrat

10
Die Zeit gibt immer nur Sekunden zurück, daher kann sie nicht für Messungen unter einer Sekunde verwendet werden.
DeepDeadpool

31

Nur Windows: (Das Linux-Tag wurde hinzugefügt, nachdem ich diese Antwort gepostet habe.)

Mit GetTickCount () können Sie die Anzahl der Millisekunden abrufen , die seit dem Start des Systems vergangen sind.

long int before = GetTickCount();

// Perform time-consuming operation

long int after = GetTickCount();

7
Ich benutze es unter Linux. Daher kann ich die Funktion GetTickCount () nicht verwenden.
Hap497

1
schon
egal

Es funktioniert und gibt die Echtzeit an, nicht die CPU-Zeit. Ich habe es getestet , indem SleepEx(5000,0)anstelle von // Perform zeitaufwendiger Vorgang und Differenz von afterund beforewaren fast 5 Sekunden.
Ruchir

14

time(NULL)Gibt die Anzahl der Sekunden zurück, die seit dem 01.01.1970 um 00:00 Uhr ( Epoche ) vergangen sind . Der Unterschied zwischen den beiden Werten ist also die Anzahl der Sekunden, die Ihre Verarbeitung benötigt hat.

int t0 = time(NULL);
doSomthing();
doSomthingLong();
int t1 = time(NULL);

printf ("time = %d secs\n", t1 - t0);

Mit können Sie feinere Ergebnisse erzielen getttimeofday(), die die aktuelle Zeit in Sekunden time()und auch in Mikrosekunden zurückgeben.


13

Die Zeitfunktion (NULL) gibt die Anzahl der Sekunden zurück, die seit dem 01.01.1970 um 00:00 Uhr vergangen sind. Und weil diese Funktion in Ihrem Programm zu unterschiedlichen Zeiten aufgerufen wird, ist sie in C ++ immer zu unterschiedlichen Zeiten


Ich weiß nicht, warum jemand herabgestimmt hat, aber Ihre Antwort ist nicht ganz richtig. Für den Anfang gibt es nicht die Datums- und Uhrzeitangabe zurück und es wird nicht immer anders sein.
Matt Joiner

12
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)

Verwendung ist unten ::

{
    PROFILE_BLOCK("Some time");
    // your code or function
}

Dies ist ähnlich wie RAII im Umfang

HINWEIS: Dies ist nicht meins, aber ich dachte, dass es hier relevant ist


1
beinhaltet vermisst
Stepan Yakovenko

9
#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 

3
Obwohl Ihre Antwort geschätzt wird, bevorzugen wir ein Pre-Amble mit einer kurzen Beschreibung des Codes. Vielen Dank.
Kev

2
Dies ist nicht die verstrichene Zeit, sondern die Prozessorzeit.
JonnyJD

8

Die von Ihrem zweiten Programm gedruckten Werte sind Sekunden und Mikrosekunden.

0 26339 = 0.026'339 s =   26339 µs
4 45025 = 4.045'025 s = 4045025 µs

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

4

C ++ std :: chrono hat den klaren Vorteil, plattformübergreifend zu sein. Es führt jedoch auch zu einem erheblichen Overhead im Vergleich zu POSIX clock_gettime (). Auf meiner Linux-Box std::chrono::xxx_clock::now()funktionieren alle Geschmacksrichtungen ungefähr gleich:

std::chrono::system_clock::now()
std::chrono::steady_clock::now()
std::chrono::high_resolution_clock::now()

Obwohl POSIX clock_gettime(CLOCK_MONOTONIC, &time)das gleiche sein sollte wiesteady_clock::now() , ist es mehr als x3 mal schneller!

Hier ist mein Test der Vollständigkeit halber.

#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
                        ? (end.tv_nsec - start.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec) * 1e3
                        : (start.tv_nsec - end.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec - 1) * 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;
}

Und dies ist die Ausgabe, die ich beim Kompilieren mit gcc7.2 -O3 erhalte:

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

3

Der time(NULL)Funktionsaufruf gibt die Anzahl der Sekunden zurück, die seit dem Epoc: 1. Januar 1970 vergangen sind. Vielleicht möchten Sie die Differenz zwischen zwei Zeitstempeln ermitteln:

size_t start = time(NULL);
doSomthing();
doSomthingLong();

printf ("**MyProgram::time elapsed= %lds\n", time(NULL) - start);

3

Wie andere bereits bemerkt haben, hat die time () - Funktion in der C-Standardbibliothek keine bessere Auflösung als eine Sekunde. Die einzige vollständig tragbare C-Funktion, die möglicherweise eine bessere Auflösung bietet, scheint clock () zu sein, misst jedoch eher die Prozessorzeit als die Wanduhrzeit. Wenn man sich damit zufrieden gibt, sich auf POSIX-Plattformen (z. B. Linux) zu beschränken, ist die Funktion clock_gettime () eine gute Wahl.

Seit C ++ 11 gibt es viel bessere Timing-Möglichkeiten Verfügung, die eine bessere Auflösung in einer Form bieten, die für verschiedene Compiler und Betriebssysteme sehr portabel sein sollte. In ähnlicher Weise bietet die boost :: datetime-Bibliothek gute hochauflösende Timing-Klassen, die hoch portabel sein sollten.

Eine Herausforderung bei der Verwendung einer dieser Einrichtungen ist die Zeitverzögerung, die durch die Abfrage der Systemuhr eingeführt wird. Durch das Experimentieren mit clock_gettime (), boost :: datetime und std :: chrono kann diese Verzögerung leicht eine Frage von Mikrosekunden sein. Wenn Sie also die Dauer eines Teils Ihres Codes messen, müssen Sie einen Messfehler von etwa dieser Größe berücksichtigen oder versuchen, diesen Nullfehler auf irgendeine Weise zu korrigieren. Im Idealfall möchten Sie möglicherweise mehrere Messungen der von Ihrer Funktion benötigten Zeit erfassen und die durchschnittliche oder maximale / minimale Zeit berechnen, die für viele Läufe benötigt wird.

Um all diese Probleme mit der Portabilität und dem Sammeln von Statistiken zu lösen, habe ich die auf Github verfügbare cxx-rtimers-Bibliothek entwickelt, die versucht, eine einfache API für Timing-Blöcke von C ++ - Code bereitzustellen, null Fehler zu berechnen und Statistiken von mehreren eingebetteten Timern zu melden in Ihrem Code. Wenn Sie einen C ++ 11-Compiler haben, verwenden Sie einfach #include <rtimers/cxx11.hpp>Folgendes:

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensiveFunc");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}

Beim Beenden des Programms erhalten Sie eine Zusammenfassung der in std :: cerr geschriebenen Timing-Statistiken wie:

Timer(expensiveFunc): <t> = 6.65289us, std = 3.91685us, 3.842us <= t <= 63.257us (n=731)

Dies zeigt die mittlere Zeit, ihre Standardabweichung, die oberen und unteren Grenzen und die Häufigkeit, mit der diese Funktion aufgerufen wurde.

Wenn Sie Linux-spezifische Timing-Funktionen verwenden möchten, können Sie dies #include <rtimers/posix.hpp>, oder wenn Sie die Boost-Bibliotheken, aber einen älteren C ++ - Compiler haben, können Sie dies #include <rtimers/boost.hpp>. Es gibt auch Versionen dieser Timer-Klassen, die statistische Timing-Informationen aus mehreren Threads erfassen können. Es gibt auch Methoden, mit denen Sie den Nullfehler schätzen können, der mit zwei unmittelbar aufeinanderfolgenden Abfragen der Systemuhr verbunden ist.


2

Intern greift die Funktion auf die Uhr des Systems zu, weshalb sie bei jedem Aufruf unterschiedliche Werte zurückgibt. Im Allgemeinen kann es bei nicht funktionierenden Sprachen zu vielen Nebenwirkungen und versteckten Zuständen in Funktionen kommen, die Sie nicht sehen können, wenn Sie nur den Namen und die Argumente der Funktion betrachten.


2

Nach dem, was zu sehen ist, speichert tv_sec die verstrichenen Sekunden, während tv_usec die verstrichenen Mikrosekunden separat speichert. Und sie sind nicht die Bekehrungen voneinander. Daher müssen sie in die richtige Einheit geändert und hinzugefügt werden, um die verstrichene Gesamtzeit zu erhalten.

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

2

Unter Linux ist clock_gettime () eine der guten Entscheidungen. Sie müssen die Echtzeitbibliothek (-lrt) verknüpfen.

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

2

Ich musste die Ausführungszeit einzelner Funktionen innerhalb einer Bibliothek messen. Ich wollte nicht jeden Aufruf jeder Funktion mit einer Zeitmessfunktion abschließen müssen, da dies hässlich ist und den Aufrufstapel vertieft. Ich wollte auch nicht den Timer-Code oben und unten in jede Funktion einfügen, da dies zu Problemen führt, wenn die Funktion vorzeitig beendet oder beispielsweise Ausnahmen ausgelöst werden kann. Am Ende habe ich also einen Timer erstellt, der seine eigene Lebensdauer verwendet, um die Zeit zu messen.

Auf diese Weise kann ich die Wandzeit messen, die ein Codeblock benötigt, indem ich nur eines dieser Objekte am Anfang des betreffenden Codeblocks (Funktion oder ein beliebiger Bereich) instanziiere und dann dem Instruktordestruktor erlaube, die seitdem verstrichene Zeit zu messen Konstruktion, wenn die Instanz den Gültigkeitsbereich verlässt. Das vollständige Beispiel finden Sie hier, aber die Struktur ist äußerst einfach:

template <typename clock_t = std::chrono::steady_clock>
struct scoped_timer {
  using duration_t = typename clock_t::duration;
  const std::function<void(const duration_t&)> callback;
  const std::chrono::time_point<clock_t> start;

  scoped_timer(const std::function<void(const duration_t&)>& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  scoped_timer(std::function<void(const duration_t&)>&& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  ~scoped_timer() { callback(clock_t::now() - start); }
};

Die Struktur ruft Sie auf dem bereitgestellten Funktor zurück, wenn dieser außerhalb des Gültigkeitsbereichs liegt, damit Sie etwas mit den Zeitinformationen tun können (drucken oder speichern oder was auch immer). Wenn Sie etwas noch komplexer tun müssen , könnten Sie sogar verwenden std::bindmit std::placeholdersFunktionen Rückruf mit mehreren Argumenten.

Hier ist ein kurzes Beispiel für die Verwendung:

void test(bool should_throw) {
  scoped_timer<> t([](const scoped_timer<>::duration_t& elapsed) {
    auto e = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(elapsed).count();
    std::cout << "took " << e << "ms" << std::endl;
  });

  std::this_thread::sleep_for(std::chrono::seconds(1));

  if (should_throw)
    throw nullptr;

  std::this_thread::sleep_for(std::chrono::seconds(1));
}

Wenn Sie bewusster sein möchten, können Sie den Timer auch verwenden newund deleteexplizit starten und stoppen, ohne sich auf das Scoping verlassen zu müssen, um dies für Sie zu tun.


1

Sie sind dieselben, weil Ihre doSomething-Funktion schneller abläuft als die Granularität des Timers. Versuchen:

printf ("**MyProgram::before time= %ld\n", time(NULL));

for(i = 0; i < 1000; ++i) {
    doSomthing();
    doSomthingLong();
}

printf ("**MyProgram::after time= %ld\n", time(NULL));

1

Der Grund, warum beide Werte gleich sind, liegt in Ihrer langen Prozedur nicht so dauert - weniger als eine Sekunde. Sie können versuchen, am Ende der Funktion einfach eine lange Schleife (für (int i = 0; i <100000000; i ++);) hinzuzufügen, um sicherzustellen, dass dies das Problem ist. Dann können wir fortfahren ...

Falls sich herausstellt, dass das oben Gesagte zutrifft, müssen Sie eine andere Systemfunktion finden (ich verstehe, dass Sie unter Linux arbeiten, daher kann ich Ihnen mit dem Funktionsnamen nicht helfen), um die Zeit genauer zu messen. Ich bin mir sicher, dass es unter Linux eine ähnliche Funktion wie GetTickCount () gibt. Sie müssen sie nur finden.


1

Ich benutze normalerweise Folgendes:

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

Es ist dasselbe wie @ nikos-athanasiou vorgeschlagen, außer dass ich die Verwendung einer instationären Uhr vermeide und eine schwebende Anzahl von Sekunden als Dauer verwende.


1
Bei diesem Typschalter : Ist normalerweisehigh_resolution_clock ein Typedef für entweder system_clockoder steady_clock. Um zu verfolgen, dass, std::conditionalwenn das is_steadyTeil wahr ist, Sie das auswählen, high_resolution_clockwas (ein typedef zu) das ist steady_clock. Wenn es falsch ist, wählen Sie das steady_clockerneut aus. Verwenden Sie einfach steady_clockvon Anfang an ...
Nikos Athanasiou

@ nikos-athanasiou Ich stimme dem Kommentar von 5gon12eder voll und ganz zu, dass der Standard keinen "typischen" Fall vorschreibt, so dass einige STL möglicherweise auf andere Weise implementiert werden. Ich bevorzuge es, wenn mein Code allgemeiner ist und sich nicht auf Implementierungsdetails bezieht.
Oliora

Es ist nicht erforderlich, wird aber ausdrücklich in 20.12.7.3 angegeben : high_resolution_clock may be a synonym for system_clock or steady_clock. Der Grund ist folgender: high_resolution_clockStellt Uhren mit der kürzesten Tick-Periode dar. Unabhängig von der Implementierung gibt es also zwei Möglichkeiten, ob sie stabil sind oder nicht. Unabhängig davon, welche Wahl wir treffen, ist die Aussage, dass sich die Implementierung von den beiden anderen Uhren unterscheidet, gleichbedeutend mit der Aussage, dass wir eine bessere Implementierung für eine stabile (oder nicht stabile) Uhr haben, die wir nicht verwenden (für stabile oder nicht stabile Uhren). Wissen, wie gut ist, wissen, warum es besser ist
Nikos Athanasiou

@ nikos-athanasiou Ich würde es vorziehen, 100% sicher zu sein, insbesondere wenn dies mich keinen Laufzeitaufwand und keinen nicht nachweisbaren Overhead für die Kompilierungszeit kostet. Sie können sich auf "Mai" und Annahmen verlassen, wenn Sie möchten.
Oliora

Au contraire mein Freund, du bist es, der sich auf "Mai" verlässt, aber zu dir passt. Wenn Sie 100% sicher sein möchten und dies dann weiter schreiben möchten, sollten Sie auch einen Weg für Sie und Benutzer Ihres Codes finden, um zu vermeiden, dass Zeitpunkte verschiedener Uhren nicht portabel gemischt werden (falls dieser Schalter jemals eine Bedeutung erhält). es wird sich auf verschiedenen Plattformen unterschiedlich verhalten). Habe Spaß!
Nikos Athanasiou

0

Als Antwort auf die drei spezifischen Fragen von OP .

"Was ich nicht verstehe ist, warum die Werte im Vorher und Nachher gleich sind? "

Die erste Frage und der Beispielcode zeigen, dass time()sie eine Auflösung von 1 Sekunde haben. Die Antwort muss also sein, dass die beiden Funktionen in weniger als 1 Sekunde ausgeführt werden. Aber gelegentlich wird es (anscheinend unlogisch) 1 Sekunde informieren, wenn die beiden Timer-Markierungen eine Grenze von einer Sekunde überschreiten.

Das nächste Beispiel verwendet gettimeofday(), das diese Struktur ausfüllt

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

und die zweite Frage lautet : "Wie lese ich ein Ergebnis von **time taken = 0 26339? Bedeutet das 26.339 Nanosekunden = 26,3 ms?"

Meine zweite Antwort lautet: Die benötigte Zeit beträgt 0 Sekunden und 26339 Mikrosekunden, dh 0,026339 Sekunden. Dies bestätigt das erste Beispiel, das in weniger als 1 Sekunde ausgeführt wird.

Die dritte Frage lautet : "Was **time taken = 4 45025bedeutet das, bedeutet das 4 Sekunden und 25 ms?"

Meine dritte Antwort lautet: Die benötigte Zeit beträgt 4 Sekunden und 45025 Mikrosekunden, dh 4,045025 Sekunden. Dies zeigt, dass OP die Aufgaben der beiden Funktionen geändert hat, die er zuvor zeitlich festgelegt hat.


0
#include <ctime>
#include <functional>

using namespace std;

void f() {
  clock_t begin = clock();

  // ...code to measure time...

  clock_t end = clock();

  function<double(double, double)> convtime = [](clock_t begin, clock_t end)
  {
     return double(end - begin) / CLOCKS_PER_SEC;
  };

  printf("Elapsed time: %.2g sec\n", convtime(begin, end));

}

Ähnliches Beispiel wie hier, nur mit zusätzlicher Konvertierungsfunktion + Ausdruck.


0

Ich habe eine Klasse erstellt, um die verstrichene Zeit automatisch zu messen. Überprüfen Sie den Code (c ++ 11) in diesem Link: https://github.com/sonnt174/Common/blob/master/time_measure.h

Beispiel für die Verwendung der Klasse TimeMeasure:

void test_time_measure(std::vector<int> arr) {
  TimeMeasure<chrono::microseconds> time_mea;  // create time measure obj
  std::sort(begin(arr), end(arr));
}

Ich mag Ihre Druckaussage mit den Einheiten. Was würde es brauchen, um Ihren Code auf gcc und clang zu portieren? ( wandbox.org )
Howard Hinnant

1
@HowardHinnant: Danke für die Adressierung, ich habe den Code für gcc und clang ebenfalls aktualisiert.
Sirn Nguyen Truong

0

Matlab mit ...-Geschmack!

ticStartet einen Stoppuhr-Timer, um die Leistung zu messen. Die Funktion zeichnet die interne Zeit bei der Ausführung des Befehls tic auf. Zeigen Sie die verstrichene Zeit mit der tocFunktion an.

#include <iostream>
#include <ctime>
#include <thread>
using namespace std;

clock_t START_TIMER;

clock_t tic()
{
    return START_TIMER = clock();
}

void toc(clock_t start = START_TIMER)
{
    cout
        << "Elapsed time: "
        << (clock() - start) / (double)CLOCKS_PER_SEC << "s"
        << endl;
}

int main()
{
    tic();
    this_thread::sleep_for(2s);
    toc();

    return 0;
}

-4

Sie können die SFML-Bibliothek verwenden , bei der es sich um eine einfache und schnelle Multimedia-Bibliothek handelt. Es enthält viele nützliche und genau definierte Klassen wie Clock, Socket, Sound, Graphics usw. Es ist so einfach zu bedienen und sehr zu empfehlen.

Dies ist ein Beispiel für diese Frage.

sf::Clock clock;
...
Time time1 = clock.getElapsedTime();
...
Time time2 = clock.restart();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.