409 Stimmen

Einfaches Messen der verstrichenen Zeit

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

Was ich nicht verstehe, ist, warum die Werte vorher und nachher gleich sind? Mir ist klar, dass dies nicht der beste Weg ist, um ein Profil meines Programms zu erstellen, 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 es 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 msec?

Was ist mit **time taken = 4 45025 Bedeutet das 4 Sekunden und 25 msec?

10 Stimmen

Ich verstehe die Frage nicht. Natürlich sind die Werte unterschiedlich. Dazwischen ist Zeit vergangen, also time() gibt einen anderen Wert zurück.

1 Stimmen

Was meinen Sie 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 es aufrufen, wird N Sekunden nach dem ersten und damit ... anders sein (es sei denn, was auch immer es ist Sie tun, dauert nicht eine Sekunde zu beenden ... in diesem Fall, es wird das gleiche wie das erste sein).

1 Stimmen

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?

2voto

Kevin Kreiser Punkte 526

Ich musste die Ausführungszeit der einzelnen Funktionen innerhalb einer Bibliothek messen. Ich wollte nicht jeden Aufruf jeder Funktion mit einer Zeitmessfunktion umhüllen müssen, weil das hässlich ist und den Aufrufstapel vergrößert. Ich wollte auch nicht am Anfang und am Ende jeder Funktion einen Zeitmessungscode einfügen, weil das zu einem Chaos führt, wenn die Funktion zum Beispiel vorzeitig beendet wird oder Ausnahmen auslöst. Also habe ich einen Timer entwickelt, der seine eigene Lebensdauer verwendet, um die Zeit zu messen.

Auf diese Weise kann ich die Zeit messen, die ein Codeblock benötigte, indem ich einfach eines dieser Objekte zu Beginn des betreffenden Codeblocks (Funktion oder ein beliebiger Bereich) instanziiere und dann dem Destruktor der Instanz erlaube, die seit der Konstruktion verstrichene Zeit zu messen, wenn die Instanz den Bereich verlässt. Das vollständige Beispiel finden Sie unter aquí aber die Struktur ist sehr 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 über den bereitgestellten Funktor zurück, wenn sie den Bereich verlässt, so dass Sie etwas mit den Zeitinformationen tun können (drucken oder speichern oder was auch immer). Wenn Sie etwas noch Komplexeres machen wollen, können Sie sogar std::bind con std::placeholders zu Callback-Funktionen mit mehreren Argumenten.

Hier ist ein kurzes Beispiel für die Anwendung:

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 mehr Sorgfalt walten lassen wollen, können Sie auch new y delete um den Timer explizit zu starten und zu stoppen, ohne sich auf Scoping zu verlassen, um es für Sie zu tun.

2voto

Mike Weller Punkte 44986

Intern greift die Funktion auf die Systemuhr zu, weshalb sie bei jedem Aufruf andere Werte zurückgibt. Im Allgemeinen kann es bei nicht-funktionalen Sprachen viele Seiteneffekte und verborgene Zustände in Funktionen geben, die man nicht sehen kann, wenn man nur den Namen der Funktion und die Argumente betrachtet.

2voto

Safar Ligal Punkte 44

Soweit ich sehe, speichert tv_sec die verstrichenen Sekunden, während tv_usec die verstrichenen Mikrosekunden separat speichert. Und sie sind nicht die Konvertierungen von einander. Daher müssen sie in die richtige Einheit umgewandelt und addiert 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))
    );

1voto

oliora Punkte 794

Ich verwende in der Regel die folgenden Methoden:

#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 von @nikos-athanasiou vorgeschlagen, außer dass ich die Verwendung einer unstetigen Uhr vermeide und eine gleitende Anzahl von Sekunden als Dauer verwende.

2 Stimmen

Zu diesem Tipptastenschalter : Normalerweise high_resolution_clock ist ein Typedef für entweder system_clock o steady_clock . Um das nachzuvollziehen std::conditional wenn die is_steady Teil wahr ist, dann wählen Sie den high_resolution_clock die (ein Typedef zu) der steady_clock . Wenn sie falsch ist, wählen Sie die steady_clock wieder. Verwenden Sie einfach steady_clock von Anfang an ...

0 Stimmen

@nikos-athanasiou Ich stimme völlig mit dem Kommentar von 5gon12eder überein, dass der "typische" Fall von der Norm nicht gefordert wird, so dass einige STL auf eine andere Weise implementiert werden können. Ich ziehe es vor, dass mein Code generischer ist und sich nicht auf Implementierungsdetails bezieht.

0 Stimmen

Es ist nicht erforderlich, aber ausdrücklich festgelegt in 20.12.7.3 : high_resolution_clock may be a synonym for system_clock or steady_clock . Der Grund dafür ist folgender: high_resolution_clock repräsentiert die Uhren mit der kürzesten Tickperiode, so dass es unabhängig von der Implementierung zwei Möglichkeiten gibt: gleichmäßig zu ticken oder nicht. Unabhängig von der Wahl, die wir treffen, ist die Aussage, dass sich die Implementierung von den beiden anderen Uhren unterscheidet, so, als ob wir eine bessere Implementierung für eine stetige (oder nicht stetige) Uhr hätten, die wir nicht verwenden wollen (für stetige oder nicht stetige Uhren). Zu wissen wie ist gut, zu wissen warum ist besser

1voto

David Božjak Punkte 15745

Der Grund, warum beide Werte gleich sind, ist, dass Ihr lange Prozedur dauert nicht so lange - weniger als eine Sekunde. Sie können versuchen, einfach eine lange Schleife (for (int i = 0; i < 100000000; i++) ; ) am Ende der Funktion hinzuzufügen, um sicherzustellen, dass dies das Problem ist, und dann können wir von dort aus weitermachen...

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X