Wo sind meine Ticks geblieben?
-
Hi!
Ich habe ein Problem: Ich berechne via GetTickCount() die Zeit zwischen zwei Aufrufen der Timerfunktionen meiner Klassen (dazwischen liegt die grafische Ausgabe etc.)
Direkt ausgegeben ergibt sich ein ziemlich konstanter Wert von 50 Ticks, allerdings kommen in den (bzw. der wo ich mitlogge) meistens 0, manchmal 10 und extrem selten (ganz am Anfang) so ca. 30 an.
Woran kann das liegen?[code] //Ausschnitt der main()-Schleife tickcount = GetTickCount(); game::get_singleton()->regions.getdata(0)->timerCall( GetTickCount() - engine::get_singleton()->getTime()); PostMessage(engine::main_window,WM_PAINT,0,0); engine::get_singleton()->resetTimer(); [/code]
Bei der Verarbeitung von WM_PAINT gebe ich gleichzeitig GetTickCount() - tickcount auf dem Bildschirm aus -> konstant 50 - 60 Ticks
[code] //hier wirds weitergereicht void region::timerCall(DWORD ticks) { int i = 0; freedynamics(); prep_dynamics(); game_object* object; while(object = dynamiclayer.getdataonposition(i)) { object->timer(ticks); i++; } } //Und kommt dann hier an (abgeleitete Klasse) //Der Log beweist: meistens ticks == 0, manchmal 10 void Charakter::timer(DWORD ticks) { engine::get_singleton()->logevent("%d : %d",GetTickCount(),ticks); } [/code]
-
GetTickCount ist viel zu ungenau für das Stoppen der Zeit.
Eine gute und extrem genaue Möglichkeit ist der High-Performance-Counter: Schau dir QueryPerformanceCounter und QueryPerformanceFrequency aus der Windows API an.
Programmierst du ein Spiel? Wenn du willst kann ich dir meine Timer-Klasse geben. Die kapselt den Umgang mit dem High-Performance-Counter und hat zum Beispiel eine Funktion GetFrameTime.
-
oder du nimmst sowas: http://www.wolfgang-rolke.de/dev_tips/dev_03.htm
musste etwas umbauen für deine belange.
btw: der time stamp counter ist ein echter hardware counter und lässt sich nicht beeindrucken von irgendwelchem quatsch, den windows sonst so veranstaltet.
-
Zeiten unter ca 50ms sind gettickcout eher nicht messbar.
der genannte highperformance counter is gut und sehr einfach zu benutzten
-
Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum WinAPI verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Ich habs jetzt mal mit einem HighPerformanceCounter - Timer aus dem Forum probiert, das Problem blieb aber. Ich hab dann zum Testen mal ein Sleep() for den kritischen Aufruf gesetzt und festgestellt, das mir tatsächlich ein absoluter Wert von ca. 50 ms (getestet bei verschiedener Sleep-Dauer) abhanden kommt. Ich werds nochmal mit der Hardwarenahen Variante probieren und werde das Zurücksetzen des Timers vor den Timeraufruf setzen (natürlich werd ich die Zeit vorher speichern
) -> Vielleicht dauert das ja 50 ms. IMHO dürfte das zwar nicht sein, weil dann ein Timeraufruf in einem Objekt so ewig dauert (das wäre irgendwie schlecht... ^^ Vor allem, weil das Objekt noch nicht sehr komplex ist ^^' ^^)
-
Dir hat schjon jemand gesagt, das Windows kein Echtzeitbetriebssystem ist und Dir somit niemand die Zeit garantieren kann?
-
Hmmm. Okay das heißt für 1s Echtzeit bekomme ich keine 1000 ms im Rechner? Soll ich mich also lieber auf eine Framerate festlegen bzw Ticks pro Frame? Dagegen hab ich nichts, nur wird dann folgendes passieren: Ich übergebe immer eine konstante Anzahl Ticks. Ist der Rechner nun schneller als mein "Testrechner", läuft das Spiel auch entsprechend schneller ab (u.U. nicht so vorteilhaft). Wenn der Rechner langsamer ist, läuft auch das Spiel langsamer, obwohl eigentlich genügend Rechenleistung da wäre seitens des Rechners. Der Hintergrund der ganzen Tickübergabe war doch eigentlich, eine vom Rechner unabhängige, konstante Spielgeschwindigkeit zu erreichen (wäre bei langsamen Rechner auf Kosten der Genauigkeit gegangen, bei schnelleren Rechnern wie man sieht, geht mir meine Zeit komplett verloren)
Kann ich das irgendwie umgehen? Soll ich anhand des Prozessortakts oder wasauchimmer eine Sleep()-Dauer berechnen, damit ich eine (einigermaßen)konstante Zeit zur Verfügung habe?
-
Hallifax schrieb:
Hmmm. Okay das heißt für 1s Echtzeit bekomme ich keine 1000 ms im Rechner?
Nein. Das soll heissen, dass wenn Du 1 sec warten willst, Du manchmal auf 10 sec warten musst.
Hallifax schrieb:
Soll ich mich also lieber auf eine Framerate festlegen bzw Ticks pro Frame? Dagegen hab ich nichts, nur wird dann folgendes passieren: Ich übergebe immer eine konstante Anzahl Ticks. Ist der Rechner nun schneller als mein "Testrechner", läuft das Spiel auch entsprechend schneller ab (u.U. nicht so vorteilhaft). Wenn der Rechner langsamer ist, läuft auch das Spiel langsamer, obwohl eigentlich genügend Rechenleistung da wäre seitens des Rechners. Der Hintergrund der ganzen Tickübergabe war doch eigentlich, eine vom Rechner unabhängige, konstante Spielgeschwindigkeit zu erreichen (wäre bei langsamen Rechner auf Kosten der Genauigkeit gegangen, bei schnelleren Rechnern wie man sieht, geht mir meine Zeit komplett verloren)
Wie schon gesagt wurde. Du solltest die Zeit mit "QueryPerformanceCounter" messen. Und abhängig von der gemessenen Zeit, dann die Bewegung, welcher dieser Zeit entspricht, durchführen. Somit erreichst Du eine Rechnerunabhängige Darstellung, die bestimmte Zeitintervalle voraussetzen...
Hallifax schrieb:
Kann ich das irgendwie umgehen? Soll ich anhand des Prozessortakts oder wasauchimmer eine Sleep()-Dauer berechnen, damit ich eine (einigermaßen)konstante Zeit zur Verfügung habe?
Nein. Es macht keinen Sinn, da ein "Sleep(1)" manchmal 10 und manchmal 1000 ms dauern kann.
Messe die Zeit und zeige die Bewegung abhängig der Different Deiner letzten Darstellung an.
-
Kauf dir ein Buch über Spieleprogrammierung. Da steht drin wie man es richtig macht.
-
Jochen Kalmbach schrieb:
Wie schon gesagt wurde. Du solltest die Zeit mit "QueryPerformanceCounter" messen. Und abhängig von der gemessenen Zeit, dann die Bewegung, welcher dieser Zeit entspricht, durchführen. Somit erreichst Du eine Rechnerunabhängige Darstellung, die bestimmte Zeitintervalle voraussetzen...
Messe die Zeit und zeige die Bewegung abhängig der Different Deiner letzten Darstellung an.
Hab ich das nicht schon die ganze Zeit gemacht? Mein Problem ist doch gerade, dass es so, wie du es gerade sagst, nicht funktioniert!
spieleprogrammmierer schrieb:
Kauf dir ein Buch über Spieleprogrammierung. Da steht drin wie man es richtig macht.
Das Buch über Spieleprogrammierung, was ich habe, macht das mit WM_TIMER. Soll ich das auch so machen? Wenn ichs mir recht überlege, könnte das sogar die beste (oder einfachste) Lösung sein, nur war ich der Meinung, mit einem genaueren Timer ein besseres Ergebnis erreichen zu können.
-
Vielleicht hab ich ja Dein Problem nicht so ganz verstanden... Wenn Du als Unterschied "0" rausgekommst, dann machst Du halt einfach nichts... oder was ist Dein Problem (der Thread enthält soviel Text
)
-
Hmmm also vielleicht... weil "0" _etwas_ wenig und auch irgendwie unrealistisch ist?
-
Wenn die Auflösung von GetTickCount zwischen 10 und 20 ms liegt, dann ist 0 sehr wohl realistisch....
-
Okay, aber wieso passiert bei HighPerformanceCounter das gleiche?
Und @ Auflösung: Wenn ich keinen Denkfehler gemacht habe, müsste die Auflösung, um den Fehler hervorzurufen, mindestens 30 ticks betragen. (60 - 0 !)
-
SCM?
-
Jochen Kalmbach schrieb:
Du solltest die Zeit mit "QueryPerformanceCounter" messen.
Vorsicht damit! QueryPerformanceCounter greift auf den Prozessorinternen Time Stamp Counter zu, der eigentlich nur dazu gedacht war, die Anzahl Clocks zwischen zwei Zeitpunkten zu messen. Dies ist aber mit einigen Problemen bei neueren Prozessorarchitekturen (Powermanagement, variabler Taktfrequenz, ...) verbunden...
Siehe dazu: http://www.heise.de/newsticker/meldung/65802
Hatte damals auch eine Diskussion im Heise-Forum angefangen, weil ich selber verunsichert war.. und siehe da es gab sogar mal kompetente Antworten.
Als Alternative wurden mir damals TimerQueues ([msdn]CreateTimerQueue[/msdn], etc) vorgeschlagen. Allerdings haben die Funktionen natürlich auch einen Pferdefuss der sich durch Studium der MSDN erst verdeutlicht:
Requirements
Client Requires Windows Vista, Windows XP, or Windows 2000 Professional.
Server Requires Windows Server "Longhorn", Windows Server 2003, or Windows 2000 Server.Bei POSIX gäbs zum Beispiel die Funktion microtime und das seit Jahren... (o;
Auf codeproject.com findet sich im Übrigen auch ein netter Artikel über Timer unter Windows.Mein Vorschlag für die Zeitmessung in Zukunft ist einen eigenen Zeit-Zähler mitlaufen zu lassen, um Zeitschritte zu messen. Die Inkrementierung des Zählers würde ich wohl in zukünftigen Projekten über Queue Timer erledigen.
-
Es sei zumindest angemerkt, dass der TSC nicht immer verwendet wird (ist abhängig von der geladenen HAL). Auch kann man die Verwendung des TSC mit /usepmtimer bei den Boot-Parametern unterbinden.
-
Ich denke jedoch man wird wohl, um stabile und funktionierende Software zu entwickeln, annehmen müssen, dass die TSC - mit allen Konsequenzen verwendet wird. Nich umsonst hat z.B. Windows XP mit SP2 dank der DualCore-Offensive u.a. genau damit Sorgen...
-
Ich denke jedoch man wird wohl, um stabile und funktionierende Software zu entwickeln, annehmen müssen dass QueryPerformanceCounter/Frequency funktioniert.