obwohl ich weiß dass dieses Thema alt ist muss ich eine Ergänzung machen. Dies auch deshalb weil Peter Bucher in seinem aktuellsten Blog-Eintrag sich darauf bezieht.
die Stopwatch verwendet intern den QueryPerformanceCounter und somit dürfte keine Unterschied zwischen den beiden bestehen.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
in einer Diskussion im Ogre-Forum (3D Grafikbibliothek) geht es auch gerade um FPS-Messungen (Bilder pro Sekunde) und FPS-Begrenzung (nicht schneller als xxx FPS rendern).
Als ich auf den QueryPerformanceCounter hinwies, bekam ich eine Antwort, daß das (heutzutage) Probleme verursachen kann:
Zitat
Using the QueryPerformanceCounter functions can cause problems on multi-core CPUs, at least there were some serious problems in the past. I don't know if the .NET Stopwatch class is aware of the problem and contains a fix.
On most machines you should be fine using any of these methods. If you have strange effects, just remember that you might have to take care of these bugs.
A little more detail:
On multi-core CPUs the performance counter on different cores can have different values. If the scheduler changes your program flow to another core, you might get strange readings like large differences between calls. If you create a time delta every frame (currentTimeStamp - lastTimeStamp) and you get negative values, you just encountered this problem.
The easiest way is to use a background thread with an affinity mask that binds it to only one core. So the functions will always use the same performance counter and the problem is solved. You'll have to do this in C or C++ code, because .NET has its own internal scheduler that is independent of the system scheduler and you can't change the affinity mask in a reliable way.
More information about QueryPerformanceCounter problems can be found here and here.
Auch wenn die Zeitmessung ausschließlich auf einem CPU-Kern stattfindet, kann ich mir Probleme vorstellen, da sich bei modernen CPUs die Taktfrequenz dynamisch ändern kann. (Es sei denn, man liest ständig QueryPerformanceFrequency aus und beachtet Änderungen in den Zeitberechnungen. Trotzdem wären dann Zeitvergleiche komplizierter zu berechnen.)
Frage:
Gibt es vielleicht eine Bibliothek für präzise Zeitmessungen, die man bei .NET-Programmen einbinden kann und die oben genannten Probleme berücksichtigen? Ich hatte selber schon gesucht, aber nichts passendes gefunden.
Oh, jetzt habe ich doch noch etwas interessantes gefunden:
Zitat von herbivore
Hallo Xqgene
wenn ich mit Stopwatch 10 mal in einer Schleife die Zeit für eine leere Anweisung messe, bekommt ich auf meinem Rechner exemplarisch folgende Ausgabe in Ticks (Jeder Tick stellt laut Doku ein Intervall von 100 Nanosekunden dar):
6
5
5
4
5
5
5
5
4
5
Also Schwankungen im Bereich von 200 Nanosekunden. Ich glaube das disqualifiziert auch die ansich nützliche Stopwatch für Messungen im Bereich von 0.1 - 5 nanosec. :-)
herbivore
Mit der Stopwatch-Klasse kann man also Zeitintervalle fast mit Tick-Genauigkeit messen.
Ich hoffe, da gibt es nicht so die Probleme wie beim QueryPerformanceCounter.
die Stopwatch verwendet intern den QueryPerformanceCounter und somit dürfte keine Unterschied zwischen den beiden bestehen.
Theoretisch könnte es sein, daß die Stopwatch-Klasse schwankende CPU-Taktungen berücksichtigt. Vielleicht finde ich dazu was in der Doku.
Dennoch bleibt noch die Frage offen, ob es möglicherweise eine alternative (externe) Bibliothek für sowas gibt. Daher ist hochscrollen keine ultimative Lösung
Theoretisch könnte es sein, daß die Stopwatch-Klasse schwankende CPU-Taktungen berücksichtigt
Könnte sein, ist aber nicht umgestetzt. Die Stopwatch ist nur ein "Wrapper" für QueryPerformanceCounter.
Zitat
ob es möglicherweise eine alternative (externe) Bibliothek für sowas gibt.
Ich kenn keine - hab aber auch nicht danach gesucht ;-)
Fürs Messen muss halt mit statistischen Mitteln gearbeitet werden - absolute Messungen sind auf einem Betriebssystem wie Windows sowieso nicht möglich (Multitasking, ...).
Für das von dir oben (hochscrollen ^^) angesprochene FPS-Begrenzung ist das allerdings auch keine befriedigende Lösung...(das soll ja zur Laufzeit direkt passieren oder?)
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Mir geht es nicht um einzelne Mikrosekunden (oder gar Nanosekunden wie in einem anderen Thread), sondern nur darum, etwas genauer zu sein als wie die Rückgabe von DateTime.Now.Ticks.
Früher dachte ich blauäugig, die Zeitabfrage wäre wirklich so genau (etwa 100ns), aber später bemerkte ich eigenartige Effekte bei einem Programm. Ursache war, daß der Zeitwert von DateTime.Now.Ticks lange nicht so oft aktualisiert wird, wie der Name es vermuten läßt. Ich weiß die Aktualisierungsabstände nicht mehr. Vielleicht wurde etwa jede Millisekunde der Wert aktualisiert.
Der QueryPerformanceCounter ist eigentlich eine tolle Sache, aber die oben genannten (möglichen) Probleme machen mich etwas skeptisch.
da Stopwatch.Frequency die Frequenz des Zeitgebers als Anzahl der Ticks pro Sekunde angibt, bekommt man mit sw.EllapsedTicks / Stopwatch.Frequency die Anzahl der vergangenen Sekunden heraus. Wenn man die Anzahl der vergangenen Nanosekunden haben will, muss mal also noch mit 1000000000 (109) multiplizieren.
BTW: Da EllapsedTicks und Frequency longs sind, wird hier standardmäßig Integer-Arithmetik verwendet. Man muss also aufpassen, dass man weder einen Überlauf bekommt (der bei sw.EllapsedTicks * 1000000000 / Stopwatch.Frequency denkbar wäre) noch durch abgeschnittene Nachkommastellen im Zwischenergebnis das Ergebnis unbrauchbar ungenau macht (wie das bei sw.EllapsedTicks / Stopwatch.Frequency * 1000000000) der Fall wäre).