Ich habe ein C-Programm, das auf mehreren Prozessoren parallel ausgeführt werden soll. Ich muss in der Lage sein, die Ausführungszeit aufzuzeichnen (die zwischen 1 Sekunde und mehreren Minuten liegen kann). Ich habe nach Antworten gesucht, aber alle scheinen die Verwendung der clock()
Funktion vorzuschlagen , bei der dann die Anzahl der Uhren berechnet wird, die das Programm geteilt hat, geteilt durch dieClocks_per_second
Wert berechnet wird.
Ich bin mir nicht sicher wie Clocks_per_second
Wert berechnet wird?
In Java nehme ich nur die aktuelle Zeit in Millisekunden vor und nach der Ausführung.
Gibt es eine ähnliche Sache in C? Ich habe es mir angesehen, aber ich kann anscheinend keinen Weg finden, etwas Besseres als eine zweite Auflösung zu erreichen.
Ich bin mir auch bewusst, dass ein Profiler eine Option wäre, möchte aber selbst einen Timer implementieren.
Vielen Dank
quelle
Antworten:
CLOCKS_PER_SEC
ist eine Konstante, die in deklariert ist<time.h>
. Verwenden Sie Folgendes, um die von einer Aufgabe in einer C-Anwendung verwendete CPU-Zeit abzurufen:Beachten Sie, dass dies die Zeit als Gleitkommatyp zurückgibt. Dies kann genauer als eine Sekunde sein (z. B. messen Sie 4,52 Sekunden). Die Präzision hängt von der Architektur ab. Auf modernen Systemen erreichen Sie leicht 10 ms oder weniger, auf älteren Windows-Computern (aus der Win98-Ära) waren es jedoch eher 60 ms.
clock()
ist Standard C; es funktioniert "überall". Es gibt systemspezifische Funktionen wiegetrusage()
auf Unix-ähnlichen Systemen.Java
System.currentTimeMillis()
misst nicht dasselbe. Es ist eine "Wanduhr": Sie kann Ihnen helfen, zu messen, wie viel Zeit das Programm für die Ausführung benötigt hat, aber es sagt Ihnen nicht, wie viel CPU-Zeit verwendet wurde. Auf einem Multitasking-System (dh allen) können diese sehr unterschiedlich sein.quelle
clock()
Gibt eine Zeit in einer internen Skala zurück, die als "Uhren" bezeichnet wird, undCLOCKS_PER_SEC
gibt die Anzahl der Uhren pro Sekunde an. Wenn Sie also durch dividieren, erhalten SieCLOCKS_PER_SEC
eine Zeit in Sekunden. Im obigen Code ist der Wert a,double
sodass Sie ihn nach Belieben skalieren können.CLOCKS_PER_SEC
ist einlong int
mit dem Wert1000000
, der Zeit in Mikrosekunden angibt, wenn er nicht geteilt wird; keine CPU-Taktzyklen. Daher muss die dynamische Frequenz nicht berücksichtigt werden, da der Takt hier in Mikrosekunden angegeben ist (möglicherweise Taktzyklen für eine 1-MHz-CPU?). Ich habe ein kurzes C-Programm erstellt, das diesen Wert druckt, und es war 1000000 auf meinem i7-2640M-Laptop. mit einer dynamischen Frequenz von 800 MHz bis 2,8 GHz, sogar mit Turbo Boost bis zu 3,5 GHz.Wenn Sie die Unix-Shell zum Ausführen verwenden, können Sie den Befehl time verwenden.
tun
Wenn Sie a.out als ausführbare Datei annehmen, erhalten Sie die Zeit, die zum Ausführen benötigt wird
quelle
perf stat ./a.out
Sie HW-Leistungsindikatoren für Cache-Fehler abrufen und Branch Mispredicts und IPC.In einfacher Vanille C:
quelle
Sie möchten dies funktional:
Beachten Sie, dass dies in Mikrosekunden und nicht nur in Sekunden gemessen wird.
quelle
gettimeofday
ist veraltet und wird für neuen Code nicht empfohlen. Die POSIX-Manpage empfiehlt clock_gettime stattdessen , mit der Sie fragen können,CLOCK_MONOTONIC
ob dies nicht durch Änderungen an der Systemuhr beeinflusst wird. ist es besser als Intervallzeit. (Siehe JohnSlls Antwort ). Auf modernen Linux-Systemen ist gettimeofday beispielsweise im Grunde ein Wrapper für clock_gettime, der Nanosekunden in Mikrosekunden konvertiert.Die meisten einfachen Programme haben eine Rechenzeit in Millisekunden. Ich nehme an, Sie werden dies nützlich finden.
Wenn Sie die Laufzeit des gesamten Programms berechnen möchten und sich auf einem Unix-System befinden, führen Sie Ihr Programm mit dem folgenden Befehl time aus
time ./a.out
quelle
Viele Antworten wurden vorgeschlagen
clock()
und dannCLOCKS_PER_SEC
vontime.h
. Dies ist wahrscheinlich eine schlechte Idee, da dies in meiner/bits/time.h
Datei steht:CLOCKS_PER_SEC
Je nachdem, welche Optionen Sie zum Kompilieren verwenden, kann dies als 1000000 definiert werden. Daher scheint dies keine gute Lösung zu sein.quelle
CLOCK_PER_SEC==1000000
, aber gleichzeitig verwenden sie alle eine Genauigkeit von 1 µs für ihre clock () -Implementierung. Übrigens hat es die nette Eigenschaft, Probleme beim Teilen zu reduzieren. Wenn Sie potenziell sehr schnelle Ereignisse messen möchten, z. B. unter 1 ms, sollten Sie sich zuerst um die Genauigkeit (oder Auflösung) der clock () -Funktion kümmern, die in Posix notwendigerweise gröber als 1 µs ist, aber häufig auch viel gröber. Die übliche Lösung besteht darin, den Test viele Male auszuführen. Die gestellte Frage schien dies jedoch nicht zu erfordern.clock()
, wenn Sie diesen Wert mit Ihnen teilen, erhaltenCLOCK_PER_SEC
Sie garantiert Zeit in Sekunden CPU benötigt. Die Verantwortung für die Messung der tatsächlichen Taktrate liegt bei derclock()
Funktion, nicht bei Ihnen.Thomas Pornins Antwort als Makros:
Verwenden Sie es so:
Ausgabe:
quelle
Sie müssen die Zeitmessung berücksichtigen , die ein Programm nahm auszuführen viel von der Last abhängt , dass die Maschine in diesem bestimmten Moment hat.
In dem Wissen, dass der Weg, die aktuelle Zeit in C zu erhalten, auf verschiedene Arten erreicht werden kann, ist ein einfacher:
Ich hoffe es hilft.
Grüße!
quelle
(Alle Antworten hier fehlen, wenn Ihr Systemadministrator die Systemzeit ändert oder Ihre Zeitzone unterschiedliche Winter- und Sommerzeiten hat. Daher ...)
Bei Verwendung unter Linux:
clock_gettime(CLOCK_MONOTONIC_RAW, &time_variable);
Es ist nicht betroffen, wenn der Systemadministrator die Zeit ändert oder Sie in einem Land leben, in dem die Winterzeit anders ist als die Sommerzeit usw.man clock_gettime
Zustände:quelle
(end.tv_nsec - begin.tv_nsec) / 1000000000.0
Ergebnis in0
immer?double
Literal löst int oderlong
einedouble
Konvertierung vor der Teilung aus. Natürlich können Sie sich einfach an eine Ganzzahl halten und dastv_sec
Teil und dann den Bruchteil mit Null drucken%ld.%09ld
, aber die Konvertierung in Double ist einfach und 53 Bit Genauigkeit reichen normalerweise für Benchmark-Zeiten aus.timespec_subtract
wie dietimeval_subtract
in dem glibc Handbuch vorgeschlagen : gnu.org/software/libc/manual/html_node/Elapsed-Time.html )ANSI C gibt nur Zeitfunktionen mit zweiter Genauigkeit an. Wenn Sie jedoch in einer POSIX-Umgebung ausgeführt werden, können Sie die Funktion gettimeofday () verwenden, die eine Auflösung von Mikrosekunden für die seit der UNIX-Epoche verstrichene Zeit bietet.
Als Randnotiz würde ich die Verwendung von clock () nicht empfehlen, da es auf vielen (wenn nicht allen?) Systemen schlecht implementiert und nicht genau ist, abgesehen von der Tatsache, dass es sich nur darauf bezieht, wie lange Ihr Programm auf der CPU und verbracht hat nicht die Gesamtlebensdauer des Programms, die Sie Ihrer Frage zufolge gerne messen würden.
quelle
In meinem System funktionieren nicht alle Lösungen.
Ich kann es gebrauchen
quelle
time_t
Werten als Doppel. Da dietime_t
Werte nur auf eine Sekunde genau sind, ist sie für den Ausdruck der Zeit, die von Programmen mit kurzer Laufzeit benötigt wird, von begrenztem Wert. Dies kann jedoch für Programme nützlich sein, die über einen längeren Zeitraum ausgeführt werden.clock_t
s andifftime
zu übergeben. Dies ist unter Linux x86. Ich kann auch nicht die Subtraktion vonstop
undstart
zur Arbeit bekommen.difftime()
clock() / CLOCKS_PER_SEC
, da es Sekunden erwartet.quelle
Ich habe festgestellt, dass die übliche Uhr (), die jeder hier empfiehlt, aus irgendeinem Grund stark von Lauf zu Lauf abweicht, selbst für statischen Code ohne Nebenwirkungen, wie Zeichnen auf dem Bildschirm oder Lesen von Dateien. Dies kann daran liegen, dass die CPU den Stromverbrauch ändert, das Betriebssystem unterschiedliche Prioritäten setzt usw.
Die einzige Möglichkeit, mit clock () jedes Mal zuverlässig das gleiche Ergebnis zu erzielen, besteht darin, den gemessenen Code mehrmals (mehrere Minuten lang) in einer Schleife auszuführen und dabei Vorsichtsmaßnahmen zu treffen, um zu verhindern, dass der Compiler ihn optimiert: Moderne Compiler können den Code vorberechnen ohne Nebenwirkungen, die in einer Schleife ausgeführt werden, und verschieben Sie sie aus der Schleife heraus, z. B. indem Sie für jede Iteration eine zufällige Eingabe verwenden.
Nachdem genügend Samples in einem Array gesammelt wurden, sortiert man dieses Array und nimmt das mittlere Element, den Median. Der Median ist besser als der Durchschnitt, da er extreme Abweichungen beseitigt, z. B. wenn Antivirenprogramme die gesamte CPU belegen oder das Betriebssystem Aktualisierungen vornimmt.
Hier ist ein einfaches Dienstprogramm zum Messen der Ausführungsleistung von C / C ++ - Code, bei dem die Werte nahe dem Median gemittelt werden: https://github.com/saniv/gauge
Ich selbst bin immer noch auf der Suche nach einer robusteren und schnelleren Methode zum Messen von Code. Man könnte wahrscheinlich versuchen, den Code unter kontrollierten Bedingungen auf Bare-Metal ohne Betriebssystem auszuführen, aber das führt zu einem unrealistischen Ergebnis, da in Wirklichkeit das Betriebssystem involviert ist.
x86 verfügt über diese Hardwareleistungsindikatoren, die die tatsächliche Anzahl der ausgeführten Anweisungen enthalten. Sie sind jedoch ohne Hilfe des Betriebssystems schwierig zuzugreifen, schwer zu interpretieren und haben ihre eigenen Probleme ( http://archive.gamedev.net/archive/reference/articles) /article213.html ). Dennoch könnten sie hilfreich sein, um die Art des Flaschenhalses zu untersuchen (Datenzugriff oder tatsächliche Berechnungen dieser Daten).
quelle
performance
) oder viele zehn Millisekunden dauern . en.wikipedia.org/wiki/Dynamic_frequency_scaling . Und ja, die mittlere Leistung ist normalerweise eine gute Wahl. Das High-End weist normalerweise einige Störspitzen auf.main
, die ein Argument annimmt und ein Ergebnis zurückgibt, und verwenden Sie keine Optimierung der Verbindungszeit. Dann kann der Compiler es nicht in den Aufrufer einbinden. Funktioniert nur, wenn die Funktion bereits eine Art Schleife enthält, andernfalls ist der Overhead für Aufruf / Ret zu hoch.Man könnte eine andere Art von Eingabe nützlich finden: Ich habe diese Methode gegebener Zeit im Rahmen eines Hochschulstudium auf GPGPU-Programmierung mit CUDA (Messkursbeschreibung ). Es kombiniert Methoden, die in früheren Beiträgen verwendet wurden, und ich poste sie einfach, weil die Anforderungen ihr Glaubwürdigkeit verleihen:
Ich nehme an, Sie könnten mit zB multiplizieren
1.0 / 1000.0
, um die Maßeinheit zu erhalten, die Ihren Anforderungen entspricht.quelle
clock_gettime
stattdessen, dass Sie fragen können,CLOCK_MONOTONIC
ob dies nicht durch Änderungen an der Systemuhr beeinflusst wird, und daher besser als Intervall-Timer geeignet ist. Auf modernen Linux-Systemen ist beispielsweisegettimeofday
ein Wrapperclock_gettime
, der Nanosekunden in Mikrosekunden umwandelt. (Siehe JohnSlls Antwort).timeval_subtract
.Vergleich der Ausführungszeit von Blasensortierung und Auswahlsortierung Ich habe ein Programm, das die Ausführungszeit von Blasensortierung und Auswahlsortierung vergleicht. Um den Zeitpunkt der Ausführung eines Codeblocks herauszufinden, berechnen Sie die Zeit vor und nach dem Block durch
Beispielcode:
quelle