myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
   » Plugin für Firefox
   » Plugin für IE
   » Gadget für Windows
» Regeln
» Wie poste ich richtig?
» Datenschutzerklärung
» wbb-FAQ

Mitglieder
» Liste / Suche
» Stadt / Anleitung dazu
» Wer ist wo online?

Angebote
» ASP.NET Webspace
» Bücher
» Zeitschriften
   » dot.net magazin

Ressourcen
» guide to C#
» openbook: Visual C#
» openbook: OO
» MSDN Webcasts
» Search.Net

Team
» Kontakt
» Übersicht
» Wir über uns
» Impressum

» Unsere MiniCity
MiniCity
» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Basistechnologien und allgemeine .NET-Klassen » Genaue Zeitfunktion
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Genaue Zeitfunktion

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Rapthor
myCSharp.de-Mitglied

Dabei seit: 31.03.2005
Beiträge: 151


Rapthor ist offline Füge Rapthor Deiner Kontaktliste hinzu

Genaue Zeitfunktion

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

zur Frameratenberechnung setze ich zur Zeit noch "Environment.TickCount" ein, was mir aber aufgrund der Millisekunden noch zu ungenau ist.

Welche Funktionen gibt es noch, die mir eine genauere Zeitangabe als ms liefern?
11.01.2007 10:53 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Superbenny Superbenny ist männlich
myCSharp.de-Mitglied

Dabei seit: 06.09.2006
Beiträge: 27
Entwicklungsumgebung: Visual Studio 2005 Team Suite


Superbenny ist offline Füge Superbenny Deiner Kontaktliste hinzu

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Rapthor

Wenn du das FW2.0 verwendest, sollte die Klasse Stopwatch genauer sein.
11.01.2007 11:09 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Rapthor
myCSharp.de-Mitglied

Dabei seit: 31.03.2005
Beiträge: 151

Themenstarter Thema begonnen von Rapthor

Rapthor ist offline Füge Rapthor Deiner Kontaktliste hinzu

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Dankeschön, das hat mir geholfen!
11.01.2007 22:10 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Peter Bucher Peter Bucher ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-4103.jpg


Dabei seit: 17.03.2005
Beiträge: 5.879
Entwicklungsumgebung: VS 2017 / VS Code
Herkunft: Zentralschweiz


Peter Bucher ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Rapthor

Am genausten geht sowas IMO mit der API Funktion "QueryPerformanceCounter" und "QueryPerformanceFrequency".

Anbei meine Klasse, die ich selber in einer DirectX Applikation benutze.
Benutzung sollte selbsterklärend sein.

C#-Code:
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace SharpKrush.Misc
{
    /// <summary>
    /// Gibt den FPS Wert, der in einem gewissen Intervall aktualisiert wird, zurück.
    /// </summary>
    public class FrameCounter
    {
        [DllImport("kernel32.dll")]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

        [DllImport("kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(out long frequency);

        private System.Windows.Forms.Timer _timer;
        private float _fps;    // Fps Wert der im Intervall mit dem actFps befüllt wird
        private float _avgFps;
        private float _minFps;
        private float _maxFps;

        private float _sum;
        private float _sumCount;

        private float _actFps; // aktueller Fps Wert (Nach dem Render Timing)
        private long _lastFrame;
        private long _freq;
        private long _currentFrame;
        private int _interval;

        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="interval">Intervall der Aktualisierung vom FPS Wert, in Millisekunden</param>
        public FrameCounter(int interval) {
            this._sum = 0f;
            this._sumCount = 0f;

            // Min- und MaxFps Werte default setzen
            this._minFps = 999; // Das eigentlich jeder Wert kleiner ist~
            this._maxFps = 0;

            this._timer = new System.Windows.Forms.Timer();
            this._timer.Start();
            this._timer.Tick += new EventHandler(this.OnTick);
            this._timer.Interval = interval;
        }

        /// <summary>
        /// Gibt den Fps Wert zurück
        /// </summary>
        public float Fps {
            get { return this._fps; }
        }

        /// <summary>
        /// Gibt den durchschnittlichen Fps Wert zurück
        /// </summary>
        public float AvgFps {
            get { return this._avgFps; }
        }

        /// <summary>
        /// Gibt den kleinsten Fps Wert zurück
        /// </summary>
        public float MinFps {
            get { return this._minFps; }
        }

        /// <summary>
        /// Gibt den grössenn Fps Wert zurück
        /// </summary>
        public float MaxFps {
            get { return this._maxFps; }
        }

        /// <summary>
        /// Intervall der Aktualisierung vom FPS Wert, in Millisekunden
        /// </summary>
        public int Interval {
            set { this._interval = value; }
        }

        /// <summary>
        /// Beginnt mit der Zeitmessung
        /// </summary>
        public void Begin() {
            QueryPerformanceFrequency(out this._freq);
            QueryPerformanceCounter(out this._lastFrame);
        }

        /// <summary>
        /// Berechnet am Ende des Renderns den aktuellen Fps Wert
        /// </summary>
        public void End() {
            QueryPerformanceCounter(out this._currentFrame);
            this._actFps = this._freq / (this._currentFrame - this._lastFrame);

            // Auf kleinsten Wert prüfen
            if (this._actFps < this._minFps) {
                this._minFps = this._actFps;
            }

            // Auf grössten Wert prüfen
            if (this._actFps > this._maxFps) {
                this._maxFps = this._actFps;
            }
        }

        /// <summary>
        /// Berechnet den durchschnittlichen Fps Wert
        /// </summary>
        private void CalculateAvgFps() {
            if (this._sumCount <= 600) {
                this._sum += this._fps;
                this._sumCount++;

                this._avgFps = this._sum / this._sumCount;
            } else {
                this._sum = 0;
                this._avgFps = 60;
            }
        }

        /// <summary>
        /// Nach jedem Intervall wird der FPS Wert hier aktualisiert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTick(object sender, EventArgs e) {
            this._fps = this._actFps;
            this.CalculateAvgFps();
        }
    }
}

Gruss Peter
12.01.2007 01:06 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 2 Jahre.
gfoidl gfoidl ist männlich
myCSharp.de-Team

images/avatars/avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.506
Entwicklungsumgebung: VS 201[27]
Herkunft: Waidring


gfoidl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

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ü
18.10.2009 21:58 Beiträge des Benutzers | zu Buddylist hinzufügen
Peter Bucher Peter Bucher ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-4103.jpg


Dabei seit: 17.03.2005
Beiträge: 5.879
Entwicklungsumgebung: VS 2017 / VS Code
Herkunft: Zentralschweiz


Peter Bucher ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo gfoidl

Danke für die Info, das wusste ich noch nicht.


Gruss Peter
26.10.2009 11:05 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 9 Monate.
Beauty
myCSharp.de-Mitglied

images/avatars/avatar-2333.jpg


Dabei seit: 31.05.2007
Beiträge: 79
Entwicklungsumgebung: Visual C# 2008
Herkunft: Thüringen


Beauty ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

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.
12.08.2010 21:21 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Beauty
myCSharp.de-Mitglied

images/avatars/avatar-2333.jpg


Dabei seit: 31.05.2007
Beiträge: 79
Entwicklungsumgebung: Visual C# 2008
Herkunft: Thüringen


Beauty ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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.
12.08.2010 21:58 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
gfoidl gfoidl ist männlich
myCSharp.de-Team

images/avatars/avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.506
Entwicklungsumgebung: VS 201[27]
Herkunft: Waidring


gfoidl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Beauty,

siehe ein paar Antworten weiter oben ;-)


mfG Gü
12.08.2010 22:41 Beiträge des Benutzers | zu Buddylist hinzufügen
Beauty
myCSharp.de-Mitglied

images/avatars/avatar-2333.jpg


Dabei seit: 31.05.2007
Beiträge: 79
Entwicklungsumgebung: Visual C# 2008
Herkunft: Thüringen


Beauty ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ah, Du meinst das:

Zitat:
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 Zunge raus
12.08.2010 23:24 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
gfoidl gfoidl ist männlich
myCSharp.de-Team

images/avatars/avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.506
Entwicklungsumgebung: VS 201[27]
Herkunft: Waidring


gfoidl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

Zitat:
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ü
12.08.2010 23:35 Beiträge des Benutzers | zu Buddylist hinzufügen
Beauty
myCSharp.de-Mitglied

images/avatars/avatar-2333.jpg


Dabei seit: 31.05.2007
Beiträge: 79
Entwicklungsumgebung: Visual C# 2008
Herkunft: Thüringen


Beauty ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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.
13.08.2010 02:30 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
VizOne VizOne ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-1563.gif


Dabei seit: 26.05.2004
Beiträge: 1.373
Entwicklungsumgebung: VS 2010


VizOne ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ob die CPU-Frequenz sich ändert, sollte für QueryPerformanceFrequency irrelevant sein, denn:

Zitat:
The frequency cannot change while the system is running.

Quelle:  QueryPerformanceFrequency Function

Das Problem sind nicht die variablen CPU-Frequenzen sondern wie schon erwähnt v.a. die Anwesenheit mehrerer Kerne.

Hier noch einige Tipps zum Thema Timing:  Game Timing and Multicore Processors

Grüße,
Andre
13.08.2010 08:25 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Beauty
myCSharp.de-Mitglied

images/avatars/avatar-2333.jpg


Dabei seit: 31.05.2007
Beiträge: 79
Entwicklungsumgebung: Visual C# 2008
Herkunft: Thüringen


Beauty ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Sehr nützlicher Artikel - darüber habe ich auch weitere relevante Seiten gefunden.

Danke (-:
13.08.2010 20:56 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
xxMUROxx xxMUROxx ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-3236.jpg


Dabei seit: 11.01.2010
Beiträge: 1.552
Entwicklungsumgebung: VS 13, SSMS 12
Herkunft: Südtirol/Italien


xxMUROxx ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo leute,

Zitat von Beauty:
Oh, jetzt habe ich doch noch etwas interessantes gefunden:

Zitat von herbivore:
(Jeder Tick stellt laut Doku ein Intervall von 100 Nanosekunden dar)

Das stimmt so nicht. Die 100ns beziehen sich auf die Ticks Property der DateTime Klasse, denn dort ist 1 Tick = 100ns.

Wenn du mit Ticks arbeiten willst kannst du folgendes schreiben:

C#-Code:
Stopwatch sw = [...]
[...]
long ellapsedNanoSeconds = sw.EllapsedTicks / Stopwatch.Frequency;

Gruß Michael
13.08.2010 21:17 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.444
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo xxMUROxx,

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

herbivore
14.08.2010 09:31 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 11 Jahre.
Der letzte Beitrag ist älter als 8 Jahre.
Antwort erstellen


© Copyright 2003-2018 myCSharp.de-Team. Alle Rechte vorbehalten. 14.12.2018 22:18